From 237b70621ae0164ce8dbd6495b9207e858e71d08 Mon Sep 17 00:00:00 2001 From: reiern70 Date: Wed, 30 Dec 2015 11:41:14 +0100 Subject: [PATCH] Added a bootstrap based slider --- .../slider/AjaxBootstrapSlider.java | 67 + .../slider/AjaxNumericBootstrapSlider.java | 25 + .../extensions/slider/BootstrapSlider.java | 330 ++++ .../extensions/slider/ISliderValue.java | 16 + .../slider/NumericBootstrapSlider.java | 25 + .../BootstrapSliderCssResourceReference.java | 19 + .../res/BootstrapSliderResourceReference.java | 19 + .../extensions/slider/res/bootstrap-slider.js | 1548 +++++++++++++++++ .../slider/res/bootstrap-slider.min.js | 29 + .../slider/res/css/bootstrap-slider.css | 255 +++ .../slider/res/css/bootstrap-slider.min.css | 28 + .../slider/util/DoubleRangeValue.java | 55 + .../extensions/slider/util/DoubleValue.java | 41 + .../extensions/slider/util/INumericValue.java | 13 + .../slider/util/IntegerRangeValue.java | 73 + .../extensions/slider/util/IntegerValue.java | 58 + .../slider/util/LongRangeValue.java | 73 + .../extensions/slider/util/LongValue.java | 58 + .../extensions/slider/util/NumericModel.java | 46 + .../wicket/samples/pages/BasePage.java | 1 + .../wicket/samples/pages/ExtensionsPage.java | 7 +- .../wicket/samples/pages/SliderPage.html | 151 ++ .../wicket/samples/pages/SliderPage.java | 142 ++ 23 files changed, 3078 insertions(+), 1 deletion(-) create mode 100644 bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/AjaxBootstrapSlider.java create mode 100644 bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/AjaxNumericBootstrapSlider.java create mode 100644 bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/BootstrapSlider.java create mode 100644 bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/ISliderValue.java create mode 100644 bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/NumericBootstrapSlider.java create mode 100644 bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/res/BootstrapSliderCssResourceReference.java create mode 100644 bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/res/BootstrapSliderResourceReference.java create mode 100644 bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/res/bootstrap-slider.js create mode 100644 bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/res/bootstrap-slider.min.js create mode 100644 bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/res/css/bootstrap-slider.css create mode 100644 bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/res/css/bootstrap-slider.min.css create mode 100644 bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/util/DoubleRangeValue.java create mode 100644 bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/util/DoubleValue.java create mode 100644 bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/util/INumericValue.java create mode 100644 bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/util/IntegerRangeValue.java create mode 100644 bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/util/IntegerValue.java create mode 100644 bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/util/LongRangeValue.java create mode 100644 bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/util/LongValue.java create mode 100644 bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/util/NumericModel.java create mode 100644 bootstrap-samples/src/main/java/de/agilecoders/wicket/samples/pages/SliderPage.html create mode 100644 bootstrap-samples/src/main/java/de/agilecoders/wicket/samples/pages/SliderPage.java diff --git a/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/AjaxBootstrapSlider.java b/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/AjaxBootstrapSlider.java new file mode 100644 index 000000000..f049d173f --- /dev/null +++ b/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/AjaxBootstrapSlider.java @@ -0,0 +1,67 @@ +package de.agilecoders.wicket.extensions.slider; + +import org.apache.wicket.ajax.AbstractDefaultAjaxBehavior; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.model.IModel; +import org.apache.wicket.request.cycle.RequestCycle; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +/** + * AjaxBootstrapSlider: ajaxified version of Slider. + */ +public class AjaxBootstrapSlider extends BootstrapSlider { + + private AbstractDefaultAjaxBehavior behavior; + + public enum SliderEvent { + slide, //This event fires when the slider is dragged + slideStart, //This event fires when dragging starts The new slider value + slideStop, //This event fires when the dragging stops or has been clicked on The new slider value + change + } + + public interface EventHandler extends Serializable { + + public void onAjaxEvent(AjaxRequestTarget target, T newValue); + } + + private final Map handlers = new HashMap(); + + public AjaxBootstrapSlider(String id, IModel model, Class typeClass) { + super(id, model, typeClass); + + behavior = new AbstractDefaultAjaxBehavior() { + @Override + protected void respond(AjaxRequestTarget target) { + SliderEvent event = SliderEvent.valueOf(RequestCycle.get().getRequest().getRequestParameters().getParameterValue("event").toString()); + AjaxBootstrapSlider.EventHandler handler = handlers.get(event); + T value = (T)newInstance().fromString(RequestCycle.get().getRequest().getRequestParameters().getParameterValue("value").toString()); + getModel().setObject(value); + if(handler != null) { + handler.onAjaxEvent(target, value); + } + } + }; + add(behavior); + } + + public AjaxBootstrapSlider addHandler(SliderEvent event, EventHandler handler) { + handlers.put(event, handler); + return this; + } + + @Override + protected void configEvents(StringBuilder builder) { + CharSequence url = behavior.getCallbackUrl(); + for(SliderEvent event: handlers.keySet()) { + builder.append(".on('").append(event.name()).append("',").append("function(value) {\n"); + builder.append("var ep={};\n").append("ep['event']='").append(event.name()).append("';\n"); + builder.append("ep['value']=value['value'];\n"); + builder.append("Wicket.Ajax.get({'u': '").append(url).append("', 'ep': ep").append("});"); + builder.append("\n})"); + } + } +} diff --git a/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/AjaxNumericBootstrapSlider.java b/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/AjaxNumericBootstrapSlider.java new file mode 100644 index 000000000..4f810f25a --- /dev/null +++ b/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/AjaxNumericBootstrapSlider.java @@ -0,0 +1,25 @@ +package de.agilecoders.wicket.extensions.slider; + +import de.agilecoders.wicket.extensions.slider.util.*; +import org.apache.wicket.model.IModel; + +/** + * AjaxNumericBootstrapSlider: version of Ajaxified slider that makes easier to work with numeric values. + */ +public class AjaxNumericBootstrapSlider extends AjaxBootstrapSlider, T> { + + public AjaxNumericBootstrapSlider(String id, IModel model) { + super(id, new NumericModel(model), (Class>)getSliderClass(model.getObject().getClass())); + } + + private static Class getSliderClass(Class typeClass) { + if(Double.class.isAssignableFrom(typeClass)) { + return DoubleValue.class; + } else if(Integer.class.isAssignableFrom(typeClass)) { + return IntegerValue.class; + } else { + return LongValue.class; + } + + } +} diff --git a/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/BootstrapSlider.java b/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/BootstrapSlider.java new file mode 100644 index 000000000..66808c3bb --- /dev/null +++ b/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/BootstrapSlider.java @@ -0,0 +1,330 @@ +package de.agilecoders.wicket.extensions.slider; + +import de.agilecoders.wicket.extensions.slider.res.BootstrapSliderCssResourceReference; +import de.agilecoders.wicket.extensions.slider.res.BootstrapSliderResourceReference; +import de.agilecoders.wicket.extensions.slider.util.*; +import org.apache.wicket.WicketRuntimeException; +import org.apache.wicket.markup.ComponentTag; +import org.apache.wicket.markup.head.CssHeaderItem; +import org.apache.wicket.markup.head.IHeaderResponse; +import org.apache.wicket.markup.head.JavaScriptHeaderItem; +import org.apache.wicket.markup.head.OnDomReadyHeaderItem; +import org.apache.wicket.markup.html.form.TextField; +import org.apache.wicket.model.IModel; +import org.apache.wicket.util.convert.ConversionException; +import org.apache.wicket.util.convert.IConverter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Locale; + +/** + * BootstrapSlider: a Wicket wrapper for: https://github.com/seiyria/bootstrap-slider + * + * @author Ernesto Reinaldo Barreiro (reiern70@gmail.com) + */ +public class BootstrapSlider extends TextField { + + private static Logger logger = LoggerFactory.getLogger(BootstrapSlider.class); + + public enum TooltipType { + show, hide, always + } + + public enum HandleType { + round, square, triangle, custom + } + + public enum Orientation { + horizontal, vertical + } + + public enum Scale { + logarithmic, + linear + } + + private static class BootstrapDoubleSliderConverter implements IConverter + { + @Override + public ISliderValue convertToObject(String value, Locale locale) throws ConversionException { + if(value.contains("[")) { + return new DoubleRangeValue().fromString(value); + } else { + return new DoubleValue().fromString(value); + } + } + + @Override + public String convertToString(ISliderValue value, Locale locale) { + return value.toString(); + } + } + + private static class BootstrapLongSliderConverter implements IConverter + { + @Override + public ISliderValue convertToObject(String value, Locale locale) throws ConversionException { + if(value.contains("[")) { + return new LongRangeValue().fromString(value); + } else { + return new LongValue().fromString(value); + } + } + + @Override + public String convertToString(ISliderValue value, Locale locale) { + return value.toString(); + } + } + + private static class BootstrapIntegerSliderConverter implements IConverter + { + @Override + public ISliderValue convertToObject(String value, Locale locale) throws ConversionException { + if(value.contains("[")) { + return new IntegerRangeValue().fromString(value); + } else { + return new IntegerValue().fromString(value); + } + } + + @Override + public String convertToString(ISliderValue value, Locale locale) { + return value.toString(); + } + } + + private IConverter converter; + + private N min; + private N max; + private N step; + private TooltipType tooltip; + private HandleType handle; + // function to create custom tooltip. + private String formatter; + private Orientation orientation; + /** + * whether or not the slider should be reversed + */ + private Boolean reversed; + /** + * if false show one tooltip if true show two tooltips one for each handler + */ + private Boolean tooltipSplit; + /** + * The number of digits shown after the decimal. Defaults to the number of digits after the decimal of step value. + */ + private Integer precision; + + private Scale scale; + + public BootstrapSlider(final String id, final IModel model, final Class typeClass) + { + super(id, model, typeClass); + setOutputMarkupId(true); + try { + if(Double.class.isAssignableFrom(typeClass.newInstance().getNumberType())) { + converter = new BootstrapDoubleSliderConverter(); + } else if(Integer.class.isAssignableFrom(typeClass.newInstance().getNumberType())) { + converter = new BootstrapIntegerSliderConverter(); + } else { + converter = new BootstrapLongSliderConverter(); + } + } catch (InstantiationException e) { + throw new WicketRuntimeException(e); + } catch (IllegalAccessException e) { + throw new WicketRuntimeException(e); + } + } + + protected T newInstance() { + try { + return getType().newInstance(); + } catch (InstantiationException e) { + logger.error("newInstance", e); + } catch (IllegalAccessException e) { + logger.error("newInstance", e); + } + return null; + } + + @Override + public IConverter getConverter(final Class type) + { + if (ISliderValue.class.isAssignableFrom(type)) + { + return (IConverter)converter; + } + else + { + return super.getConverter(type); + } + } + + @Override + protected void onComponentTag(ComponentTag tag) { + super.onComponentTag(tag); + // Must be attached to an input tag + checkComponentTag(tag, "input"); + tag.put("data-slider-value", converter.convertToString(getModelObject(), getLocale())); + tag.put("data-slider-min", min != null ? min.toString() : "0"); + tag.put("data-slider-max",max != null? max.toString(): "10"); + tag.put("data-slider-step",step != null? step.toString(): "1"); + tag.put("type", "text"); + if(tooltip != null) { + tag.put("data-slider-tooltip", tooltip.name()); + } + if(handle != null) { + tag.put("data-slider-handle", handle.name()); + } + if(!isEnabled()) { + tag.put("data-slider-enabled", false); + } + if(orientation != null) { + tag.put("data-slider-orientation", orientation.name()); + } + tag.put("id", getMarkupId()); + } + + @Override + public void renderHead(IHeaderResponse response) { + response.render(JavaScriptHeaderItem.forReference(BootstrapSliderResourceReference.getInstance())); + response.render(CssHeaderItem.forReference(BootstrapSliderCssResourceReference.getInstance())); + StringBuilder builder = new StringBuilder(); + builder.append("$('#").append(getMarkupId()).append("').slider({"); + if(formatter != null) { + builder.append("'formatter':").append(formatter); + } + if(reversed != null && reversed.equals(true)) { + builder.append("'reversed':").append(reversed); + } + if(tooltipSplit != null && tooltipSplit.equals(true)) { + builder.append("'tooltip_split':").append(tooltipSplit); + } + if(precision != null) { + builder.append("'precision':").append(precision); + } + if(scale != null) { + builder.append("'scale':").append(scale); + } + configExtraParams(builder); + builder.append("})"); + configEvents(builder); + builder.append(";"); + response.render(OnDomReadyHeaderItem.forScript(builder)); + } + + protected void configExtraParams(final StringBuilder builder) { + + + } + + protected void configEvents(StringBuilder builder) { + + + } + + public N getMin() { + return min; + } + + public BootstrapSlider setMin(N min) { + this.min = min; + return this; + } + + public N getMax() { + return max; + } + + public BootstrapSlider setMax(N max) { + this.max = max; + return this; + } + + public N getStep() { + return step; + } + + public BootstrapSlider setStep(N step) { + this.step = step; + return this; + } + + public TooltipType getTooltip() { + return tooltip; + } + + public BootstrapSlider setTooltip(TooltipType tooltip) { + this.tooltip = tooltip; + return this; + } + + public HandleType getHandle() { + return handle; + } + + public BootstrapSlider setHandle(HandleType handle) { + this.handle = handle; + return this; + } + + public String getFormatter() { + return formatter; + } + + public BootstrapSlider setFormatter(String formatter) { + this.formatter = formatter; + return this; + } + + public Orientation getOrientation() { + return orientation; + } + + public BootstrapSlider setOrientation(Orientation orientation) { + this.orientation = orientation; + return this; + } + + public Boolean getReversed() { + return reversed; + } + + public BootstrapSlider setReversed(Boolean reversed) { + this.reversed = reversed; + return this; + } + + public Boolean getTooltipSplit() { + return tooltipSplit; + } + + public BootstrapSlider setTooltipSplit(Boolean tooltipSplit) { + this.tooltipSplit = tooltipSplit; + return this; + } + + public Integer getPrecision() { + return precision; + } + + public BootstrapSlider setPrecision(Integer precision) { + this.precision = precision; + if(precision != null && precision < 0) { + throw new IllegalArgumentException("Precision should be a positive number"); + } + return this; + } + + public Scale getScale() { + return scale; + } + + public BootstrapSlider setScale(Scale scale) { + this.scale = scale; + return this; + } +} diff --git a/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/ISliderValue.java b/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/ISliderValue.java new file mode 100644 index 000000000..4612f41d6 --- /dev/null +++ b/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/ISliderValue.java @@ -0,0 +1,16 @@ +package de.agilecoders.wicket.extensions.slider; + +import java.io.Serializable; + +/** + * ISliderValue represents a value for the slider component: either a numeric value or a range [a,b], + * It know how to represent itself as a String and read itself form a String. + */ +public interface ISliderValue extends Serializable { + + ISliderValue fromString(String value); + + String toString(); + + Class getNumberType(); +} diff --git a/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/NumericBootstrapSlider.java b/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/NumericBootstrapSlider.java new file mode 100644 index 000000000..ff250f5be --- /dev/null +++ b/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/NumericBootstrapSlider.java @@ -0,0 +1,25 @@ +package de.agilecoders.wicket.extensions.slider; + +import de.agilecoders.wicket.extensions.slider.util.*; +import org.apache.wicket.model.IModel; + +/** + * NumericBootstrapSlider: version of slider that works with numeric values. + */ +public class NumericBootstrapSlider extends BootstrapSlider { + + public NumericBootstrapSlider(String id, IModel model) { + super(id, new NumericModel(model), (Class)getSliderClass(model.getObject().getClass())); + } + + private static Class getSliderClass(Class typeClass) { + if(Double.class.isAssignableFrom(typeClass)) { + return DoubleValue.class; + } else if(Integer.class.isAssignableFrom(typeClass)) { + return IntegerValue.class; + } else { + return LongValue.class; + } + + } +} diff --git a/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/res/BootstrapSliderCssResourceReference.java b/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/res/BootstrapSliderCssResourceReference.java new file mode 100644 index 000000000..5c68b017b --- /dev/null +++ b/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/res/BootstrapSliderCssResourceReference.java @@ -0,0 +1,19 @@ +package de.agilecoders.wicket.extensions.slider.res; + +import org.apache.wicket.request.resource.PackageResourceReference; + +/** + * BootsTrapSliderResourceReference + */ +public class BootstrapSliderCssResourceReference extends PackageResourceReference { + + private static final BootstrapSliderCssResourceReference instance = new BootstrapSliderCssResourceReference(); + + public BootstrapSliderCssResourceReference() { + super(BootstrapSliderCssResourceReference.class, "css/bootstrap-slider.css"); + } + + public static BootstrapSliderCssResourceReference getInstance() { + return instance; + } +} diff --git a/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/res/BootstrapSliderResourceReference.java b/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/res/BootstrapSliderResourceReference.java new file mode 100644 index 000000000..96b459d91 --- /dev/null +++ b/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/res/BootstrapSliderResourceReference.java @@ -0,0 +1,19 @@ +package de.agilecoders.wicket.extensions.slider.res; + +import org.apache.wicket.request.resource.JavaScriptResourceReference; + +/** + * BootsTrapSliderResourceReference + */ +public class BootstrapSliderResourceReference extends JavaScriptResourceReference { + + private static final BootstrapSliderResourceReference instance = new BootstrapSliderResourceReference(); + + public BootstrapSliderResourceReference() { + super(BootstrapSliderResourceReference.class, "bootstrap-slider.js"); + } + + public static BootstrapSliderResourceReference getInstance() { + return instance; + } +} diff --git a/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/res/bootstrap-slider.js b/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/res/bootstrap-slider.js new file mode 100644 index 000000000..620219618 --- /dev/null +++ b/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/res/bootstrap-slider.js @@ -0,0 +1,1548 @@ +/*! ======================================================= + VERSION 6.0.4 +========================================================= */ +"use strict"; + +function _typeof(obj) { return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj; } + +/*! ========================================================= + * bootstrap-slider.js + * + * Maintainers: + * Kyle Kemp + * - Twitter: @seiyria + * - Github: seiyria + * Rohit Kalkur + * - Twitter: @Rovolutionary + * - Github: rovolution + * + * ========================================================= + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================= */ + +/** + * Bridget makes jQuery widgets + * v1.0.1 + * MIT license + */ + +(function (factory) { + if (typeof define === "function" && define.amd) { + define(["jquery"], factory); + } else if ((typeof module === "undefined" ? "undefined" : _typeof(module)) === "object" && module.exports) { + var jQuery; + try { + jQuery = require("jquery"); + } catch (err) { + jQuery = null; + } + module.exports = factory(jQuery); + } else if (window) { + window.Slider = factory(window.jQuery); + } +})(function ($) { + // Reference to Slider constructor + var Slider; + + (function ($) { + + 'use strict'; + + // -------------------------- utils -------------------------- // + + var slice = Array.prototype.slice; + + function noop() {} + + // -------------------------- definition -------------------------- // + + function defineBridget($) { + + // bail if no jQuery + if (!$) { + return; + } + + // -------------------------- addOptionMethod -------------------------- // + + /** + * adds option method -> $().plugin('option', {...}) + * @param {Function} PluginClass - constructor class + */ + function addOptionMethod(PluginClass) { + // don't overwrite original option method + if (PluginClass.prototype.option) { + return; + } + + // option setter + PluginClass.prototype.option = function (opts) { + // bail out if not an object + if (!$.isPlainObject(opts)) { + return; + } + this.options = $.extend(true, this.options, opts); + }; + } + + // -------------------------- plugin bridge -------------------------- // + + // helper function for logging errors + // $.error breaks jQuery chaining + var logError = typeof console === 'undefined' ? noop : function (message) { + console.error(message); + }; + + /** + * jQuery plugin bridge, access methods like $elem.plugin('method') + * @param {String} namespace - plugin name + * @param {Function} PluginClass - constructor class + */ + function bridge(namespace, PluginClass) { + // add to jQuery fn namespace + $.fn[namespace] = function (options) { + if (typeof options === 'string') { + // call plugin method when first argument is a string + // get arguments for method + var args = slice.call(arguments, 1); + + for (var i = 0, len = this.length; i < len; i++) { + var elem = this[i]; + var instance = $.data(elem, namespace); + if (!instance) { + logError("cannot call methods on " + namespace + " prior to initialization; " + "attempted to call '" + options + "'"); + continue; + } + if (!$.isFunction(instance[options]) || options.charAt(0) === '_') { + logError("no such method '" + options + "' for " + namespace + " instance"); + continue; + } + + // trigger method with arguments + var returnValue = instance[options].apply(instance, args); + + // break look and return first value if provided + if (returnValue !== undefined && returnValue !== instance) { + return returnValue; + } + } + // return this if no return value + return this; + } else { + var objects = this.map(function () { + var instance = $.data(this, namespace); + if (instance) { + // apply options & init + instance.option(options); + instance._init(); + } else { + // initialize new instance + instance = new PluginClass(this, options); + $.data(this, namespace, instance); + } + return $(this); + }); + + if (!objects || objects.length > 1) { + return objects; + } else { + return objects[0]; + } + } + }; + } + + // -------------------------- bridget -------------------------- // + + /** + * converts a Prototypical class into a proper jQuery plugin + * the class must have a ._init method + * @param {String} namespace - plugin name, used in $().pluginName + * @param {Function} PluginClass - constructor class + */ + $.bridget = function (namespace, PluginClass) { + addOptionMethod(PluginClass); + bridge(namespace, PluginClass); + }; + + return $.bridget; + } + + // get jquery from browser global + defineBridget($); + })($); + + /************************************************* + BOOTSTRAP-SLIDER SOURCE CODE + **************************************************/ + + (function ($) { + + var ErrorMsgs = { + formatInvalidInputErrorMsg: function formatInvalidInputErrorMsg(input) { + return "Invalid input value '" + input + "' passed in"; + }, + callingContextNotSliderInstance: "Calling context element does not have instance of Slider bound to it. Check your code to make sure the JQuery object returned from the call to the slider() initializer is calling the method" + }; + + var SliderScale = { + linear: { + toValue: function toValue(percentage) { + var rawValue = percentage / 100 * (this.options.max - this.options.min); + var shouldAdjustWithBase = true; + if (this.options.ticks_positions.length > 0) { + var minv, + maxv, + minp, + maxp = 0; + for (var i = 1; i < this.options.ticks_positions.length; i++) { + if (percentage <= this.options.ticks_positions[i]) { + minv = this.options.ticks[i - 1]; + minp = this.options.ticks_positions[i - 1]; + maxv = this.options.ticks[i]; + maxp = this.options.ticks_positions[i]; + + break; + } + } + var partialPercentage = (percentage - minp) / (maxp - minp); + rawValue = minv + partialPercentage * (maxv - minv); + shouldAdjustWithBase = false; + } + + var adjustment = shouldAdjustWithBase ? this.options.min : 0; + var value = adjustment + Math.round(rawValue / this.options.step) * this.options.step; + if (value < this.options.min) { + return this.options.min; + } else if (value > this.options.max) { + return this.options.max; + } else { + return value; + } + }, + toPercentage: function toPercentage(value) { + if (this.options.max === this.options.min) { + return 0; + } + + if (this.options.ticks_positions.length > 0) { + var minv, + maxv, + minp, + maxp = 0; + for (var i = 0; i < this.options.ticks.length; i++) { + if (value <= this.options.ticks[i]) { + minv = i > 0 ? this.options.ticks[i - 1] : 0; + minp = i > 0 ? this.options.ticks_positions[i - 1] : 0; + maxv = this.options.ticks[i]; + maxp = this.options.ticks_positions[i]; + + break; + } + } + if (i > 0) { + var partialPercentage = (value - minv) / (maxv - minv); + return minp + partialPercentage * (maxp - minp); + } + } + + return 100 * (value - this.options.min) / (this.options.max - this.options.min); + } + }, + + logarithmic: { + /* Based on http://stackoverflow.com/questions/846221/logarithmic-slider */ + toValue: function toValue(percentage) { + var min = this.options.min === 0 ? 0 : Math.log(this.options.min); + var max = Math.log(this.options.max); + var value = Math.exp(min + (max - min) * percentage / 100); + value = this.options.min + Math.round((value - this.options.min) / this.options.step) * this.options.step; + /* Rounding to the nearest step could exceed the min or + * max, so clip to those values. */ + if (value < this.options.min) { + return this.options.min; + } else if (value > this.options.max) { + return this.options.max; + } else { + return value; + } + }, + toPercentage: function toPercentage(value) { + if (this.options.max === this.options.min) { + return 0; + } else { + var max = Math.log(this.options.max); + var min = this.options.min === 0 ? 0 : Math.log(this.options.min); + var v = value === 0 ? 0 : Math.log(value); + return 100 * (v - min) / (max - min); + } + } + } + }; + + /************************************************* + CONSTRUCTOR + **************************************************/ + Slider = function (element, options) { + createNewSlider.call(this, element, options); + return this; + }; + + function createNewSlider(element, options) { + + /* + The internal state object is used to store data about the current 'state' of slider. + This includes values such as the `value`, `enabled`, etc... + */ + this._state = { + value: null, + enabled: null, + offset: null, + size: null, + percentage: null, + inDrag: false, + over: false + }; + + if (typeof element === "string") { + this.element = document.querySelector(element); + } else if (element instanceof HTMLElement) { + this.element = element; + } + + /************************************************* + Process Options + **************************************************/ + options = options ? options : {}; + var optionTypes = Object.keys(this.defaultOptions); + + for (var i = 0; i < optionTypes.length; i++) { + var optName = optionTypes[i]; + + // First check if an option was passed in via the constructor + var val = options[optName]; + // If no data attrib, then check data atrributes + val = typeof val !== 'undefined' ? val : getDataAttrib(this.element, optName); + // Finally, if nothing was specified, use the defaults + val = val !== null ? val : this.defaultOptions[optName]; + + // Set all options on the instance of the Slider + if (!this.options) { + this.options = {}; + } + this.options[optName] = val; + } + + /* + Validate `tooltip_position` against 'orientation` + - if `tooltip_position` is incompatible with orientation, swith it to a default compatible with specified `orientation` + -- default for "vertical" -> "right" + -- default for "horizontal" -> "left" + */ + if (this.options.orientation === "vertical" && (this.options.tooltip_position === "top" || this.options.tooltip_position === "bottom")) { + + this.options.tooltip_position = "right"; + } else if (this.options.orientation === "horizontal" && (this.options.tooltip_position === "left" || this.options.tooltip_position === "right")) { + + this.options.tooltip_position = "top"; + } + + function getDataAttrib(element, optName) { + var dataName = "data-slider-" + optName.replace(/_/g, '-'); + var dataValString = element.getAttribute(dataName); + + try { + return JSON.parse(dataValString); + } catch (err) { + return dataValString; + } + } + + /************************************************* + Create Markup + **************************************************/ + + var origWidth = this.element.style.width; + var updateSlider = false; + var parent = this.element.parentNode; + var sliderTrackSelection; + var sliderTrackLow, sliderTrackHigh; + var sliderMinHandle; + var sliderMaxHandle; + + if (this.sliderElem) { + updateSlider = true; + } else { + /* Create elements needed for slider */ + this.sliderElem = document.createElement("div"); + this.sliderElem.className = "slider"; + + /* Create slider track elements */ + var sliderTrack = document.createElement("div"); + sliderTrack.className = "slider-track"; + + sliderTrackLow = document.createElement("div"); + sliderTrackLow.className = "slider-track-low"; + + sliderTrackSelection = document.createElement("div"); + sliderTrackSelection.className = "slider-selection"; + + sliderTrackHigh = document.createElement("div"); + sliderTrackHigh.className = "slider-track-high"; + + sliderMinHandle = document.createElement("div"); + sliderMinHandle.className = "slider-handle min-slider-handle"; + sliderMinHandle.setAttribute('role', 'slider'); + sliderMinHandle.setAttribute('aria-valuemin', this.options.min); + sliderMinHandle.setAttribute('aria-valuemax', this.options.max); + + sliderMaxHandle = document.createElement("div"); + sliderMaxHandle.className = "slider-handle max-slider-handle"; + sliderMaxHandle.setAttribute('role', 'slider'); + sliderMaxHandle.setAttribute('aria-valuemin', this.options.min); + sliderMaxHandle.setAttribute('aria-valuemax', this.options.max); + + sliderTrack.appendChild(sliderTrackLow); + sliderTrack.appendChild(sliderTrackSelection); + sliderTrack.appendChild(sliderTrackHigh); + + /* Add aria-labelledby to handle's */ + var isLabelledbyArray = Array.isArray(this.options.labelledby); + if (isLabelledbyArray && this.options.labelledby[0]) { + sliderMinHandle.setAttribute('aria-labelledby', this.options.labelledby[0]); + } + if (isLabelledbyArray && this.options.labelledby[1]) { + sliderMaxHandle.setAttribute('aria-labelledby', this.options.labelledby[1]); + } + if (!isLabelledbyArray && this.options.labelledby) { + sliderMinHandle.setAttribute('aria-labelledby', this.options.labelledby); + sliderMaxHandle.setAttribute('aria-labelledby', this.options.labelledby); + } + + /* Create ticks */ + this.ticks = []; + if (Array.isArray(this.options.ticks) && this.options.ticks.length > 0) { + for (i = 0; i < this.options.ticks.length; i++) { + var tick = document.createElement('div'); + tick.className = 'slider-tick'; + + this.ticks.push(tick); + sliderTrack.appendChild(tick); + } + + sliderTrackSelection.className += " tick-slider-selection"; + } + + sliderTrack.appendChild(sliderMinHandle); + sliderTrack.appendChild(sliderMaxHandle); + + this.tickLabels = []; + if (Array.isArray(this.options.ticks_labels) && this.options.ticks_labels.length > 0) { + this.tickLabelContainer = document.createElement('div'); + this.tickLabelContainer.className = 'slider-tick-label-container'; + + for (i = 0; i < this.options.ticks_labels.length; i++) { + var label = document.createElement('div'); + var noTickPositionsSpecified = this.options.ticks_positions.length === 0; + var tickLabelsIndex = this.options.reversed && noTickPositionsSpecified ? this.options.ticks_labels.length - (i + 1) : i; + label.className = 'slider-tick-label'; + label.innerHTML = this.options.ticks_labels[tickLabelsIndex]; + + this.tickLabels.push(label); + this.tickLabelContainer.appendChild(label); + } + } + + var createAndAppendTooltipSubElements = function createAndAppendTooltipSubElements(tooltipElem) { + var arrow = document.createElement("div"); + arrow.className = "tooltip-arrow"; + + var inner = document.createElement("div"); + inner.className = "tooltip-inner"; + + tooltipElem.appendChild(arrow); + tooltipElem.appendChild(inner); + }; + + /* Create tooltip elements */ + var sliderTooltip = document.createElement("div"); + sliderTooltip.className = "tooltip tooltip-main"; + sliderTooltip.setAttribute('role', 'presentation'); + createAndAppendTooltipSubElements(sliderTooltip); + + var sliderTooltipMin = document.createElement("div"); + sliderTooltipMin.className = "tooltip tooltip-min"; + sliderTooltipMin.setAttribute('role', 'presentation'); + createAndAppendTooltipSubElements(sliderTooltipMin); + + var sliderTooltipMax = document.createElement("div"); + sliderTooltipMax.className = "tooltip tooltip-max"; + sliderTooltipMax.setAttribute('role', 'presentation'); + createAndAppendTooltipSubElements(sliderTooltipMax); + + /* Append components to sliderElem */ + this.sliderElem.appendChild(sliderTrack); + this.sliderElem.appendChild(sliderTooltip); + this.sliderElem.appendChild(sliderTooltipMin); + this.sliderElem.appendChild(sliderTooltipMax); + + if (this.tickLabelContainer) { + this.sliderElem.appendChild(this.tickLabelContainer); + } + + /* Append slider element to parent container, right before the original element */ + parent.insertBefore(this.sliderElem, this.element); + + /* Hide original element */ + this.element.style.display = "none"; + } + /* If JQuery exists, cache JQ references */ + if ($) { + this.$element = $(this.element); + this.$sliderElem = $(this.sliderElem); + } + + /************************************************* + Setup + **************************************************/ + this.eventToCallbackMap = {}; + this.sliderElem.id = this.options.id; + + this.touchCapable = 'ontouchstart' in window || window.DocumentTouch && document instanceof window.DocumentTouch; + + this.tooltip = this.sliderElem.querySelector('.tooltip-main'); + this.tooltipInner = this.tooltip.querySelector('.tooltip-inner'); + + this.tooltip_min = this.sliderElem.querySelector('.tooltip-min'); + this.tooltipInner_min = this.tooltip_min.querySelector('.tooltip-inner'); + + this.tooltip_max = this.sliderElem.querySelector('.tooltip-max'); + this.tooltipInner_max = this.tooltip_max.querySelector('.tooltip-inner'); + + if (SliderScale[this.options.scale]) { + this.options.scale = SliderScale[this.options.scale]; + } + + if (updateSlider === true) { + // Reset classes + this._removeClass(this.sliderElem, 'slider-horizontal'); + this._removeClass(this.sliderElem, 'slider-vertical'); + this._removeClass(this.tooltip, 'hide'); + this._removeClass(this.tooltip_min, 'hide'); + this._removeClass(this.tooltip_max, 'hide'); + + // Undo existing inline styles for track + ["left", "top", "width", "height"].forEach(function (prop) { + this._removeProperty(this.trackLow, prop); + this._removeProperty(this.trackSelection, prop); + this._removeProperty(this.trackHigh, prop); + }, this); + + // Undo inline styles on handles + [this.handle1, this.handle2].forEach(function (handle) { + this._removeProperty(handle, 'left'); + this._removeProperty(handle, 'top'); + }, this); + + // Undo inline styles and classes on tooltips + [this.tooltip, this.tooltip_min, this.tooltip_max].forEach(function (tooltip) { + this._removeProperty(tooltip, 'left'); + this._removeProperty(tooltip, 'top'); + this._removeProperty(tooltip, 'margin-left'); + this._removeProperty(tooltip, 'margin-top'); + + this._removeClass(tooltip, 'right'); + this._removeClass(tooltip, 'top'); + }, this); + } + + if (this.options.orientation === 'vertical') { + this._addClass(this.sliderElem, 'slider-vertical'); + this.stylePos = 'top'; + this.mousePos = 'pageY'; + this.sizePos = 'offsetHeight'; + } else { + this._addClass(this.sliderElem, 'slider-horizontal'); + this.sliderElem.style.width = origWidth; + this.options.orientation = 'horizontal'; + this.stylePos = 'left'; + this.mousePos = 'pageX'; + this.sizePos = 'offsetWidth'; + } + this._setTooltipPosition(); + /* In case ticks are specified, overwrite the min and max bounds */ + if (Array.isArray(this.options.ticks) && this.options.ticks.length > 0) { + this.options.max = Math.max.apply(Math, this.options.ticks); + this.options.min = Math.min.apply(Math, this.options.ticks); + } + + if (Array.isArray(this.options.value)) { + this.options.range = true; + this._state.value = this.options.value; + } else if (this.options.range) { + // User wants a range, but value is not an array + this._state.value = [this.options.value, this.options.max]; + } else { + this._state.value = this.options.value; + } + + this.trackLow = sliderTrackLow || this.trackLow; + this.trackSelection = sliderTrackSelection || this.trackSelection; + this.trackHigh = sliderTrackHigh || this.trackHigh; + + if (this.options.selection === 'none') { + this._addClass(this.trackLow, 'hide'); + this._addClass(this.trackSelection, 'hide'); + this._addClass(this.trackHigh, 'hide'); + } + + this.handle1 = sliderMinHandle || this.handle1; + this.handle2 = sliderMaxHandle || this.handle2; + + if (updateSlider === true) { + // Reset classes + this._removeClass(this.handle1, 'round triangle'); + this._removeClass(this.handle2, 'round triangle hide'); + + for (i = 0; i < this.ticks.length; i++) { + this._removeClass(this.ticks[i], 'round triangle hide'); + } + } + + var availableHandleModifiers = ['round', 'triangle', 'custom']; + var isValidHandleType = availableHandleModifiers.indexOf(this.options.handle) !== -1; + if (isValidHandleType) { + this._addClass(this.handle1, this.options.handle); + this._addClass(this.handle2, this.options.handle); + + for (i = 0; i < this.ticks.length; i++) { + this._addClass(this.ticks[i], this.options.handle); + } + } + + this._state.offset = this._offset(this.sliderElem); + this._state.size = this.sliderElem[this.sizePos]; + this.setValue(this._state.value); + + /****************************************** + Bind Event Listeners + ******************************************/ + + // Bind keyboard handlers + this.handle1Keydown = this._keydown.bind(this, 0); + this.handle1.addEventListener("keydown", this.handle1Keydown, false); + + this.handle2Keydown = this._keydown.bind(this, 1); + this.handle2.addEventListener("keydown", this.handle2Keydown, false); + + this.mousedown = this._mousedown.bind(this); + if (this.touchCapable) { + // Bind touch handlers + this.sliderElem.addEventListener("touchstart", this.mousedown, false); + } + this.sliderElem.addEventListener("mousedown", this.mousedown, false); + + // Bind window handlers + this.resize = this._resize.bind(this); + window.addEventListener("resize", this.resize, false); + + // Bind tooltip-related handlers + if (this.options.tooltip === 'hide') { + this._addClass(this.tooltip, 'hide'); + this._addClass(this.tooltip_min, 'hide'); + this._addClass(this.tooltip_max, 'hide'); + } else if (this.options.tooltip === 'always') { + this._showTooltip(); + this._alwaysShowTooltip = true; + } else { + this.showTooltip = this._showTooltip.bind(this); + this.hideTooltip = this._hideTooltip.bind(this); + + this.sliderElem.addEventListener("mouseenter", this.showTooltip, false); + this.sliderElem.addEventListener("mouseleave", this.hideTooltip, false); + + this.handle1.addEventListener("focus", this.showTooltip, false); + this.handle1.addEventListener("blur", this.hideTooltip, false); + + this.handle2.addEventListener("focus", this.showTooltip, false); + this.handle2.addEventListener("blur", this.hideTooltip, false); + } + + if (this.options.enabled) { + this.enable(); + } else { + this.disable(); + } + } + + /************************************************* + INSTANCE PROPERTIES/METHODS + - Any methods bound to the prototype are considered + part of the plugin's `public` interface + **************************************************/ + Slider.prototype = { + _init: function _init() {}, // NOTE: Must exist to support bridget + + constructor: Slider, + + defaultOptions: { + id: "", + min: 0, + max: 10, + step: 1, + precision: 0, + orientation: 'horizontal', + value: 5, + range: false, + selection: 'before', + tooltip: 'show', + tooltip_split: false, + handle: 'round', + reversed: false, + enabled: true, + formatter: function formatter(val) { + if (Array.isArray(val)) { + return val[0] + " : " + val[1]; + } else { + return val; + } + }, + natural_arrow_keys: false, + ticks: [], + ticks_positions: [], + ticks_labels: [], + ticks_snap_bounds: 0, + scale: 'linear', + focus: false, + tooltip_position: null, + labelledby: null + }, + + getElement: function getElement() { + return this.sliderElem; + }, + + getValue: function getValue() { + if (this.options.range) { + return this._state.value; + } else { + return this._state.value[0]; + } + }, + + setValue: function setValue(val, triggerSlideEvent, triggerChangeEvent) { + if (!val) { + val = 0; + } + var oldValue = this.getValue(); + this._state.value = this._validateInputValue(val); + var applyPrecision = this._applyPrecision.bind(this); + + if (this.options.range) { + this._state.value[0] = applyPrecision(this._state.value[0]); + this._state.value[1] = applyPrecision(this._state.value[1]); + + this._state.value[0] = Math.max(this.options.min, Math.min(this.options.max, this._state.value[0])); + this._state.value[1] = Math.max(this.options.min, Math.min(this.options.max, this._state.value[1])); + } else { + this._state.value = applyPrecision(this._state.value); + this._state.value = [Math.max(this.options.min, Math.min(this.options.max, this._state.value))]; + this._addClass(this.handle2, 'hide'); + if (this.options.selection === 'after') { + this._state.value[1] = this.options.max; + } else { + this._state.value[1] = this.options.min; + } + } + + if (this.options.max > this.options.min) { + this._state.percentage = [this._toPercentage(this._state.value[0]), this._toPercentage(this._state.value[1]), this.options.step * 100 / (this.options.max - this.options.min)]; + } else { + this._state.percentage = [0, 0, 100]; + } + + this._layout(); + var newValue = this.options.range ? this._state.value : this._state.value[0]; + + if (triggerSlideEvent === true) { + this._trigger('slide', newValue); + } + if (oldValue !== newValue && triggerChangeEvent === true) { + this._trigger('change', { + oldValue: oldValue, + newValue: newValue + }); + } + this._setDataVal(newValue); + + return this; + }, + + destroy: function destroy() { + // Remove event handlers on slider elements + this._removeSliderEventHandlers(); + + // Remove the slider from the DOM + this.sliderElem.parentNode.removeChild(this.sliderElem); + /* Show original element */ + this.element.style.display = ""; + + // Clear out custom event bindings + this._cleanUpEventCallbacksMap(); + + // Remove data values + this.element.removeAttribute("data"); + + // Remove JQuery handlers/data + if ($) { + this._unbindJQueryEventHandlers(); + this.$element.removeData('slider'); + } + }, + + disable: function disable() { + this._state.enabled = false; + this.handle1.removeAttribute("tabindex"); + this.handle2.removeAttribute("tabindex"); + this._addClass(this.sliderElem, 'slider-disabled'); + this._trigger('slideDisabled'); + + return this; + }, + + enable: function enable() { + this._state.enabled = true; + this.handle1.setAttribute("tabindex", 0); + this.handle2.setAttribute("tabindex", 0); + this._removeClass(this.sliderElem, 'slider-disabled'); + this._trigger('slideEnabled'); + + return this; + }, + + toggle: function toggle() { + if (this._state.enabled) { + this.disable(); + } else { + this.enable(); + } + return this; + }, + + isEnabled: function isEnabled() { + return this._state.enabled; + }, + + on: function on(evt, callback) { + this._bindNonQueryEventHandler(evt, callback); + return this; + }, + + off: function off(evt, callback) { + if ($) { + this.$element.off(evt, callback); + this.$sliderElem.off(evt, callback); + } else { + this._unbindNonQueryEventHandler(evt, callback); + } + }, + + getAttribute: function getAttribute(attribute) { + if (attribute) { + return this.options[attribute]; + } else { + return this.options; + } + }, + + setAttribute: function setAttribute(attribute, value) { + this.options[attribute] = value; + return this; + }, + + refresh: function refresh() { + this._removeSliderEventHandlers(); + createNewSlider.call(this, this.element, this.options); + if ($) { + // Bind new instance of slider to the element + $.data(this.element, 'slider', this); + } + return this; + }, + + relayout: function relayout() { + this._layout(); + return this; + }, + + /******************************+ + HELPERS + - Any method that is not part of the public interface. + - Place it underneath this comment block and write its signature like so: + _fnName : function() {...} + ********************************/ + _removeSliderEventHandlers: function _removeSliderEventHandlers() { + // Remove keydown event listeners + this.handle1.removeEventListener("keydown", this.handle1Keydown, false); + this.handle2.removeEventListener("keydown", this.handle2Keydown, false); + + if (this.showTooltip) { + this.handle1.removeEventListener("focus", this.showTooltip, false); + this.handle2.removeEventListener("focus", this.showTooltip, false); + } + if (this.hideTooltip) { + this.handle1.removeEventListener("blur", this.hideTooltip, false); + this.handle2.removeEventListener("blur", this.hideTooltip, false); + } + + // Remove event listeners from sliderElem + if (this.showTooltip) { + this.sliderElem.removeEventListener("mouseenter", this.showTooltip, false); + } + if (this.hideTooltip) { + this.sliderElem.removeEventListener("mouseleave", this.hideTooltip, false); + } + this.sliderElem.removeEventListener("touchstart", this.mousedown, false); + this.sliderElem.removeEventListener("mousedown", this.mousedown, false); + + // Remove window event listener + window.removeEventListener("resize", this.resize, false); + }, + _bindNonQueryEventHandler: function _bindNonQueryEventHandler(evt, callback) { + if (this.eventToCallbackMap[evt] === undefined) { + this.eventToCallbackMap[evt] = []; + } + this.eventToCallbackMap[evt].push(callback); + }, + _unbindNonQueryEventHandler: function _unbindNonQueryEventHandler(evt, callback) { + var callbacks = this.eventToCallbackMap[evt]; + if (callbacks !== undefined) { + for (var i = 0; i < callbacks.length; i++) { + if (callbacks[i] === callback) { + callbacks.splice(i, 1); + break; + } + } + } + }, + _cleanUpEventCallbacksMap: function _cleanUpEventCallbacksMap() { + var eventNames = Object.keys(this.eventToCallbackMap); + for (var i = 0; i < eventNames.length; i++) { + var eventName = eventNames[i]; + this.eventToCallbackMap[eventName] = null; + } + }, + _showTooltip: function _showTooltip() { + if (this.options.tooltip_split === false) { + this._addClass(this.tooltip, 'in'); + this.tooltip_min.style.display = 'none'; + this.tooltip_max.style.display = 'none'; + } else { + this._addClass(this.tooltip_min, 'in'); + this._addClass(this.tooltip_max, 'in'); + this.tooltip.style.display = 'none'; + } + this._state.over = true; + }, + _hideTooltip: function _hideTooltip() { + if (this._state.inDrag === false && this.alwaysShowTooltip !== true) { + this._removeClass(this.tooltip, 'in'); + this._removeClass(this.tooltip_min, 'in'); + this._removeClass(this.tooltip_max, 'in'); + } + this._state.over = false; + }, + _layout: function _layout() { + var positionPercentages; + + if (this.options.reversed) { + positionPercentages = [100 - this._state.percentage[0], this.options.range ? 100 - this._state.percentage[1] : this._state.percentage[1]]; + } else { + positionPercentages = [this._state.percentage[0], this._state.percentage[1]]; + } + + this.handle1.style[this.stylePos] = positionPercentages[0] + '%'; + this.handle1.setAttribute('aria-valuenow', this._state.value[0]); + + this.handle2.style[this.stylePos] = positionPercentages[1] + '%'; + this.handle2.setAttribute('aria-valuenow', this._state.value[1]); + + /* Position ticks and labels */ + if (Array.isArray(this.options.ticks) && this.options.ticks.length > 0) { + + var styleSize = this.options.orientation === 'vertical' ? 'height' : 'width'; + var styleMargin = this.options.orientation === 'vertical' ? 'marginTop' : 'marginLeft'; + var labelSize = this._state.size / (this.options.ticks.length - 1); + + if (this.tickLabelContainer) { + var extraMargin = 0; + if (this.options.ticks_positions.length === 0) { + if (this.options.orientation !== 'vertical') { + this.tickLabelContainer.style[styleMargin] = -labelSize / 2 + 'px'; + } + + extraMargin = this.tickLabelContainer.offsetHeight; + } else { + /* Chidren are position absolute, calculate height by finding the max offsetHeight of a child */ + for (i = 0; i < this.tickLabelContainer.childNodes.length; i++) { + if (this.tickLabelContainer.childNodes[i].offsetHeight > extraMargin) { + extraMargin = this.tickLabelContainer.childNodes[i].offsetHeight; + } + } + } + if (this.options.orientation === 'horizontal') { + this.sliderElem.style.marginBottom = extraMargin + 'px'; + } + } + for (var i = 0; i < this.options.ticks.length; i++) { + + var percentage = this.options.ticks_positions[i] || this._toPercentage(this.options.ticks[i]); + + if (this.options.reversed) { + percentage = 100 - percentage; + } + + this.ticks[i].style[this.stylePos] = percentage + '%'; + + /* Set class labels to denote whether ticks are in the selection */ + this._removeClass(this.ticks[i], 'in-selection'); + if (!this.options.range) { + if (this.options.selection === 'after' && percentage >= positionPercentages[0]) { + this._addClass(this.ticks[i], 'in-selection'); + } else if (this.options.selection === 'before' && percentage <= positionPercentages[0]) { + this._addClass(this.ticks[i], 'in-selection'); + } + } else if (percentage >= positionPercentages[0] && percentage <= positionPercentages[1]) { + this._addClass(this.ticks[i], 'in-selection'); + } + + if (this.tickLabels[i]) { + this.tickLabels[i].style[styleSize] = labelSize + 'px'; + + if (this.options.orientation !== 'vertical' && this.options.ticks_positions[i] !== undefined) { + this.tickLabels[i].style.position = 'absolute'; + this.tickLabels[i].style[this.stylePos] = percentage + '%'; + this.tickLabels[i].style[styleMargin] = -labelSize / 2 + 'px'; + } else if (this.options.orientation === 'vertical') { + this.tickLabels[i].style['marginLeft'] = this.sliderElem.offsetWidth + 'px'; + this.tickLabelContainer.style['marginTop'] = this.sliderElem.offsetWidth / 2 * -1 + 'px'; + } + } + } + } + + var formattedTooltipVal; + + if (this.options.range) { + formattedTooltipVal = this.options.formatter(this._state.value); + this._setText(this.tooltipInner, formattedTooltipVal); + this.tooltip.style[this.stylePos] = (positionPercentages[1] + positionPercentages[0]) / 2 + '%'; + + if (this.options.orientation === 'vertical') { + this._css(this.tooltip, 'margin-top', -this.tooltip.offsetHeight / 2 + 'px'); + } else { + this._css(this.tooltip, 'margin-left', -this.tooltip.offsetWidth / 2 + 'px'); + } + + if (this.options.orientation === 'vertical') { + this._css(this.tooltip, 'margin-top', -this.tooltip.offsetHeight / 2 + 'px'); + } else { + this._css(this.tooltip, 'margin-left', -this.tooltip.offsetWidth / 2 + 'px'); + } + + var innerTooltipMinText = this.options.formatter(this._state.value[0]); + this._setText(this.tooltipInner_min, innerTooltipMinText); + + var innerTooltipMaxText = this.options.formatter(this._state.value[1]); + this._setText(this.tooltipInner_max, innerTooltipMaxText); + + this.tooltip_min.style[this.stylePos] = positionPercentages[0] + '%'; + + if (this.options.orientation === 'vertical') { + this._css(this.tooltip_min, 'margin-top', -this.tooltip_min.offsetHeight / 2 + 'px'); + } else { + this._css(this.tooltip_min, 'margin-left', -this.tooltip_min.offsetWidth / 2 + 'px'); + } + + this.tooltip_max.style[this.stylePos] = positionPercentages[1] + '%'; + + if (this.options.orientation === 'vertical') { + this._css(this.tooltip_max, 'margin-top', -this.tooltip_max.offsetHeight / 2 + 'px'); + } else { + this._css(this.tooltip_max, 'margin-left', -this.tooltip_max.offsetWidth / 2 + 'px'); + } + } else { + formattedTooltipVal = this.options.formatter(this._state.value[0]); + this._setText(this.tooltipInner, formattedTooltipVal); + + this.tooltip.style[this.stylePos] = positionPercentages[0] + '%'; + if (this.options.orientation === 'vertical') { + this._css(this.tooltip, 'margin-top', -this.tooltip.offsetHeight / 2 + 'px'); + } else { + this._css(this.tooltip, 'margin-left', -this.tooltip.offsetWidth / 2 + 'px'); + } + } + + if (this.options.orientation === 'vertical') { + this.trackLow.style.top = '0'; + this.trackLow.style.height = Math.min(positionPercentages[0], positionPercentages[1]) + '%'; + + this.trackSelection.style.top = Math.min(positionPercentages[0], positionPercentages[1]) + '%'; + this.trackSelection.style.height = Math.abs(positionPercentages[0] - positionPercentages[1]) + '%'; + + this.trackHigh.style.bottom = '0'; + this.trackHigh.style.height = 100 - Math.min(positionPercentages[0], positionPercentages[1]) - Math.abs(positionPercentages[0] - positionPercentages[1]) + '%'; + } else { + this.trackLow.style.left = '0'; + this.trackLow.style.width = Math.min(positionPercentages[0], positionPercentages[1]) + '%'; + + this.trackSelection.style.left = Math.min(positionPercentages[0], positionPercentages[1]) + '%'; + this.trackSelection.style.width = Math.abs(positionPercentages[0] - positionPercentages[1]) + '%'; + + this.trackHigh.style.right = '0'; + this.trackHigh.style.width = 100 - Math.min(positionPercentages[0], positionPercentages[1]) - Math.abs(positionPercentages[0] - positionPercentages[1]) + '%'; + + var offset_min = this.tooltip_min.getBoundingClientRect(); + var offset_max = this.tooltip_max.getBoundingClientRect(); + + if (offset_min.right > offset_max.left) { + this._removeClass(this.tooltip_max, 'top'); + this._addClass(this.tooltip_max, 'bottom'); + this.tooltip_max.style.top = 18 + 'px'; + } else { + this._removeClass(this.tooltip_max, 'bottom'); + this._addClass(this.tooltip_max, 'top'); + this.tooltip_max.style.top = this.tooltip_min.style.top; + } + } + }, + _resize: function _resize(ev) { + /*jshint unused:false*/ + this._state.offset = this._offset(this.sliderElem); + this._state.size = this.sliderElem[this.sizePos]; + this._layout(); + }, + _removeProperty: function _removeProperty(element, prop) { + if (element.style.removeProperty) { + element.style.removeProperty(prop); + } else { + element.style.removeAttribute(prop); + } + }, + _mousedown: function _mousedown(ev) { + if (!this._state.enabled) { + return false; + } + + this._state.offset = this._offset(this.sliderElem); + this._state.size = this.sliderElem[this.sizePos]; + + var percentage = this._getPercentage(ev); + + if (this.options.range) { + var diff1 = Math.abs(this._state.percentage[0] - percentage); + var diff2 = Math.abs(this._state.percentage[1] - percentage); + this._state.dragged = diff1 < diff2 ? 0 : 1; + } else { + this._state.dragged = 0; + } + + this._state.percentage[this._state.dragged] = percentage; + this._layout(); + + if (this.touchCapable) { + document.removeEventListener("touchmove", this.mousemove, false); + document.removeEventListener("touchend", this.mouseup, false); + } + + if (this.mousemove) { + document.removeEventListener("mousemove", this.mousemove, false); + } + if (this.mouseup) { + document.removeEventListener("mouseup", this.mouseup, false); + } + + this.mousemove = this._mousemove.bind(this); + this.mouseup = this._mouseup.bind(this); + + if (this.touchCapable) { + // Touch: Bind touch events: + document.addEventListener("touchmove", this.mousemove, false); + document.addEventListener("touchend", this.mouseup, false); + } + // Bind mouse events: + document.addEventListener("mousemove", this.mousemove, false); + document.addEventListener("mouseup", this.mouseup, false); + + this._state.inDrag = true; + var newValue = this._calculateValue(); + + this._trigger('slideStart', newValue); + + this._setDataVal(newValue); + this.setValue(newValue, false, true); + + this._pauseEvent(ev); + + if (this.options.focus) { + this._triggerFocusOnHandle(this._state.dragged); + } + + return true; + }, + _triggerFocusOnHandle: function _triggerFocusOnHandle(handleIdx) { + if (handleIdx === 0) { + this.handle1.focus(); + } + if (handleIdx === 1) { + this.handle2.focus(); + } + }, + _keydown: function _keydown(handleIdx, ev) { + if (!this._state.enabled) { + return false; + } + + var dir; + switch (ev.keyCode) { + case 37: // left + case 40: + // down + dir = -1; + break; + case 39: // right + case 38: + // up + dir = 1; + break; + } + if (!dir) { + return; + } + + // use natural arrow keys instead of from min to max + if (this.options.natural_arrow_keys) { + var ifVerticalAndNotReversed = this.options.orientation === 'vertical' && !this.options.reversed; + var ifHorizontalAndReversed = this.options.orientation === 'horizontal' && this.options.reversed; + + if (ifVerticalAndNotReversed || ifHorizontalAndReversed) { + dir = -dir; + } + } + + var val = this._state.value[handleIdx] + dir * this.options.step; + if (this.options.range) { + val = [!handleIdx ? val : this._state.value[0], handleIdx ? val : this._state.value[1]]; + } + + this._trigger('slideStart', val); + this._setDataVal(val); + this.setValue(val, true, true); + + this._setDataVal(val); + this._trigger('slideStop', val); + this._layout(); + + this._pauseEvent(ev); + + return false; + }, + _pauseEvent: function _pauseEvent(ev) { + if (ev.stopPropagation) { + ev.stopPropagation(); + } + if (ev.preventDefault) { + ev.preventDefault(); + } + ev.cancelBubble = true; + ev.returnValue = false; + }, + _mousemove: function _mousemove(ev) { + if (!this._state.enabled) { + return false; + } + + var percentage = this._getPercentage(ev); + this._adjustPercentageForRangeSliders(percentage); + this._state.percentage[this._state.dragged] = percentage; + this._layout(); + + var val = this._calculateValue(true); + this.setValue(val, true, true); + + return false; + }, + _adjustPercentageForRangeSliders: function _adjustPercentageForRangeSliders(percentage) { + if (this.options.range) { + var precision = this._getNumDigitsAfterDecimalPlace(percentage); + precision = precision ? precision - 1 : 0; + var percentageWithAdjustedPrecision = this._applyToFixedAndParseFloat(percentage, precision); + if (this._state.dragged === 0 && this._applyToFixedAndParseFloat(this._state.percentage[1], precision) < percentageWithAdjustedPrecision) { + this._state.percentage[0] = this._state.percentage[1]; + this._state.dragged = 1; + } else if (this._state.dragged === 1 && this._applyToFixedAndParseFloat(this._state.percentage[0], precision) > percentageWithAdjustedPrecision) { + this._state.percentage[1] = this._state.percentage[0]; + this._state.dragged = 0; + } + } + }, + _mouseup: function _mouseup() { + if (!this._state.enabled) { + return false; + } + if (this.touchCapable) { + // Touch: Unbind touch event handlers: + document.removeEventListener("touchmove", this.mousemove, false); + document.removeEventListener("touchend", this.mouseup, false); + } + // Unbind mouse event handlers: + document.removeEventListener("mousemove", this.mousemove, false); + document.removeEventListener("mouseup", this.mouseup, false); + + this._state.inDrag = false; + if (this._state.over === false) { + this._hideTooltip(); + } + var val = this._calculateValue(true); + + this._layout(); + this._setDataVal(val); + this._trigger('slideStop', val); + + return false; + }, + _calculateValue: function _calculateValue(snapToClosestTick) { + var val; + if (this.options.range) { + val = [this.options.min, this.options.max]; + if (this._state.percentage[0] !== 0) { + val[0] = this._toValue(this._state.percentage[0]); + val[0] = this._applyPrecision(val[0]); + } + if (this._state.percentage[1] !== 100) { + val[1] = this._toValue(this._state.percentage[1]); + val[1] = this._applyPrecision(val[1]); + } + } else { + val = this._toValue(this._state.percentage[0]); + val = parseFloat(val); + val = this._applyPrecision(val); + } + + if (snapToClosestTick) { + var min = [val, Infinity]; + for (var i = 0; i < this.options.ticks.length; i++) { + var diff = Math.abs(this.options.ticks[i] - val); + if (diff <= min[1]) { + min = [this.options.ticks[i], diff]; + } + } + if (min[1] <= this.options.ticks_snap_bounds) { + return min[0]; + } + } + + return val; + }, + _applyPrecision: function _applyPrecision(val) { + var precision = this.options.precision || this._getNumDigitsAfterDecimalPlace(this.options.step); + return this._applyToFixedAndParseFloat(val, precision); + }, + _getNumDigitsAfterDecimalPlace: function _getNumDigitsAfterDecimalPlace(num) { + var match = ('' + num).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/); + if (!match) { + return 0; + } + return Math.max(0, (match[1] ? match[1].length : 0) - (match[2] ? +match[2] : 0)); + }, + _applyToFixedAndParseFloat: function _applyToFixedAndParseFloat(num, toFixedInput) { + var truncatedNum = num.toFixed(toFixedInput); + return parseFloat(truncatedNum); + }, + /* + Credits to Mike Samuel for the following method! + Source: http://stackoverflow.com/questions/10454518/javascript-how-to-retrieve-the-number-of-decimals-of-a-string-number + */ + _getPercentage: function _getPercentage(ev) { + if (this.touchCapable && (ev.type === 'touchstart' || ev.type === 'touchmove')) { + ev = ev.touches[0]; + } + + var eventPosition = ev[this.mousePos]; + var sliderOffset = this._state.offset[this.stylePos]; + var distanceToSlide = eventPosition - sliderOffset; + // Calculate what percent of the length the slider handle has slid + var percentage = distanceToSlide / this._state.size * 100; + percentage = Math.round(percentage / this._state.percentage[2]) * this._state.percentage[2]; + if (this.options.reversed) { + percentage = 100 - percentage; + } + + // Make sure the percent is within the bounds of the slider. + // 0% corresponds to the 'min' value of the slide + // 100% corresponds to the 'max' value of the slide + return Math.max(0, Math.min(100, percentage)); + }, + _validateInputValue: function _validateInputValue(val) { + if (typeof val === 'number') { + return val; + } else if (Array.isArray(val)) { + this._validateArray(val); + return val; + } else { + throw new Error(ErrorMsgs.formatInvalidInputErrorMsg(val)); + } + }, + _validateArray: function _validateArray(val) { + for (var i = 0; i < val.length; i++) { + var input = val[i]; + if (typeof input !== 'number') { + throw new Error(ErrorMsgs.formatInvalidInputErrorMsg(input)); + } + } + }, + _setDataVal: function _setDataVal(val) { + this.element.setAttribute('data-value', val); + this.element.setAttribute('value', val); + this.element.value = val; + }, + _trigger: function _trigger(evt, val) { + val = val || val === 0 ? val : undefined; + + var callbackFnArray = this.eventToCallbackMap[evt]; + if (callbackFnArray && callbackFnArray.length) { + for (var i = 0; i < callbackFnArray.length; i++) { + var callbackFn = callbackFnArray[i]; + callbackFn(val); + } + } + + /* If JQuery exists, trigger JQuery events */ + if ($) { + this._triggerJQueryEvent(evt, val); + } + }, + _triggerJQueryEvent: function _triggerJQueryEvent(evt, val) { + var eventData = { + type: evt, + value: val + }; + this.$element.trigger(eventData); + this.$sliderElem.trigger(eventData); + }, + _unbindJQueryEventHandlers: function _unbindJQueryEventHandlers() { + this.$element.off(); + this.$sliderElem.off(); + }, + _setText: function _setText(element, text) { + if (typeof element.innerText !== "undefined") { + element.innerText = text; + } else if (typeof element.textContent !== "undefined") { + element.textContent = text; + } + }, + _removeClass: function _removeClass(element, classString) { + var classes = classString.split(" "); + var newClasses = element.className; + + for (var i = 0; i < classes.length; i++) { + var classTag = classes[i]; + var regex = new RegExp("(?:\\s|^)" + classTag + "(?:\\s|$)"); + newClasses = newClasses.replace(regex, " "); + } + + element.className = newClasses.trim(); + }, + _addClass: function _addClass(element, classString) { + var classes = classString.split(" "); + var newClasses = element.className; + + for (var i = 0; i < classes.length; i++) { + var classTag = classes[i]; + var regex = new RegExp("(?:\\s|^)" + classTag + "(?:\\s|$)"); + var ifClassExists = regex.test(newClasses); + + if (!ifClassExists) { + newClasses += " " + classTag; + } + } + + element.className = newClasses.trim(); + }, + _offsetLeft: function _offsetLeft(obj) { + return obj.getBoundingClientRect().left; + }, + _offsetTop: function _offsetTop(obj) { + var offsetTop = obj.offsetTop; + while ((obj = obj.offsetParent) && !isNaN(obj.offsetTop)) { + offsetTop += obj.offsetTop; + } + return offsetTop; + }, + _offset: function _offset(obj) { + return { + left: this._offsetLeft(obj), + top: this._offsetTop(obj) + }; + }, + _css: function _css(elementRef, styleName, value) { + if ($) { + $.style(elementRef, styleName, value); + } else { + var style = styleName.replace(/^-ms-/, "ms-").replace(/-([\da-z])/gi, function (all, letter) { + return letter.toUpperCase(); + }); + elementRef.style[style] = value; + } + }, + _toValue: function _toValue(percentage) { + return this.options.scale.toValue.apply(this, [percentage]); + }, + _toPercentage: function _toPercentage(value) { + return this.options.scale.toPercentage.apply(this, [value]); + }, + _setTooltipPosition: function _setTooltipPosition() { + var tooltips = [this.tooltip, this.tooltip_min, this.tooltip_max]; + if (this.options.orientation === 'vertical') { + var tooltipPos = this.options.tooltip_position || 'right'; + var oppositeSide = tooltipPos === 'left' ? 'right' : 'left'; + tooltips.forEach((function (tooltip) { + this._addClass(tooltip, tooltipPos); + tooltip.style[oppositeSide] = '100%'; + }).bind(this)); + } else if (this.options.tooltip_position === 'bottom') { + tooltips.forEach((function (tooltip) { + this._addClass(tooltip, 'bottom'); + tooltip.style.top = 22 + 'px'; + }).bind(this)); + } else { + tooltips.forEach((function (tooltip) { + this._addClass(tooltip, 'top'); + tooltip.style.top = -this.tooltip.outerHeight - 14 + 'px'; + }).bind(this)); + } + } + }; + + /********************************* + Attach to global namespace + *********************************/ + if ($) { + var namespace = $.fn.slider ? 'bootstrapSlider' : 'slider'; + $.bridget(namespace, Slider); + } + })($); + + return Slider; +}); diff --git a/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/res/bootstrap-slider.min.js b/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/res/bootstrap-slider.min.js new file mode 100644 index 000000000..8d82d5990 --- /dev/null +++ b/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/res/bootstrap-slider.min.js @@ -0,0 +1,29 @@ +/*! ======================================================= + VERSION 6.0.4 +========================================================= */ +"use strict";function _typeof(a){return a&&"undefined"!=typeof Symbol&&a.constructor===Symbol?"symbol":typeof a}/*! ========================================================= + * bootstrap-slider.js + * + * Maintainers: + * Kyle Kemp + * - Twitter: @seiyria + * - Github: seiyria + * Rohit Kalkur + * - Twitter: @Rovolutionary + * - Github: rovolution + * + * ========================================================= + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================= */ +!function(a){if("function"==typeof define&&define.amd)define(["jquery"],a);else if("object"===("undefined"==typeof module?"undefined":_typeof(module))&&module.exports){var b;try{b=require("jquery")}catch(c){b=null}module.exports=a(b)}else window&&(window.Slider=a(window.jQuery))}(function(a){var b;return function(a){function b(){}function c(a){function c(b){b.prototype.option||(b.prototype.option=function(b){a.isPlainObject(b)&&(this.options=a.extend(!0,this.options,b))})}function e(b,c){a.fn[b]=function(e){if("string"==typeof e){for(var g=d.call(arguments,1),h=0,i=this.length;i>h;h++){var j=this[h],k=a.data(j,b);if(k)if(a.isFunction(k[e])&&"_"!==e.charAt(0)){var l=k[e].apply(k,g);if(void 0!==l&&l!==k)return l}else f("no such method '"+e+"' for "+b+" instance");else f("cannot call methods on "+b+" prior to initialization; attempted to call '"+e+"'")}return this}var m=this.map(function(){var d=a.data(this,b);return d?(d.option(e),d._init()):(d=new c(this,e),a.data(this,b,d)),a(this)});return!m||m.length>1?m:m[0]}}if(a){var f="undefined"==typeof console?b:function(a){console.error(a)};return a.bridget=function(a,b){c(b),e(a,b)},a.bridget}}var d=Array.prototype.slice;c(a)}(a),function(a){function c(b,c){function d(a,b){var c="data-slider-"+b.replace(/_/g,"-"),d=a.getAttribute(c);try{return JSON.parse(d)}catch(e){return d}}this._state={value:null,enabled:null,offset:null,size:null,percentage:null,inDrag:!1,over:!1},"string"==typeof b?this.element=document.querySelector(b):b instanceof HTMLElement&&(this.element=b),c=c?c:{};for(var f=Object.keys(this.defaultOptions),g=0;g0){for(g=0;g0)for(this.tickLabelContainer=document.createElement("div"),this.tickLabelContainer.className="slider-tick-label-container",g=0;g0&&(this.options.max=Math.max.apply(Math,this.options.ticks),this.options.min=Math.min.apply(Math,this.options.ticks)),Array.isArray(this.options.value)?(this.options.range=!0,this._state.value=this.options.value):this.options.range?this._state.value=[this.options.value,this.options.max]:this._state.value=this.options.value,this.trackLow=k||this.trackLow,this.trackSelection=j||this.trackSelection,this.trackHigh=l||this.trackHigh,"none"===this.options.selection&&(this._addClass(this.trackLow,"hide"),this._addClass(this.trackSelection,"hide"),this._addClass(this.trackHigh,"hide")),this.handle1=m||this.handle1,this.handle2=n||this.handle2,p===!0)for(this._removeClass(this.handle1,"round triangle"),this._removeClass(this.handle2,"round triangle hide"),g=0;g0){for(var d,e,f,g=0,h=1;hthis.options.max?this.options.max:k},toPercentage:function(a){if(this.options.max===this.options.min)return 0;if(this.options.ticks_positions.length>0){for(var b,c,d,e=0,f=0;f0?this.options.ticks[f-1]:0,d=f>0?this.options.ticks_positions[f-1]:0,c=this.options.ticks[f],e=this.options.ticks_positions[f];break}if(f>0){var g=(a-b)/(c-b);return d+g*(e-d)}}return 100*(a-this.options.min)/(this.options.max-this.options.min)}},logarithmic:{toValue:function(a){var b=0===this.options.min?0:Math.log(this.options.min),c=Math.log(this.options.max),d=Math.exp(b+(c-b)*a/100);return d=this.options.min+Math.round((d-this.options.min)/this.options.step)*this.options.step,dthis.options.max?this.options.max:d},toPercentage:function(a){if(this.options.max===this.options.min)return 0;var b=Math.log(this.options.max),c=0===this.options.min?0:Math.log(this.options.min),d=0===a?0:Math.log(a);return 100*(d-c)/(b-c)}}};if(b=function(a,b){return c.call(this,a,b),this},b.prototype={_init:function(){},constructor:b,defaultOptions:{id:"",min:0,max:10,step:1,precision:0,orientation:"horizontal",value:5,range:!1,selection:"before",tooltip:"show",tooltip_split:!1,handle:"round",reversed:!1,enabled:!0,formatter:function(a){return Array.isArray(a)?a[0]+" : "+a[1]:a},natural_arrow_keys:!1,ticks:[],ticks_positions:[],ticks_labels:[],ticks_snap_bounds:0,scale:"linear",focus:!1,tooltip_position:null,labelledby:null},getElement:function(){return this.sliderElem},getValue:function(){return this.options.range?this._state.value:this._state.value[0]},setValue:function(a,b,c){a||(a=0);var d=this.getValue();this._state.value=this._validateInputValue(a);var e=this._applyPrecision.bind(this);this.options.range?(this._state.value[0]=e(this._state.value[0]),this._state.value[1]=e(this._state.value[1]),this._state.value[0]=Math.max(this.options.min,Math.min(this.options.max,this._state.value[0])),this._state.value[1]=Math.max(this.options.min,Math.min(this.options.max,this._state.value[1]))):(this._state.value=e(this._state.value),this._state.value=[Math.max(this.options.min,Math.min(this.options.max,this._state.value))],this._addClass(this.handle2,"hide"),"after"===this.options.selection?this._state.value[1]=this.options.max:this._state.value[1]=this.options.min),this.options.max>this.options.min?this._state.percentage=[this._toPercentage(this._state.value[0]),this._toPercentage(this._state.value[1]),100*this.options.step/(this.options.max-this.options.min)]:this._state.percentage=[0,0,100],this._layout();var f=this.options.range?this._state.value:this._state.value[0];return b===!0&&this._trigger("slide",f),d!==f&&c===!0&&this._trigger("change",{oldValue:d,newValue:f}),this._setDataVal(f),this},destroy:function(){this._removeSliderEventHandlers(),this.sliderElem.parentNode.removeChild(this.sliderElem),this.element.style.display="",this._cleanUpEventCallbacksMap(),this.element.removeAttribute("data"),a&&(this._unbindJQueryEventHandlers(),this.$element.removeData("slider"))},disable:function(){return this._state.enabled=!1,this.handle1.removeAttribute("tabindex"),this.handle2.removeAttribute("tabindex"),this._addClass(this.sliderElem,"slider-disabled"),this._trigger("slideDisabled"),this},enable:function(){return this._state.enabled=!0,this.handle1.setAttribute("tabindex",0),this.handle2.setAttribute("tabindex",0),this._removeClass(this.sliderElem,"slider-disabled"),this._trigger("slideEnabled"),this},toggle:function(){return this._state.enabled?this.disable():this.enable(),this},isEnabled:function(){return this._state.enabled},on:function(a,b){return this._bindNonQueryEventHandler(a,b),this},off:function(b,c){a?(this.$element.off(b,c),this.$sliderElem.off(b,c)):this._unbindNonQueryEventHandler(b,c)},getAttribute:function(a){return a?this.options[a]:this.options},setAttribute:function(a,b){return this.options[a]=b,this},refresh:function(){return this._removeSliderEventHandlers(),c.call(this,this.element,this.options),a&&a.data(this.element,"slider",this),this},relayout:function(){return this._layout(),this},_removeSliderEventHandlers:function(){this.handle1.removeEventListener("keydown",this.handle1Keydown,!1),this.handle2.removeEventListener("keydown",this.handle2Keydown,!1),this.showTooltip&&(this.handle1.removeEventListener("focus",this.showTooltip,!1),this.handle2.removeEventListener("focus",this.showTooltip,!1)),this.hideTooltip&&(this.handle1.removeEventListener("blur",this.hideTooltip,!1),this.handle2.removeEventListener("blur",this.hideTooltip,!1)),this.showTooltip&&this.sliderElem.removeEventListener("mouseenter",this.showTooltip,!1),this.hideTooltip&&this.sliderElem.removeEventListener("mouseleave",this.hideTooltip,!1),this.sliderElem.removeEventListener("touchstart",this.mousedown,!1),this.sliderElem.removeEventListener("mousedown",this.mousedown,!1),window.removeEventListener("resize",this.resize,!1)},_bindNonQueryEventHandler:function(a,b){void 0===this.eventToCallbackMap[a]&&(this.eventToCallbackMap[a]=[]),this.eventToCallbackMap[a].push(b)},_unbindNonQueryEventHandler:function(a,b){var c=this.eventToCallbackMap[a];if(void 0!==c)for(var d=0;d0){var b="vertical"===this.options.orientation?"height":"width",c="vertical"===this.options.orientation?"marginTop":"marginLeft",d=this._state.size/(this.options.ticks.length-1);if(this.tickLabelContainer){var e=0;if(0===this.options.ticks_positions.length)"vertical"!==this.options.orientation&&(this.tickLabelContainer.style[c]=-d/2+"px"),e=this.tickLabelContainer.offsetHeight;else for(f=0;fe&&(e=this.tickLabelContainer.childNodes[f].offsetHeight);"horizontal"===this.options.orientation&&(this.sliderElem.style.marginBottom=e+"px")}for(var f=0;f=a[0]&&g<=a[1]&&this._addClass(this.ticks[f],"in-selection"):"after"===this.options.selection&&g>=a[0]?this._addClass(this.ticks[f],"in-selection"):"before"===this.options.selection&&g<=a[0]&&this._addClass(this.ticks[f],"in-selection"),this.tickLabels[f]&&(this.tickLabels[f].style[b]=d+"px","vertical"!==this.options.orientation&&void 0!==this.options.ticks_positions[f]?(this.tickLabels[f].style.position="absolute",this.tickLabels[f].style[this.stylePos]=g+"%",this.tickLabels[f].style[c]=-d/2+"px"):"vertical"===this.options.orientation&&(this.tickLabels[f].style.marginLeft=this.sliderElem.offsetWidth+"px",this.tickLabelContainer.style.marginTop=this.sliderElem.offsetWidth/2*-1+"px"))}}var h;if(this.options.range){h=this.options.formatter(this._state.value),this._setText(this.tooltipInner,h),this.tooltip.style[this.stylePos]=(a[1]+a[0])/2+"%","vertical"===this.options.orientation?this._css(this.tooltip,"margin-top",-this.tooltip.offsetHeight/2+"px"):this._css(this.tooltip,"margin-left",-this.tooltip.offsetWidth/2+"px"),"vertical"===this.options.orientation?this._css(this.tooltip,"margin-top",-this.tooltip.offsetHeight/2+"px"):this._css(this.tooltip,"margin-left",-this.tooltip.offsetWidth/2+"px");var i=this.options.formatter(this._state.value[0]);this._setText(this.tooltipInner_min,i);var j=this.options.formatter(this._state.value[1]);this._setText(this.tooltipInner_max,j),this.tooltip_min.style[this.stylePos]=a[0]+"%","vertical"===this.options.orientation?this._css(this.tooltip_min,"margin-top",-this.tooltip_min.offsetHeight/2+"px"):this._css(this.tooltip_min,"margin-left",-this.tooltip_min.offsetWidth/2+"px"),this.tooltip_max.style[this.stylePos]=a[1]+"%","vertical"===this.options.orientation?this._css(this.tooltip_max,"margin-top",-this.tooltip_max.offsetHeight/2+"px"):this._css(this.tooltip_max,"margin-left",-this.tooltip_max.offsetWidth/2+"px")}else h=this.options.formatter(this._state.value[0]),this._setText(this.tooltipInner,h),this.tooltip.style[this.stylePos]=a[0]+"%","vertical"===this.options.orientation?this._css(this.tooltip,"margin-top",-this.tooltip.offsetHeight/2+"px"):this._css(this.tooltip,"margin-left",-this.tooltip.offsetWidth/2+"px");if("vertical"===this.options.orientation)this.trackLow.style.top="0",this.trackLow.style.height=Math.min(a[0],a[1])+"%",this.trackSelection.style.top=Math.min(a[0],a[1])+"%",this.trackSelection.style.height=Math.abs(a[0]-a[1])+"%",this.trackHigh.style.bottom="0",this.trackHigh.style.height=100-Math.min(a[0],a[1])-Math.abs(a[0]-a[1])+"%";else{this.trackLow.style.left="0",this.trackLow.style.width=Math.min(a[0],a[1])+"%",this.trackSelection.style.left=Math.min(a[0],a[1])+"%",this.trackSelection.style.width=Math.abs(a[0]-a[1])+"%",this.trackHigh.style.right="0",this.trackHigh.style.width=100-Math.min(a[0],a[1])-Math.abs(a[0]-a[1])+"%";var k=this.tooltip_min.getBoundingClientRect(),l=this.tooltip_max.getBoundingClientRect();k.right>l.left?(this._removeClass(this.tooltip_max,"top"),this._addClass(this.tooltip_max,"bottom"),this.tooltip_max.style.top="18px"):(this._removeClass(this.tooltip_max,"bottom"),this._addClass(this.tooltip_max,"top"),this.tooltip_max.style.top=this.tooltip_min.style.top)}},_resize:function(a){this._state.offset=this._offset(this.sliderElem),this._state.size=this.sliderElem[this.sizePos],this._layout()},_removeProperty:function(a,b){a.style.removeProperty?a.style.removeProperty(b):a.style.removeAttribute(b)},_mousedown:function(a){if(!this._state.enabled)return!1;this._state.offset=this._offset(this.sliderElem),this._state.size=this.sliderElem[this.sizePos];var b=this._getPercentage(a);if(this.options.range){var c=Math.abs(this._state.percentage[0]-b),d=Math.abs(this._state.percentage[1]-b);this._state.dragged=d>c?0:1}else this._state.dragged=0;this._state.percentage[this._state.dragged]=b,this._layout(),this.touchCapable&&(document.removeEventListener("touchmove",this.mousemove,!1),document.removeEventListener("touchend",this.mouseup,!1)),this.mousemove&&document.removeEventListener("mousemove",this.mousemove,!1),this.mouseup&&document.removeEventListener("mouseup",this.mouseup,!1),this.mousemove=this._mousemove.bind(this),this.mouseup=this._mouseup.bind(this),this.touchCapable&&(document.addEventListener("touchmove",this.mousemove,!1),document.addEventListener("touchend",this.mouseup,!1)),document.addEventListener("mousemove",this.mousemove,!1),document.addEventListener("mouseup",this.mouseup,!1),this._state.inDrag=!0;var e=this._calculateValue();return this._trigger("slideStart",e),this._setDataVal(e),this.setValue(e,!1,!0),this._pauseEvent(a),this.options.focus&&this._triggerFocusOnHandle(this._state.dragged),!0},_triggerFocusOnHandle:function(a){0===a&&this.handle1.focus(),1===a&&this.handle2.focus()},_keydown:function(a,b){if(!this._state.enabled)return!1;var c;switch(b.keyCode){case 37:case 40:c=-1;break;case 39:case 38:c=1}if(c){if(this.options.natural_arrow_keys){var d="vertical"===this.options.orientation&&!this.options.reversed,e="horizontal"===this.options.orientation&&this.options.reversed;(d||e)&&(c=-c)}var f=this._state.value[a]+c*this.options.step;return this.options.range&&(f=[a?this._state.value[0]:f,a?f:this._state.value[1]]),this._trigger("slideStart",f),this._setDataVal(f),this.setValue(f,!0,!0),this._setDataVal(f),this._trigger("slideStop",f),this._layout(),this._pauseEvent(b),!1}},_pauseEvent:function(a){a.stopPropagation&&a.stopPropagation(),a.preventDefault&&a.preventDefault(),a.cancelBubble=!0,a.returnValue=!1},_mousemove:function(a){if(!this._state.enabled)return!1;var b=this._getPercentage(a);this._adjustPercentageForRangeSliders(b),this._state.percentage[this._state.dragged]=b,this._layout();var c=this._calculateValue(!0);return this.setValue(c,!0,!0),!1},_adjustPercentageForRangeSliders:function(a){if(this.options.range){var b=this._getNumDigitsAfterDecimalPlace(a);b=b?b-1:0;var c=this._applyToFixedAndParseFloat(a,b);0===this._state.dragged&&this._applyToFixedAndParseFloat(this._state.percentage[1],b)c&&(this._state.percentage[1]=this._state.percentage[0],this._state.dragged=0)}},_mouseup:function(){if(!this._state.enabled)return!1;this.touchCapable&&(document.removeEventListener("touchmove",this.mousemove,!1),document.removeEventListener("touchend",this.mouseup,!1)),document.removeEventListener("mousemove",this.mousemove,!1),document.removeEventListener("mouseup",this.mouseup,!1),this._state.inDrag=!1,this._state.over===!1&&this._hideTooltip();var a=this._calculateValue(!0);return this._layout(),this._setDataVal(a),this._trigger("slideStop",a),!1},_calculateValue:function(a){var b;if(this.options.range?(b=[this.options.min,this.options.max],0!==this._state.percentage[0]&&(b[0]=this._toValue(this._state.percentage[0]),b[0]=this._applyPrecision(b[0])),100!==this._state.percentage[1]&&(b[1]=this._toValue(this._state.percentage[1]),b[1]=this._applyPrecision(b[1]))):(b=this._toValue(this._state.percentage[0]),b=parseFloat(b),b=this._applyPrecision(b)),a){for(var c=[b,1/0],d=0;d=0 ? value.substring(1, value.length()-1): value; + String[] values = toParser.split(","); + return new DoubleRangeValue(Double.parseDouble(values[0]),Double.parseDouble(values[1])); + } + + @Override + public Class getNumberType() { + return Double.class; + } + + @Override + public String toString() { + return "["+min+","+max+"]"; + } + + public double getMin() { + return min; + } + + public void setMin(double min) { + this.min = min; + } + + public double getMax() { + return max; + } + + public void setMax(double max) { + this.max = max; + } + + +} diff --git a/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/util/DoubleValue.java b/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/util/DoubleValue.java new file mode 100644 index 000000000..44bd97ccd --- /dev/null +++ b/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/util/DoubleValue.java @@ -0,0 +1,41 @@ +package de.agilecoders.wicket.extensions.slider.util; + +import de.agilecoders.wicket.extensions.slider.ISliderValue; + +/** + * DoubleValue + */ +public class DoubleValue implements ISliderValue, INumericValue { + + private double value; + + public DoubleValue() { + } + + public DoubleValue(double value) { + this.value = value; + } + + @Override + public ISliderValue fromString(String value) { + return new DoubleValue(Double.parseDouble(value)); + } + + @Override + public Class getNumberType() { + return Double.class; + } + + @Override + public String toString() { + return Double.toString(value); + } + + public Double getValue() { + return value; + } + + public void setValue(Double value) { + this.value = value; + } +} diff --git a/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/util/INumericValue.java b/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/util/INumericValue.java new file mode 100644 index 000000000..1497f1d11 --- /dev/null +++ b/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/util/INumericValue.java @@ -0,0 +1,13 @@ +package de.agilecoders.wicket.extensions.slider.util; + +import de.agilecoders.wicket.extensions.slider.ISliderValue; + +/** + *INumericValue: a numeric ISlider value + */ +public interface INumericValue extends ISliderValue { + + public T getValue(); + + public void setValue(T value); +} diff --git a/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/util/IntegerRangeValue.java b/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/util/IntegerRangeValue.java new file mode 100644 index 000000000..ac2698f6e --- /dev/null +++ b/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/util/IntegerRangeValue.java @@ -0,0 +1,73 @@ +package de.agilecoders.wicket.extensions.slider.util; + +import de.agilecoders.wicket.extensions.slider.ISliderValue; + +/** + * IntegerRangeValue + */ +public class IntegerRangeValue implements ISliderValue { + + private int min; + private int max; + + public IntegerRangeValue() { + } + + public IntegerRangeValue(int min, int max) { + this.min = min; + this.max = max; + } + + @Override + public ISliderValue fromString(String value) { + String toParser = value.indexOf('[')>=0 ? value.substring(1, value.length()-1): value; + String[] values = toParser.split(","); + return new IntegerRangeValue(Integer.parseInt(values[0]),Integer.parseInt(values[1])); + } + + @Override + public Class getNumberType() { + return Integer.class; + } + + @Override + public String toString() { + return "["+min+","+max+"]"; + } + + public int getMin() { + return min; + } + + public void setMin(int min) { + this.min = min; + } + + public int getMax() { + return max; + } + + public void setMax(int max) { + this.max = max; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof IntegerRangeValue)) return false; + + IntegerRangeValue that = (IntegerRangeValue) o; + + if (max != that.max) return false; + if (min != that.min) return false; + + return true; + } + + @Override + public int hashCode() { + int result = (int) (min ^ (min >>> 32)); + result = 31 * result + (int) (max ^ (max >>> 32)); + return result; + } +} diff --git a/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/util/IntegerValue.java b/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/util/IntegerValue.java new file mode 100644 index 000000000..bf17abd78 --- /dev/null +++ b/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/util/IntegerValue.java @@ -0,0 +1,58 @@ +package de.agilecoders.wicket.extensions.slider.util; + +import de.agilecoders.wicket.extensions.slider.ISliderValue; + +/** + * IntegerValue + */ +public class IntegerValue implements ISliderValue, INumericValue { + + private int value; + + public IntegerValue() { + } + + public IntegerValue(int value) { + this.value = value; + } + + @Override + public ISliderValue fromString(String value) { + return new IntegerValue(Integer.parseInt(value)); + } + + @Override + public String toString() { + return Double.toString(value); + } + + public Integer getValue() { + return value; + } + + public void setValue(Integer value) { + this.value = value; + } + + @Override + public Class getNumberType() { + return Integer.class; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof IntegerValue)) return false; + + IntegerValue longValue = (IntegerValue) o; + + if (value != longValue.value) return false; + + return true; + } + + @Override + public int hashCode() { + return (int) (value ^ (value >>> 32)); + } +} diff --git a/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/util/LongRangeValue.java b/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/util/LongRangeValue.java new file mode 100644 index 000000000..ab9ff3996 --- /dev/null +++ b/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/util/LongRangeValue.java @@ -0,0 +1,73 @@ +package de.agilecoders.wicket.extensions.slider.util; + +import de.agilecoders.wicket.extensions.slider.ISliderValue; + +/** + * LongRangeValue + */ +public class LongRangeValue implements ISliderValue { + + private long min; + private long max; + + public LongRangeValue() { + } + + public LongRangeValue(long min, long max) { + this.min = min; + this.max = max; + } + + @Override + public ISliderValue fromString(String value) { + String toParser = value.indexOf('[')>=0 ? value.substring(1, value.length()-1): value; + String[] values = toParser.split(","); + return new LongRangeValue(Long.parseLong(values[0]),Long.parseLong(values[1])); + } + + @Override + public Class getNumberType() { + return Long.class; + } + + @Override + public String toString() { + return "["+min+","+max+"]"; + } + + public long getMin() { + return min; + } + + public void setMin(long min) { + this.min = min; + } + + public long getMax() { + return max; + } + + public void setMax(long max) { + this.max = max; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof LongRangeValue)) return false; + + LongRangeValue that = (LongRangeValue) o; + + if (max != that.max) return false; + if (min != that.min) return false; + + return true; + } + + @Override + public int hashCode() { + int result = (int) (min ^ (min >>> 32)); + result = 31 * result + (int) (max ^ (max >>> 32)); + return result; + } +} diff --git a/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/util/LongValue.java b/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/util/LongValue.java new file mode 100644 index 000000000..30eb7b4a9 --- /dev/null +++ b/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/util/LongValue.java @@ -0,0 +1,58 @@ +package de.agilecoders.wicket.extensions.slider.util; + +import de.agilecoders.wicket.extensions.slider.ISliderValue; + +/** + * LongValue + */ +public class LongValue implements ISliderValue, INumericValue { + + private Long value; + + public LongValue() { + } + + public LongValue(long value) { + this.value = value; + } + + @Override + public ISliderValue fromString(String value) { + return new LongValue(Long.parseLong(value)); + } + + @Override + public String toString() { + return Double.toString(value); + } + + public Long getValue() { + return value; + } + + public void setValue(Long value) { + this.value = value; + } + + @Override + public Class getNumberType() { + return Long.class; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof LongValue)) return false; + + LongValue longValue = (LongValue) o; + + if (!value.equals(longValue.value)) return false; + + return true; + } + + @Override + public int hashCode() { + return (int) (value ^ (value >>> 32)); + } +} diff --git a/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/util/NumericModel.java b/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/util/NumericModel.java new file mode 100644 index 000000000..622685550 --- /dev/null +++ b/bootstrap-extensions/src/main/java/de/agilecoders/wicket/extensions/slider/util/NumericModel.java @@ -0,0 +1,46 @@ +package de.agilecoders.wicket.extensions.slider.util; + +import org.apache.wicket.model.IModel; + +/** + * NumericModel: wrapper model around a numeric model (it bridges with internal slider representation of data). + */ +public class NumericModel implements IModel> { + + private IModel model; + + public NumericModel(IModel model) { + this.model = model; + } + + @Override + public INumericValue getObject() { + INumericValue value = (INumericValue)getValue(model.getObject().getClass()); + value.setValue(model.getObject()); + return value; + } + + @Override + public void setObject(INumericValue object) { + model.setObject(object.getValue()); + + } + + @Override + public void detach() { + model.detach(); + } + + public static INumericValue getValue(Class typeClass) { + if(Double.class.isAssignableFrom(typeClass)) { + return new DoubleValue(); + } + if(Long.class.isAssignableFrom(typeClass)) { + return new LongValue(); + } + if(Integer.class.isAssignableFrom(typeClass)) { + return new IntegerValue(); + } + return new DoubleValue(); + } +} diff --git a/bootstrap-samples/src/main/java/de/agilecoders/wicket/samples/pages/BasePage.java b/bootstrap-samples/src/main/java/de/agilecoders/wicket/samples/pages/BasePage.java index 01a6aceb5..05b999713 100644 --- a/bootstrap-samples/src/main/java/de/agilecoders/wicket/samples/pages/BasePage.java +++ b/bootstrap-samples/src/main/java/de/agilecoders/wicket/samples/pages/BasePage.java @@ -161,6 +161,7 @@ protected List newSubMenuButtons(String buttonMarkupId) { subMenu.add(new MenuBookmarkablePageLink(Javascript.class, Model.of("Javascript")).setIconType(GlyphIconType.refresh)); subMenu.add(new MenuBookmarkablePageLink(DatePickerPage.class, Model.of("DatePicker")).setIconType(GlyphIconType.time)); + subMenu.add(new MenuBookmarkablePageLink(SliderPage.class, Model.of("Slider")).setIconType(GlyphIconType.screenshot)); subMenu.add(new MenuBookmarkablePageLink(DatetimePickerPage.class, Model.of("DateTimePicker")).setIconType(GlyphIconType.time)); subMenu.add(new MenuBookmarkablePageLink(SelectPage.class, Model.of("SelectPicker")).setIconType(GlyphIconType.search)); subMenu.add(new MenuBookmarkablePageLink(IssuesPage.class, Model.of("Github Issues")).setIconType(GlyphIconType.book)); diff --git a/bootstrap-samples/src/main/java/de/agilecoders/wicket/samples/pages/ExtensionsPage.java b/bootstrap-samples/src/main/java/de/agilecoders/wicket/samples/pages/ExtensionsPage.java index 2e2c25112..1e4edfa57 100644 --- a/bootstrap-samples/src/main/java/de/agilecoders/wicket/samples/pages/ExtensionsPage.java +++ b/bootstrap-samples/src/main/java/de/agilecoders/wicket/samples/pages/ExtensionsPage.java @@ -112,6 +112,8 @@ public ExtensionsPage(PageParameters parameters) { final List buttons = Lists. newArrayList( new MenuBookmarkablePageLink(DatePickerPage.class, Model.of("DatePicker")) .setIconType(GlyphIconType.time), + new MenuBookmarkablePageLink(SliderPage.class, Model.of("Slider")) + .setIconType(GlyphIconType.signal), new MenuBookmarkablePageLink(IssuesPage.class, Model.of("Github Issues")) .setIconType(GlyphIconType.book), new MenuBookmarkablePageLink(ExtensionsPage.class, Model.of("Extensions")).setIconType(GlyphIconType.qrcode)); @@ -155,7 +157,10 @@ public void renderHead(IHeaderResponse response) { protected List newSubMenuButtons(String buttonMarkupId) { return Lists. newArrayList( new MenuBookmarkablePageLink(DatePickerPage.class, Model.of("DatePicker")) - .setIconType(GlyphIconType.time), new MenuBookmarkablePageLink(IssuesPage.class, + .setIconType(GlyphIconType.time), + new MenuBookmarkablePageLink(SliderPage.class, Model.of("Slider")) + .setIconType(GlyphIconType.screenshot), + new MenuBookmarkablePageLink(IssuesPage.class, Model.of("Github Issues")).setIconType(GlyphIconType.book), new MenuBookmarkablePageLink(ExtensionsPage.class, Model.of("Extensions")) .setIconType(GlyphIconType.qrcode)); diff --git a/bootstrap-samples/src/main/java/de/agilecoders/wicket/samples/pages/SliderPage.html b/bootstrap-samples/src/main/java/de/agilecoders/wicket/samples/pages/SliderPage.html new file mode 100644 index 000000000..a1802498e --- /dev/null +++ b/bootstrap-samples/src/main/java/de/agilecoders/wicket/samples/pages/SliderPage.html @@ -0,0 +1,151 @@ + + + + + ComponentsPage + + + +
+
+

Slider

+ +

A wrapper of http://seiyria.com/bootstrap-slider/

+
+
+ + +
+ +
+ +
+ +
+ + +

Example

+ +

DOC.

+ +
+
+
+

+                            

+                        
+
+ + +

Example

+ +

DOC.

+ +
+
+
+

+                            

+                        
+ +
+ + +

Example

+ +

DOC.

+ +
+
+
+

+                            

+                        
+ +
+ + +

Example

+ +
+
+
+ +
+ +
+ + +

Example

+ +
+
+
+
+ +
+ +
+ + +

Example

+ +
+
+
+ +
+ +
+ + +

Example

+ +
+
+
+
+
+ +
+ + +

Example

+ +
+
+
+ +
+
+
+
+
+ + diff --git a/bootstrap-samples/src/main/java/de/agilecoders/wicket/samples/pages/SliderPage.java b/bootstrap-samples/src/main/java/de/agilecoders/wicket/samples/pages/SliderPage.java new file mode 100644 index 000000000..7f9fa48ed --- /dev/null +++ b/bootstrap-samples/src/main/java/de/agilecoders/wicket/samples/pages/SliderPage.java @@ -0,0 +1,142 @@ +package de.agilecoders.wicket.samples.pages; + +import de.agilecoders.wicket.core.markup.html.bootstrap.block.Code; +import de.agilecoders.wicket.extensions.slider.AjaxBootstrapSlider; +import de.agilecoders.wicket.extensions.slider.AjaxNumericBootstrapSlider; +import de.agilecoders.wicket.extensions.slider.BootstrapSlider; +import de.agilecoders.wicket.extensions.slider.NumericBootstrapSlider; +import de.agilecoders.wicket.extensions.slider.util.INumericValue; +import de.agilecoders.wicket.extensions.slider.util.LongRangeValue; +import de.agilecoders.wicket.extensions.slider.util.LongValue; +import org.apache.wicket.Component; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.form.Form; +import org.apache.wicket.model.AbstractReadOnlyModel; +import org.apache.wicket.model.Model; +import org.apache.wicket.request.mapper.parameter.PageParameters; +import org.wicketstuff.annotation.mount.MountPath; + +/** + * The {@code BaseCssPage} + * + * @author Ernesto Reinaldo Barreiro + * @version 1.0 + */ +@MountPath(value = "/slider") +public class SliderPage extends BasePage { + + private Model longSliderModel = Model.of(100L); + + private Model longRangeModel = Model.of( new LongRangeValue(10, 20)); + + private Model disabledRangeModel = Model.of( new LongRangeValue(10, 20)); + + private Model tooltipFormRangeModel = Model.of( new LongRangeValue(10, 20)); + + private Model ajaxSliderModel = Model.of(100L); + + private Model verticalRangeModel = Model.of( new LongRangeValue(10, 20)); + + private Model ajaxFormRangeModel = Model.of( new LongRangeValue(10, 20)); + + private Model reversedSliderModel = Model.of(100L); + + /** + * Construct. + * + * @param parameters the current page parameters. + */ + public SliderPage(PageParameters parameters) { + super(parameters); + + Form sliderForm = new Form("sliderForm"); + add(sliderForm); + sliderForm.add(newSlider("slider", longSliderModel, 0L, 100000L, 10L)); + add(new Code("default-html-code", Model.of("//HTML\n
")).setShowLineNumbers(true), + new Code("default-java-code", Model.of("//JAVA\nadd(new NumericBootstrapSlider(\"slider\")).setMin(min).setMax(max).setStep(step);")).setShowLineNumbers(true)); + + Form rangeForm = new Form("rangeForm"); + add(rangeForm); + rangeForm.add(newRangeSlider("rangeSlider", longRangeModel, 0L, 100L, 5L).setHandle(BootstrapSlider.HandleType.triangle)); + add(new Code("range-html-code", Model.of("//HTML\n
")).setShowLineNumbers(true), + new Code("range-java-code", Model.of("//JAVA\nadd(new BootstrapSlider(\"rangeSlider\")).setMin(min).setMax(max).setStep(step);")).setShowLineNumbers(true)); + + Form disabledForm = new Form("disabledForm"); + add(disabledForm); + disabledForm.add(newRangeSlider("disabledSlider", disabledRangeModel, 0L, 100L, 5L).setEnabled(false)); + add(new Code("disabled-html-code", Model.of("//HTML\n
")).setShowLineNumbers(true), + new Code("disabled-java-code", Model.of("//JAVA\nadd(new BootstrapSlider(\"disabledSlider\")).setMin(min).setMax(max).setStep(step);")).setShowLineNumbers(true)); + + Form tooltipForm = new Form("tooltipForm"); + add(tooltipForm); + tooltipForm.add(newRangeSlider("tooltipSlider", tooltipFormRangeModel, 0L, 100L, 5L).setTooltip(BootstrapSlider.TooltipType.always).setFormatter("function(value){ return 'The values is:' + value; }")); + + final Label feedback = new Label("feedback", new AbstractReadOnlyModel() { + @Override + public String getObject() { + return ajaxSliderModel.getObject().toString(); + } + }); + feedback.setOutputMarkupId(true); + add(feedback); + Form ajaxForm = new Form("ajaxForm"); + add(ajaxForm); + ajaxForm.add(newAjaxSlider("ajaxSlider", ajaxSliderModel, 0L, 1000L, 10L, AjaxBootstrapSlider.SliderEvent.slideStop, new AjaxBootstrapSlider.EventHandler() { + @Override + public void onAjaxEvent(AjaxRequestTarget target, LongValue newValue) { + target.add(feedback); + } + })); + + Form verticalForm = new Form("verticalForm"); + add(verticalForm); + verticalForm.add(newRangeSlider("verticalSlider", verticalRangeModel, 0L, 100L, 5L).setOrientation(BootstrapSlider.Orientation.vertical)); + + final Label feedback1 = new Label("feedback1", new AbstractReadOnlyModel() { + @Override + public String getObject() { + return ajaxFormRangeModel.getObject().toString(); + } + }); + feedback1.setOutputMarkupId(true); + add(feedback1); + Form ajaxRangeForm = new Form("ajaxRangeForm"); + add(ajaxRangeForm); + ajaxRangeForm.add(newAjaxRangeSlider("ajaxRangeSlider", ajaxFormRangeModel, 0L, 100L, 5L).addHandler(AjaxBootstrapSlider.SliderEvent.slideStop, new AjaxBootstrapSlider.EventHandler() { + @Override + public void onAjaxEvent(AjaxRequestTarget target, LongRangeValue newValue) { + target.add(feedback1); + } + }).setTooltipSplit(true)); + + Form reversedForm = new Form("reversedForm"); + add(reversedForm); + reversedForm.add(newSlider("reversedSlider", reversedSliderModel, 0L, 100000L, 10L).setReversed(true)); + } + + private static Component newAjaxSlider(String markupId, Model longSliderModel, T min, T max, T step, AjaxBootstrapSlider.SliderEvent event, AjaxBootstrapSlider.EventHandler handler) { + return new AjaxNumericBootstrapSlider(markupId, longSliderModel).addHandler(event, ( AjaxBootstrapSlider.EventHandler>)handler).setMin(min).setMax(max).setStep(step); + } + + private NumericBootstrapSlider newSlider(String markupId, Model longSliderModel, Long min, Long max, Long step) { + NumericBootstrapSlider slider= new NumericBootstrapSlider(markupId, longSliderModel); + slider.setMin(min).setMax(max).setStep(step); + return slider; + } + + private BootstrapSlider newRangeSlider(String markupId, Model longSliderModel, Long min, Long max, Long step) { + return new BootstrapSlider(markupId, longSliderModel, LongRangeValue.class).setMin(min).setMax(max).setStep(step); + } + + private AjaxBootstrapSlider newAjaxRangeSlider(String markupId, Model longSliderModel, Long min, Long max, Long step) { + AjaxBootstrapSlider slider = new AjaxBootstrapSlider(markupId, longSliderModel, LongRangeValue.class); + slider.setMin(min).setMax(max).setStep(step); + return slider; + } + + @Override + protected boolean hasNavigation() { + return true; + } +}