/* * This file is part of Toolkit. * * Toolkit is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * Toolkit is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General * Public License along with this program; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA */ "use strict"; (function(w, TK){ /* Abstract toggle logic */ function reset_delay_to () { window.clearTimeout(this.__delayed_to); this.__delayed_to = -1; this.remove_class("toolkit-delayed"); } function toggle(O) { if (this.userset("state", !O.state) === false) return; this.fire_event("toggled", O.state); } function press_start() { var O = this.options; this.__press_start_time = Date.now(); if (O.delay && this.__delayed_to < 0) { this.__delayed_to = window.setTimeout((function (t) { return function () { press_start.call(t); } })(this), O.delay); this.add_class("toolkit-delayed"); return; } this.remove_class("toolkit-delayed"); if (O.delay && this.__delayed_to >= 0) { toggle.call(this, O); } if (O.press) toggle.call(this, O); } function press_end() { var O = this.options; if (O.delay && this.__delayed_to >= 0) { reset_delay_to.call(this); return; } var t = Date.now() - this.__press_start_time; if ((O.toggle && (!O.press || t > O.press)) || (!O.toggle && O.press)) { toggle.call(this, O); } } function press_cancel() { var O = this.options; if (O.delay && this.__delayed_to >= 0) { reset_delay_to.call(this); return; } /* this is definitely not a click, its a cancel by leaving the * button with mouse or finger while pressing */ if (O.press) toggle.call(this, O); } /* MOUSE handling */ function mouseup(e) { this.remove_event("mouseup", mouseup); this.remove_event("mouseleave", mouseleave); press_end.call(this); } function mouseleave(e) { this.remove_event("mouseup", mouseup); this.remove_event("mouseleave", mouseleave); press_cancel.call(this); } function mousedown(e) { /* only left click please */ if (e.button) return true; press_start.call(this); this.add_event("mouseup", mouseup); this.add_event("mouseleave", mouseleave); } /* TOUCH handling */ function is_current_touch(ev) { var id = this.__touch_id; var i; for (i = 0; i < ev.changedTouches.length; i++) { if (ev.changedTouches[i].identifier === id) { return true; } } return false; } function touchend(e) { if (!is_current_touch.call(this, e)) return; this.__touch_id = false; e.preventDefault(); press_end.call(this); this.remove_event("touchend", touchend); this.remove_event("touchcancel", touchleave); this.remove_event("touchleave", touchleave); } function touchleave(e) { if (!is_current_touch.call(this, e)) return; this.__touch_id = false; e.preventDefault(); press_cancel.call(this); this.remove_event("touchend", touchend); this.remove_event("touchcancel", touchleave); this.remove_event("touchleave", touchleave); } function touchstart(e) { if (this.__touch_id !== false) return; this.__touch_id = e.targetTouches[0].identifier; press_start.call(this); this.add_event("touchend", touchend); this.add_event("touchcancel", touchleave); this.add_event("touchleave", touchleave); e.preventDefault(); e.stopPropagation(); return false; } function contextmenu(e) { e.preventDefault(); e.stopPropagation(); return false; } var class_regex = /[^A-Za-z0-9_\-]/; function is_class_name (str) { return !class_regex.test(str); } TK.Toggle = TK.class({ /** * A toggle button. The toggle button can either be pressed (which means that it will * switch its state as long as it is pressed) or toggled permanently. Its behavior is * controlled by the two options press and toggle. * * @class TK.Toggle * * @extends TK.Button * * @param {Object} [options={ }] - An object containing initial options. * * @property {Boolean} [options.toggle=true] - If true, the button is toggled on click. * @property {Integer} [options.press=0] - Controls press behavior. If options.toggle * is false and this option is 0, the toggle button will toggle until * released. If options.toggle is true and this option is a positive integer, it is * interpreted as a milliseconds timeout. When pressing a button longer than this timeout, it will * be toggled until released, otherwise it will be toggled permanently. * @property {Integer} [options.delay=0] - Delay all actions for n milliseconds. While actions are * delayed, the widget has class toolkit-delayed. Use to force users to press the button * for a certain amount of time before it actually gets toggled. * @property {String|Boolean} [options.icon_active=false] - An optional icon which is only displayed * when the button toggle state is true. Please note that this option only works if `icon` is also set. * @property {String|Boolean} [options.label_active=false] - An optional label which is only displayed * when the button toggle state is true. Please note that this option only works if `label` is also set. */ _class: "Toggle", Extends: TK.Button, _options: Object.assign(Object.create(TK.Button.prototype._options), { label_active: "string", icon_active: "string", press: "int", delay: "int", toggle: "boolean", }), options: { label_active: false, icon_active: false, icon_inactive: false, press: 0, delay: 0, toggle: true, }, static_events: { mousedown: mousedown, touchstart: touchstart, contextmenu: contextmenu, }, initialize: function (options) { TK.Button.prototype.initialize.call(this, options); /** * @member {HTMLDivElement} TK.Toggle#element - The main DIV container. * Has class toolkit-toggle. */ TK.add_class(this.element, "toolkit-toggle"); this.__press_start_time = 0; this.__touch_id = false; this.__delayed_to = -1; }, redraw: function () { var O = this.options; var I = this.invalid; if (I.state) { var tmp = (O.state && O.label_active) || O.label; if (tmp) this.label.set("label", tmp || ""); tmp = (O.state && O.icon_active) || O.icon; if (tmp) this.icon.set("icon", tmp || ""); } TK.Button.prototype.redraw.call(this); }, /** * Toggle the button state. * * @method TK.Toggle#toggle * * @emits TK.Toggle#toggled */ toggle: function () { toggle.call(this, this.options); /** * Is fired when the button was toggled. * * @event TK.Toggle#toggled * * @param {boolean} state - The state of the {@link TK.Toggle}. */ }, }); })(this, this.TK);