      1 /*
      2     Copyright 2008-2024
      3         Matthias Ehmann,
      4         Michael Gerhaeuser,
      5         Carsten Miller,
      6         Bianca Valentin,
      7         Alfred Wassermann,
      8         Peter Wilfahrt
      9
     10     This file is part of JSXGraph.
     11
     12     JSXGraph is free software dual licensed under the GNU LGPL or MIT License.
     13
     14     You can redistribute it and/or modify it under the terms of the
     15
     16       * GNU Lesser General Public License as published by
     17         the Free Software Foundation, either version 3 of the License, or
     18         (at your option) any later version
     19       OR
     20       * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT
     21
     22     JSXGraph is distributed in the hope that it will be useful,
     23     but WITHOUT ANY WARRANTY; without even the implied warranty of
     24     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     25     GNU Lesser General Public License for more details.
     26
     27     You should have received a copy of the GNU Lesser General Public License and
     28     the MIT License along with JSXGraph. If not, see <https://www.gnu.org/licenses/>
     29     and <https://opensource.org/licenses/MIT/>.
     30  */
     31
     32 /*global JXG: true, define: true, window: true*/
     33 /*jslint nomen: true, plusplus: true*/
     34
     35 /**
     36  * @fileoverview In this file the Text element is defined.
     37  */
     38
     39 import JXG from "../jxg.js";
     40 import Env from "../utils/env.js";
     41 import Type from "../utils/type.js";
     42
     43 var priv = {
     44     /**
     45      * @class
     46      * @ignore
     47      */
     48     CheckboxChangeEventHandler: function () {
     49         this._value = this.rendNodeCheckbox.checked;
     50         this.board.update();
     51     }
     52 };
     53
     54 /**
     55  * @class This element is used to provide a constructor for special texts containing a
     56  * form checkbox element.
     57  * For this element, the attribute "display" has to have the value 'html' (which is the default).
     58  *
     59  * <p><b>Setting a CSS class:</b> The attribute <tt>cssClass</tt> affects the HTML div element that contains the checkbox element. To change the CSS properties of the HTML checkbox element a selector of the form
     60  * <tt>.mycheck > checkbox { ... }</tt> has to be used. See the analog example for buttons:
     61  * {@link Button}.
     62  *
     63  * <p><b>Access the checkbox element with JavaScript:</b>
     64  * The underlying HTML checkbox element can be accessed through the sub-object 'rendNodeCheck', e.g. to
     65  * add event listeners.
     66  *
     67  * @pseudo
     68  * @name Checkbox
     69  * @augments Text
     70  * @constructor
     71  * @type JXG.Text
     72  *
     73  * @param {number,function_number,function_String,function} x,y,label Parent elements for checkbox elements.
     74  *   <p>
     75  *   x and y are the coordinates of the lower left corner of the text box.
     76  *    The position of the text is fixed,
     77  *   x and y are numbers. The position is variable if x or y are functions.
     78  *   <p>
     79  *   The label of the input element may be given as string or function.
     80  *   <p>
     81  *   The value of the checkbox can be controlled with the attribute <tt>checked</tt>
     82  *   <p>The HTML node can be accessed with <tt>element.rendNodeCheckbox</tt>
     83  *
     84  * @example
     85  *   // Create a checkbox element at position [0,3].
     86  *   var checkbox = board.create('checkbox', [0, 3, 'Change Y'], {});
     87  *   var p = board.create('point', [
     88  *       function(){ return 0.5;}, // X-coordinate
     89  *       function() {
     90  *           y = 0.5;
     91  *           if (checkbox.Value()) {
     92  *               y += 0.5;
     93  *           }
     94  *           return y;
     95  *       }]);
     96  * </pre><div class="jxgbox" id="JXG0e835e0b-ed0c-4b85-b682-78158c0e6f5c" style="width: 300px; height: 300px;"></div>
     97  * <script type="text/javascript">
     98  * (function() {
     99  *   var t1_board = JXG.JSXGraph.initBoard('JXG0e835e0b-ed0c-4b85-b682-78158c0e6f5c', {boundingbox: [-3, 6, 5, -3], axis: true, showcopyright: false, shownavigation: false});
    100  *   var checkbox = t1_board.create('checkbox', [0, 3, 'Change Y'], {});
    101  *   var p = t1_board.create('point', [
    102  *       function(){ return 0.5;}, // X-coordinate
    103  *       function() {
    104  *           y = 0.5;
    105  *           if (checkbox.Value()) {
    106  *               y += 0.5;
    107  *           }
    108  *           return y;
    109  *       }]);
    110  * })();
    111  * </script><pre>
    112  *
    113  * The checkbox can be supplied with custom-made events by using the property rendNodeCheckbox.
    114  * @example
    115  * var checkbox = board.create('checkbox', [0, 4, 'Click me']),
    116  *     p = board.create('point', [1, 1]);
    117  *
    118  * JXG.addEvent(checkbox.rendNodeCheckbox, 'change', function() {
    119  *     if (this.Value()) {
    120  *         p.moveTo([4, 1]);
    121  *     } else {
    122  *         p.moveTo([1, 1]);
    123  *     }
    124  * }, checkbox);
    125  * </pre><div class="jxgbox" id="JXGb2f2345a-057d-44ce-bd7a-6aaff70bc810" style="width: 300px; height: 300px;"></div>
    126  * <script type="text/javascript">
    127  * (function() {
    128  * var board = JXG.JSXGraph.initBoard('JXGb2f2345a-057d-44ce-bd7a-6aaff70bc810', {boundingbox: [-3, 6, 5, -3], axis: true, showcopyright: false, shownavigation: false});
    129  * var checkbox = board.create('checkbox', [0, 4, 'Click me']),
    130  *     p = board.create('point', [1, 1]);
    131  *
    132  * JXG.addEvent(checkbox.rendNodeCheckbox, 'change', function() {
    133  *     if (this.Value()) {
    134  *         p.moveTo([4, 1]);
    135  *     } else {
    136  *         p.moveTo([1, 1]);
    137  *     }
    138  * }, checkbox);
    139  * })();
    140  * </script><pre>
    141  * @example
    142  *     var i1 = board.create('input', [1, 5, 'sin(x)', 'f(x)='], {cssStyle: 'width:4em', maxlength: 2});
    143  *         var c1 = board.create('checkbox', [1, 3, 'label 1'], {});
    144  *         var b1 = board.create('button', [1, 1, 'Change texts', function () {
    145  *                 i1.setText('g(x)=');
    146  *                 i1.set('cos(x)');
    147  *                 c1.setText('label 2');
    148  *                 b1.setText('Texts are changed');
    149  *             }],
    150  *             {cssStyle: 'width:200px'});
    151  *
    152  * </pre><div id="JXG31c6d070-354b-4f09-aab9-9aaa796f730c" class="jxgbox" style="width: 300px; height: 300px;"></div>
    153  * <script type="text/javascript">
    154  *     (function() {
    155  *         var board = JXG.JSXGraph.initBoard('JXG31c6d070-354b-4f09-aab9-9aaa796f730c',
    156  *             {boundingbox: [-1, 7, 7, -1], axis: true, showcopyright: false, shownavigation: false});
    157  *         var i1 = board.create('input', [1, 5, 'sin(x)', 'f(x)='], {cssStyle: 'width:4em', maxlength: 2});
    158  *             var c1 = board.create('checkbox', [1, 3, 'label 1'], {});
    159  *             var b1 = board.create('button', [1, 1, 'Change texts', function () {
    160  *                     i1.setText('g(x)=');
    161  *                     i1.set('cos(x)');
    162  *                     c1.setText('label 2');
    163  *                     b1.setText('Texts are changed');
    164  *                 }],
    165  *                 {cssStyle: 'width:200px'});
    166  *
    167  *     })();
    168  *
    169  * </script><pre>
    170  *
    171  */
    172 JXG.createCheckbox = function (board, parents, attributes) {
    173     var t,
    174         par,
    175         attr = Type.copyAttributes(attributes, board.options, "checkbox");
    176
    177     //if (parents.length !== 3) {
    178     //throw new Error("JSXGraph: Can't create checkbox with parent types '" +
    179     //    (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
    180     //    "\nPossible parents are: [[x,y], label]");
    181     //}
    182
    183     par = [
    184         parents[0],
    185         parents[1],
    186         '<span style="display:inline">' +
    187             '<input type="checkbox" /><label for=""></label>' +
    188             "</span>"
    189     ];
    190
    191     // 1. Create checkbox element with empty label
    192     t = board.create("text", par, attr);
    193     t.type = Type.OBJECT_TYPE_CHECKBOX;
    194
    195     t.rendNodeCheckbox = t.rendNode.childNodes[0].childNodes[0];
    196     t.rendNodeLabel = t.rendNode.childNodes[0].childNodes[1];
    197
    198     t.rendNodeTag = t.rendNodeCheckbox; // Needed for unified treatment in setAttribute
    199     t.rendNodeTag.disabled = !!attr.disabled;
    200
    201     // t.rendNodeLabel.innerHTML = parents[2];
    202     t.rendNodeCheckbox.id = t.rendNode.id + "_checkbox";
    203     t.rendNodeLabel.id = t.rendNode.id + "_label";
    204     t.rendNodeLabel.setAttribute("for", t.rendNodeCheckbox.id);
    205
    206     // 2. Set parents[2] (string|function) as label of the checkbox element.
    207     // abstract.js selects the correct DOM element for the update
    208     t.setText(parents[2]);
    209
    210     // This sets the font-size of the checkbox itself
    211     t.visPropOld.fontsize = "0px";
    212     board.renderer.updateTextStyle(t, false);
    213
    214     t.rendNodeCheckbox.checked = attr.checked;
    215
    216     t._value = attr.checked;
    217
    218     /**
    219      * Returns the value of the checkbox element
    220      * @name Value
    221      * @memberOf Checkbox.prototype
    222      * @function
    223      * @returns {String} value of the checkbox.
    224      */
    225     t.Value = function () {
    226         return this._value;
    227     };
    228
    229      /**
    230      * @class
    231      * @ignore
    232      */
    233     t.update = function () {
    234         if (this.needsUpdate) {
    235             JXG.Text.prototype.update.call(this);
    236             this._value = this.rendNodeCheckbox.checked;
    237         }
    238         return this;
    239     };
    240
    241     Env.addEvent(t.rendNodeCheckbox, "change", priv.CheckboxChangeEventHandler, t);
    242
    243     return t;
    244 };
    245
    246 JXG.registerElement("checkbox", JXG.createCheckbox);
    247
    248 // export default {
    249 //     createCheckbox: JXG.createCheckbox
    250 // };
    251