800 lines
24 KiB
JavaScript
800 lines
24 KiB
JavaScript
|
/*
|
||
|
* 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){
|
||
|
|
||
|
function Invalid(options) {
|
||
|
for (var key in options) this[key] = true;
|
||
|
};
|
||
|
Invalid.prototype = {
|
||
|
validate : function() {
|
||
|
var i = 0, key;
|
||
|
var ret = false;
|
||
|
for (i = 0; i < arguments.length; i++) {
|
||
|
key = arguments[i];
|
||
|
if (this.hasOwnProperty(key) && this[key]) {
|
||
|
this[key] = false;
|
||
|
ret = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
},
|
||
|
test : function() {
|
||
|
var i = 0, key;
|
||
|
for (i = 0; i < arguments.length; i++) {
|
||
|
key = arguments[i];
|
||
|
if (this.hasOwnProperty(key) && this[key]) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
function redraw(fun) {
|
||
|
if (!this._drawn) return;
|
||
|
this.needs_redraw = false;
|
||
|
/**
|
||
|
* Is fired when a redraw is executed.
|
||
|
*
|
||
|
* @event TK.Widget#redraw
|
||
|
*/
|
||
|
this.fire_event("redraw");
|
||
|
fun.call(this);
|
||
|
}
|
||
|
function resize() {
|
||
|
if (this.is_destructed()) return;
|
||
|
this.resize();
|
||
|
}
|
||
|
function dblclick (e) {
|
||
|
/**
|
||
|
* Is fired after a double click appeared. Set `dblclick` to 0 to
|
||
|
* disable click event handling.
|
||
|
*
|
||
|
* @event TK.Widget#doubleclick
|
||
|
*
|
||
|
* @param {string} event - The browsers `MouseEvent`.
|
||
|
*
|
||
|
*/
|
||
|
var O = this.options;
|
||
|
var dbc = O.dblclick;
|
||
|
if (!dbc) return;
|
||
|
var d = + new Date();
|
||
|
if (this.__lastclick + dbc > d) {
|
||
|
e.lastclick = this.__lastclick;
|
||
|
this.fire_event("doubleclick", e);
|
||
|
this.__lastclick = 0;
|
||
|
} else {
|
||
|
this.__lastclick = d;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TK.Widget = TK.class({
|
||
|
/**
|
||
|
* TK.Widget is the base class for all widgets drawing DOM elements. It
|
||
|
* provides basic functionality like delegating events, setting options and
|
||
|
* firing some events.
|
||
|
*
|
||
|
* @class TK.Widget
|
||
|
*
|
||
|
* @extends TK.Base
|
||
|
*
|
||
|
* @param {Object} [options={ }] - An object containing initial options.
|
||
|
*
|
||
|
* @property {String} [options.class=""] - A class to add to the class attribute of the main element.
|
||
|
* @property {HTMLElement} [options.container] - A container the main element shall be added to.
|
||
|
* @property {String} [options.id=""] - A string to be set as id attribute on the main element.
|
||
|
* @property {Object} [options.styles=""] - An object containing CSS declarations to be added directly to the main element.
|
||
|
* @property {Boolean} [options.disabled=false] - Toggles the class <code>toolkit-disabled</code>.
|
||
|
* @property {HTMLElement} [options.element] - An element to be used as the main element.
|
||
|
* @property {Boolean} [options.active] - Toggles the class <code>toolkit-inactive</code>.
|
||
|
* @property {Boolean} [options.needs_resize=true] - Set to true if the resize function shall be called before the next redraw.
|
||
|
* @property {Boolean} [options.dblclick=400] - Set a time in milliseconds for triggering double click event. If 0, no double click events are fired.
|
||
|
*/
|
||
|
/**
|
||
|
* The <code>set</code> event is emitted when an option was set using the {@link TK.Widget#set}
|
||
|
* method. The arguments are the option name and its new value.
|
||
|
*
|
||
|
* Note that this happens both for user interaction and programmatical option changes.
|
||
|
*
|
||
|
* @event TK.Widget#set
|
||
|
*/
|
||
|
/**
|
||
|
* The <code>redraw</code> event is emitted when a widget is redrawn. This can be used
|
||
|
* to do additional DOM modifications to a Widget.
|
||
|
*
|
||
|
* @event TK.Widget#redraw
|
||
|
*/
|
||
|
/**
|
||
|
* The <code>resize</code> event is emitted whenever a widget is being resized. This event can
|
||
|
* be used to e.g. measure its new size. Note that some widgets do internal adjustments after
|
||
|
* the <code>resize</code> event. If that is relevant, the {@link TK.Widget#resized} event can
|
||
|
* be used, instead.
|
||
|
*
|
||
|
* @event TK.Widget#resize
|
||
|
*/
|
||
|
/**
|
||
|
* The <code>resized</code> event is emitted after each rendering frame, which was triggered by
|
||
|
* a resize event.
|
||
|
*
|
||
|
* @event TK.Widget#resized
|
||
|
*/
|
||
|
/**
|
||
|
* The <code>hide</code> event is emitted when a widget is hidden and is not rendered anymore.
|
||
|
* This happens both with browser visibility changes and also internally when using layout widgets
|
||
|
* such as {@link TK.Pager}.
|
||
|
*
|
||
|
* @event TK.Widget#hide
|
||
|
*/
|
||
|
/**
|
||
|
* The <code>show</code> event is emitted when a widget is shown and is being rendered. This is the
|
||
|
* counterpart to {@link TK.Widget#hide}.
|
||
|
*
|
||
|
* @event TK.Widget#show
|
||
|
*/
|
||
|
Extends : TK.Base,
|
||
|
_class: "Widget",
|
||
|
_options: {
|
||
|
// A CSS class to add to the main element
|
||
|
class: "string",
|
||
|
// A DOM element as container to inject the element
|
||
|
// into
|
||
|
container: "object",
|
||
|
// a id to set on the element. If omitted a random
|
||
|
// string is generated.
|
||
|
id: "string",
|
||
|
// If an element was stylized, styles can be applied
|
||
|
styles: "object",
|
||
|
disabled: "boolean",
|
||
|
element: "object",
|
||
|
active: "boolean",
|
||
|
needs_resize: "boolean",
|
||
|
dblclick: "number",
|
||
|
},
|
||
|
options: {
|
||
|
// these options are of less use and only here to show what we need
|
||
|
disabled: false, // Widgets can be disabled by setting this to true
|
||
|
needs_resize: true,
|
||
|
dblclick: 0,
|
||
|
},
|
||
|
static_events: {
|
||
|
set_container: function(value) {
|
||
|
if (value && this.element) {
|
||
|
value.appendChild(this.element);
|
||
|
} else if (!value && this.element.parentElement) {
|
||
|
this.element.parentElement.removeChild(this.element);
|
||
|
}
|
||
|
},
|
||
|
set_dblclick: function (val) {
|
||
|
if (!this.__delegated) return;
|
||
|
if (!!val)
|
||
|
this.__delegated.addEventListener("click", this.__dblclick_cb);
|
||
|
else
|
||
|
this.__delegated.removeEventListener("click", this.__dblclick_cb);
|
||
|
},
|
||
|
initialized: function () {
|
||
|
var v = this.options.dblclick;
|
||
|
if (v > 0)
|
||
|
this.set("dblclick", v);
|
||
|
},
|
||
|
},
|
||
|
initialize: function (options) {
|
||
|
// Main actions every widget needs to take
|
||
|
if (!options) options = {};
|
||
|
/** @property {HTMLElement} TK.Widget#element - The main element. */
|
||
|
if (options.element)
|
||
|
this.element = options.element;
|
||
|
TK.Base.prototype.initialize.call(this, options);
|
||
|
this.__classified = null;
|
||
|
this.__stylized = null;
|
||
|
this.__delegated = null;
|
||
|
this.__widgetized = null;
|
||
|
this.invalid = new Invalid(this.options);
|
||
|
if (!this.value_time) this.value_time = null;
|
||
|
this.needs_redraw = false;
|
||
|
this._redraw = redraw.bind(this, this.redraw);
|
||
|
this.__resize = resize.bind(this);
|
||
|
this._schedule_resize = this.schedule_resize.bind(this);
|
||
|
this._drawn = false;
|
||
|
this.parent = null;
|
||
|
this.children = null;
|
||
|
this.draw_queue = null;
|
||
|
this.__lastclick = 0;
|
||
|
this.__dblclick_cb = dblclick.bind(this);
|
||
|
},
|
||
|
|
||
|
is_destructed: function() {
|
||
|
return this.options === null;
|
||
|
},
|
||
|
|
||
|
invalidate_all: function() {
|
||
|
for (var key in this.options) {
|
||
|
if (!this._options[key]) {
|
||
|
if (key.charCodeAt(0) !== 95)
|
||
|
TK.warn("%O %s: unknown option %s", this, this._class, key);
|
||
|
} else this.invalid[key] = true;
|
||
|
}
|
||
|
},
|
||
|
|
||
|
assert_none_invalid: function() {
|
||
|
var warn = [];
|
||
|
for (var key in this.invalid) {
|
||
|
if (this.invalid[key] === true) {
|
||
|
warn.push(key);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (warn.length) {
|
||
|
TK.warn("found", warn.length, "invalid in", this, ":", warn);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
trigger_resize: function() {
|
||
|
if (!this.options.needs_resize) {
|
||
|
if (this.is_destructed()) {
|
||
|
// This object was destroyed but trigger resize was still scheduled for the next frame.
|
||
|
// FIXME: fix this whole problem properly
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
this.set("needs_resize", true);
|
||
|
|
||
|
var C = this.children;
|
||
|
|
||
|
if (!C) return;
|
||
|
|
||
|
for (var i = 0; i < C.length; i++) {
|
||
|
C[i].trigger_resize();
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
|
||
|
trigger_resize_children: function() {
|
||
|
var C = this.children;
|
||
|
|
||
|
if (!C) return;
|
||
|
|
||
|
for (var i = 0; i < C.length; i++) {
|
||
|
C[i].trigger_resize();
|
||
|
}
|
||
|
},
|
||
|
|
||
|
schedule_resize: function() {
|
||
|
TK.S.add(this.__resize, 0);
|
||
|
},
|
||
|
|
||
|
resize: function() {
|
||
|
/**
|
||
|
* Is fired when a resize is requested.
|
||
|
*
|
||
|
* @event TK.Widget#resize
|
||
|
*/
|
||
|
this.fire_event("resize");
|
||
|
|
||
|
if (this._options.resized)
|
||
|
this.set("resized", true);
|
||
|
|
||
|
/**
|
||
|
* Is fired after the resize was executed and the DOM is updated.
|
||
|
*
|
||
|
* @event TK.Widget#resized
|
||
|
*/
|
||
|
if (this.has_event_listeners("resized")) {
|
||
|
TK.S.after_frame(this.fire_event.bind(this, "resized"));
|
||
|
}
|
||
|
},
|
||
|
|
||
|
trigger_draw: function() {
|
||
|
if (!this.needs_redraw) {
|
||
|
this.needs_redraw = true;
|
||
|
if (this._drawn) TK.S.add(this._redraw, 1);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
trigger_draw_next : function() {
|
||
|
if (!this.needs_redraw) {
|
||
|
this.needs_redraw = true;
|
||
|
if (this._drawn) TK.S.add_next(this._redraw, 1);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
initialized: function () {
|
||
|
// Main actions every widget needs to take
|
||
|
/**
|
||
|
* Is fired when a widget is initialized.
|
||
|
*
|
||
|
* @event TK.Widget#initialized
|
||
|
*/
|
||
|
this.fire_event("initialized");
|
||
|
this.trigger_draw();
|
||
|
},
|
||
|
draw_once: function(fun) {
|
||
|
var q = this.draw_queue;
|
||
|
|
||
|
if (q === null) {
|
||
|
this.draw_queue = [ fun ];
|
||
|
} else {
|
||
|
for (var i = 0; i < q.length; i++) if (q[i] === fun) return;
|
||
|
q[i] = fun;
|
||
|
}
|
||
|
this.trigger_draw();
|
||
|
},
|
||
|
redraw: function () {
|
||
|
var I = this.invalid;
|
||
|
var O = this.options;
|
||
|
var E = this.element;
|
||
|
|
||
|
if (E) {
|
||
|
if (I.id) {
|
||
|
I.id = false;
|
||
|
if (O.id) E.setAttribute("id", O.id);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
E = this.__stylized;
|
||
|
|
||
|
if (E) {
|
||
|
if (I.active) {
|
||
|
I.active = false;
|
||
|
TK.toggle_class(E, "toolkit-inactive", !O.active);
|
||
|
}
|
||
|
|
||
|
if (I.disabled) {
|
||
|
I.disabled = false;
|
||
|
TK.toggle_class(E, "toolkit-disabled", O.disabled);
|
||
|
}
|
||
|
|
||
|
if (I.styles) {
|
||
|
I.styles = false;
|
||
|
if (O.styles) TK.set_styles(E, O.styles);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (I.needs_resize) {
|
||
|
I.needs_resize = false;
|
||
|
|
||
|
if (O.needs_resize) {
|
||
|
O.needs_resize = false;
|
||
|
|
||
|
TK.S.after_frame(this._schedule_resize);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var q = this.draw_queue;
|
||
|
|
||
|
this.draw_queue = null;
|
||
|
|
||
|
if (q) for (var i = 0; i < q.length; i++) {
|
||
|
q[i].call(this, O);
|
||
|
}
|
||
|
},
|
||
|
destroy: function () {
|
||
|
/**
|
||
|
* Is fired when a widget is destroyed.
|
||
|
*
|
||
|
* @event TK.Widget#destroy
|
||
|
*/
|
||
|
if (this.is_destructed()) {
|
||
|
TK.warn("destroy called twice on ", this);
|
||
|
return;
|
||
|
}
|
||
|
this.fire_event("destroy");
|
||
|
|
||
|
this.disable_draw();
|
||
|
if (this.parent) this.parent.remove_child(this);
|
||
|
|
||
|
TK.Base.prototype.destroy.call(this);
|
||
|
|
||
|
this._redraw = null;
|
||
|
this.__resize = null;
|
||
|
this._schedule_resize = null;
|
||
|
this.children = null;
|
||
|
this.options = null;
|
||
|
this.parent = null;
|
||
|
|
||
|
if (this.element) {
|
||
|
this.element.remove();
|
||
|
this.element = null;
|
||
|
}
|
||
|
},
|
||
|
delegate: function (element) {
|
||
|
this.delegate_events(element);
|
||
|
this.__delegated = element;
|
||
|
/**
|
||
|
* Is fired when a widget gets delegated.
|
||
|
*
|
||
|
* @event TK.Widget#initialized
|
||
|
*
|
||
|
* @param {HTMLElement} element - The element all native DOM events are delegated to.
|
||
|
*/
|
||
|
this.fire_event("delegated", element);
|
||
|
return element;
|
||
|
},
|
||
|
add_class: function (cls) {
|
||
|
TK.add_class(this.__classified, cls);
|
||
|
},
|
||
|
remove_class: function (cls) {
|
||
|
TK.remove_class(this.__classified, cls);
|
||
|
},
|
||
|
has_class: function (cls) {
|
||
|
return TK.has_class(this.__classified, cls);
|
||
|
},
|
||
|
classify: function (element) {
|
||
|
// Takes a DOM element and adds its CSS functionality to the
|
||
|
// widget instance
|
||
|
this.__classified = element;
|
||
|
if (this.options.class && element)
|
||
|
TK.add_class(element, this.options.class);
|
||
|
/**
|
||
|
* Is fired when a widget is classified.
|
||
|
*
|
||
|
* @event TK.Widget#classified
|
||
|
*
|
||
|
* @param {HTMLElement} element - The element which receives all further class changes.
|
||
|
*/
|
||
|
this.fire_event("classified", element);
|
||
|
return element;
|
||
|
},
|
||
|
set_style: function (name, value) {
|
||
|
TK.set_style(this.__stylized, name, value);
|
||
|
},
|
||
|
/**
|
||
|
* Sets a CSS style property in this widgets DOM element.
|
||
|
*
|
||
|
* @method TK.Widget#set_style
|
||
|
*/
|
||
|
set_styles: function (styles) {
|
||
|
TK.set_styles(this.__stylized, styles);
|
||
|
},
|
||
|
/**
|
||
|
* Returns the computed style of this widgets DOM element.
|
||
|
*
|
||
|
* @method TK.Widget#get_style
|
||
|
*/
|
||
|
get_style: function (name) {
|
||
|
return TK.get_style(this.__stylized, name);
|
||
|
},
|
||
|
stylize: function (element) {
|
||
|
// Marks a DOM element as receiver for the "styles" options
|
||
|
this.__stylized = element;
|
||
|
if (this.options.styles) {
|
||
|
TK.set_styles(element, this.options.styles);
|
||
|
}
|
||
|
/**
|
||
|
* Is fired when a widget is stylized.
|
||
|
*
|
||
|
* @event TK.Widget#stylized
|
||
|
*
|
||
|
* @param {HTMLElement} element - The element which receives all further style changes.
|
||
|
*/
|
||
|
this.fire_event("stylized", element);
|
||
|
return element;
|
||
|
},
|
||
|
widgetize: function (element, delegate, classify, stylize) {
|
||
|
/**
|
||
|
* Set the DOM elements of this widgets. This method is usually only used internally.
|
||
|
* Basically it means to add the id from options and set a basic CSS class.
|
||
|
* If delegate is true, basic events will be delegated from the element to the widget instance
|
||
|
* if classify is true, CSS functions will be bound to the widget instance.
|
||
|
*
|
||
|
* @method TK.Widget#widgetize
|
||
|
* @emits TK.Widget#widgetize
|
||
|
*/
|
||
|
var O = this.options;
|
||
|
|
||
|
// classify?
|
||
|
TK.add_class(element, "toolkit-widget");
|
||
|
if (typeof O.id !== "string") {
|
||
|
O.id = element.getAttribute("id");
|
||
|
if (!O.id) {
|
||
|
O.id = TK.unique_id()
|
||
|
element.setAttribute("id", O.id);
|
||
|
}
|
||
|
} else element.setAttribute("id", O.id);
|
||
|
|
||
|
if (O.class) {
|
||
|
var c = O.class.split(" ");
|
||
|
for (var i = 0; i < c.length; i++)
|
||
|
TK.add_class(element, c[i]);
|
||
|
}
|
||
|
if (O.container)
|
||
|
O.container.appendChild(element);
|
||
|
if (delegate)
|
||
|
this.delegate(element);
|
||
|
if (classify)
|
||
|
this.classify(element);
|
||
|
if (stylize)
|
||
|
this.stylize(element);
|
||
|
this.__widgetized = element;
|
||
|
/**
|
||
|
* Is fired when a widget is widgetized.
|
||
|
*
|
||
|
* @event TK.Widget#widgetize
|
||
|
*
|
||
|
* @param {HTMLElement} element - The element which got widgetized.
|
||
|
*/
|
||
|
this.fire_event("widgetized", element);
|
||
|
return element;
|
||
|
},
|
||
|
|
||
|
// GETTER & SETTER
|
||
|
/**
|
||
|
* Sets an option.
|
||
|
*
|
||
|
* @method TK.Widget#set
|
||
|
*
|
||
|
* @param {string} key - The option name.
|
||
|
* @param value - The option value.
|
||
|
*/
|
||
|
set: function (key, value) {
|
||
|
/* These options are special and need to be handled immediately, in order
|
||
|
* to preserve correct ordering */
|
||
|
if (key === "class" && this.__classified) {
|
||
|
if (this.options.class) TK.remove_class(this.__classified, this.options.class);
|
||
|
if (value) TK.add_class(this.__classified, value);
|
||
|
}
|
||
|
if (this._options[key]) {
|
||
|
this.invalid[key] = true;
|
||
|
if (this.value_time && this.value_time[key])
|
||
|
this.value_time[key] = Date.now();
|
||
|
this.trigger_draw();
|
||
|
} else if (key.charCodeAt(0) !== 95) {
|
||
|
TK.warn("%O: %s.set(%s, %O): unknown option.", this, this._class, key, value);
|
||
|
}
|
||
|
TK.Base.prototype.set.call(this, key, value);
|
||
|
return value;
|
||
|
},
|
||
|
track_option: function(key) {
|
||
|
if (!this.value_time) this.value_time = {};
|
||
|
this.value_time[key] = Date.now();
|
||
|
},
|
||
|
/**
|
||
|
* Schedules this widget for drawing.
|
||
|
*
|
||
|
* @method TK.Widget#enable_draw
|
||
|
*
|
||
|
* @emits TK.Widget#show
|
||
|
*/
|
||
|
enable_draw: function () {
|
||
|
if (this._drawn) return;
|
||
|
this._drawn = true;
|
||
|
if (this.needs_redraw) {
|
||
|
TK.S.add(this._redraw, 1);
|
||
|
}
|
||
|
/**
|
||
|
* Is fired when a widget gets enabled for drawing.
|
||
|
*
|
||
|
* @event TK.Widget#show
|
||
|
*/
|
||
|
this.fire_event("show");
|
||
|
this.fire_event("visibility", true);
|
||
|
var C = this.children;
|
||
|
if (C) for (var i = 0; i < C.length; i++) C[i].enable_draw();
|
||
|
},
|
||
|
/**
|
||
|
* Stop drawing this widget.
|
||
|
*
|
||
|
* @method TK.Widget#enable_draw
|
||
|
*
|
||
|
* @emits TK.Widget#hide
|
||
|
*/
|
||
|
disable_draw: function () {
|
||
|
if (!this._drawn) return;
|
||
|
this._drawn = false;
|
||
|
if (this.needs_redraw) {
|
||
|
TK.S.remove(this._redraw, 1);
|
||
|
TK.S.remove_next(this._redraw, 1);
|
||
|
}
|
||
|
/**
|
||
|
* Is fired when a widget is hidden and not rendered anymore.
|
||
|
*
|
||
|
* @event TK.Widget#hide
|
||
|
*/
|
||
|
/**
|
||
|
* Is fired when the visibility state changes. The first argument
|
||
|
* is the visibility state, which is either <code>true</code>
|
||
|
* or <code>false</code>.
|
||
|
*
|
||
|
* @event TK.Widget#visibility
|
||
|
*/
|
||
|
this.fire_event("hide");
|
||
|
this.fire_event("visibility", false);
|
||
|
var C = this.children;
|
||
|
if (C) for (var i = 0; i < C.length; i++) C[i].disable_draw();
|
||
|
},
|
||
|
/**
|
||
|
* Make the widget visible. This does not modify the DOM, instead it will only schedule
|
||
|
* the widget for rendering.
|
||
|
*
|
||
|
* @method TK.Widget#show
|
||
|
*/
|
||
|
show: function () {
|
||
|
this.enable_draw();
|
||
|
},
|
||
|
/**
|
||
|
* This is an alias for hide, which may be overloaded.
|
||
|
* See {@link TK.Container} for an example.
|
||
|
*
|
||
|
* @method TK.Widget#force_show
|
||
|
*/
|
||
|
force_show: function() {
|
||
|
this.enable_draw();
|
||
|
},
|
||
|
/**
|
||
|
* Make the widget hidden. This does not modify the DOM, instead it will stop rendering
|
||
|
* this widget. Options changed after calling hide will only be rendered (i.e. applied
|
||
|
* to the DOM) when the widget is made visible again using {@link TK.Widget#show}.
|
||
|
*
|
||
|
* @method TK.Widget#hide
|
||
|
*/
|
||
|
hide: function () {
|
||
|
this.disable_draw();
|
||
|
},
|
||
|
/**
|
||
|
* This is an alias for hide, which may be overloaded.
|
||
|
* See {@link TK.Container} for an example.
|
||
|
*
|
||
|
* @method TK.Widget#force_hide
|
||
|
*/
|
||
|
force_hide: function () {
|
||
|
this.disable_draw();
|
||
|
},
|
||
|
show_nodraw: function() { },
|
||
|
hide_nodraw: function() { },
|
||
|
/**
|
||
|
* Returns the current hidden status.
|
||
|
*
|
||
|
* @method TK.Widget#hidden
|
||
|
*/
|
||
|
hidden: function() {
|
||
|
return !this._drawn;
|
||
|
},
|
||
|
is_drawn: function() {
|
||
|
return this._drawn;
|
||
|
},
|
||
|
/**
|
||
|
* TK.Toggle the hidden status. This is equivalent to calling hide() or show(), depending on
|
||
|
* the current hidden status of this widget.
|
||
|
*
|
||
|
* @method TK.Widget#toggle_hidden
|
||
|
*/
|
||
|
toggle_hidden: function() {
|
||
|
if (this.hidden()) this.show();
|
||
|
else this.hide();
|
||
|
},
|
||
|
set_parent: function(parent) {
|
||
|
if (this.parent) {
|
||
|
this.parent.remove_child(this);
|
||
|
}
|
||
|
this.parent = parent;
|
||
|
},
|
||
|
/**
|
||
|
* Registers a widget as a child widget. This method is used to build up the widget tree. It does not modify the DOM tree.
|
||
|
*
|
||
|
* @method TK.Widget#add_child
|
||
|
*
|
||
|
* @param {TK.Widget} child - The child to add.
|
||
|
*
|
||
|
* @see TK.Container#append_child
|
||
|
*/
|
||
|
add_child: function(child) {
|
||
|
var C = this.children;
|
||
|
if (!C) this.children = C = [];
|
||
|
child.set_parent(this);
|
||
|
C.push(child);
|
||
|
if (!this.hidden()) {
|
||
|
child.enable_draw();
|
||
|
} else {
|
||
|
child.disable_draw();
|
||
|
}
|
||
|
child.trigger_resize();
|
||
|
},
|
||
|
/**
|
||
|
* Removes a child widget. Note that this method only modifies
|
||
|
* the widget tree and does not change the DOM.
|
||
|
*
|
||
|
* @method TK.Widget#remove_child
|
||
|
*
|
||
|
* @param {TK.Widget} child - The child to remove.
|
||
|
*/
|
||
|
remove_child : function(child) {
|
||
|
child.disable_draw();
|
||
|
child.parent = null;
|
||
|
var C = this.children;
|
||
|
if (C === null) return;
|
||
|
var i = C.indexOf(child);
|
||
|
if (i !== -1) {
|
||
|
C.splice(i, 1);
|
||
|
}
|
||
|
if (!C.length) this.children = null;
|
||
|
},
|
||
|
/**
|
||
|
* Removes an array of children.
|
||
|
*
|
||
|
* @method TK.Widget#remove_children
|
||
|
*
|
||
|
* @param {Array.<TK.Widget>} a - An array of Widgets.
|
||
|
*/
|
||
|
remove_children : function(a) {
|
||
|
a.map(this.remove_child, this);
|
||
|
},
|
||
|
/**
|
||
|
* Registers an array of widgets as children.
|
||
|
*
|
||
|
* @method TK.Widget#add_children
|
||
|
*
|
||
|
* @param {Array.<TK.Widget>} a - An array of Widgets.
|
||
|
*/
|
||
|
add_children : function (a) {
|
||
|
a.map(this.add_child, this);
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Returns an array of all visible children.
|
||
|
*
|
||
|
* @method TK.Widget#visible_children
|
||
|
*/
|
||
|
visible_children: function(a) {
|
||
|
if (!a) a = [];
|
||
|
var C = this.children;
|
||
|
if (C) for (var i = 0; i < C.length; i++) {
|
||
|
a.push(C[i]);
|
||
|
C[i].visible_children(a);
|
||
|
}
|
||
|
return a;
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Returns an array of all children.
|
||
|
*
|
||
|
* @method TK.Widget#all_children
|
||
|
*/
|
||
|
all_children: function(a) {
|
||
|
if (!a) a = [];
|
||
|
var C = this.children;
|
||
|
if (C) for (var i = 0; i < C.length; i++) {
|
||
|
a.push(C[i]);
|
||
|
C[i].all_children(a);
|
||
|
}
|
||
|
return a;
|
||
|
},
|
||
|
});
|
||
|
|
||
|
TK.Module = TK.class({
|
||
|
Extends: TK.Base,
|
||
|
initialize: function(widget, options) {
|
||
|
this.parent = widget;
|
||
|
TK.Base.prototype.initialize.call(this, options);
|
||
|
},
|
||
|
destroy: function() {
|
||
|
this.parent = null;
|
||
|
TK.Base.prototype.destroy.call(this);
|
||
|
},
|
||
|
});
|
||
|
})(this, this.TK);
|
||
|
|
||
|
/**
|
||
|
* Generic DOM events. Please refer to
|
||
|
* <a href="https://www.w3schools.com/jsref/dom_obj_event.asp">
|
||
|
* W3Schools
|
||
|
* </a> for further details.
|
||
|
*
|
||
|
* @event TK.Widget##GenericDOMEvents
|
||
|
*/
|