1 /*
  2     Copyright 2008-2023
  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";
 40 import Env from "../utils/env";
 41 import Type from "../utils/type";
 42 
 43 var priv = {
 44     CheckboxChangeEventHandler: function () {
 45         this._value = this.rendNodeCheckbox.checked;
 46         this.board.update();
 47     }
 48 };
 49 
 50 /**
 51  * @class This element is used to provide a constructor for special texts containing a
 52  * form checkbox element.
 53  * <p>
 54  * For this element, the attribute "display" has to have the value 'html' (which is the default).
 55  * <p>
 56  * The underlying HTML checkbox element can be accessed through the sub-object 'rendNodeCheck', e.g. to
 57  * add event listeners.
 58  * 
 59  * @pseudo
 60  * @description
 61  * @name Checkbox
 62  * @augments Text
 63  * @constructor
 64  * @type JXG.Text
 65  *
 66  * @param {number,function_number,function_String,function} x,y,label Parent elements for checkbox elements.
 67  *   <p>
 68  *   x and y are the coordinates of the lower left corner of the text box.
 69  *    The position of the text is fixed,
 70  *   x and y are numbers. The position is variable if x or y are functions.
 71  *   <p>
 72  *   The label of the input element may be given as string or function.
 73  *   <p>
 74  *   The value of the checkbox can be controlled with the attribute <tt>checked</tt>
 75  *   <p>The HTML node can be accessed with <tt>element.rendNodeCheckbox</tt>
 76  *
 77  * @example
 78  *   // Create a checkbox element at position [0,3].
 79  *   var checkbox = board.create('checkbox', [0, 3, 'Change Y'], {});
 80  *   var p = board.create('point', [
 81  *       function(){ return 0.5;}, // X-coordinate
 82  *       function() {
 83  *           y = 0.5;
 84  *           if (checkbox.Value()) {
 85  *               y += 0.5;
 86  *           }
 87  *           return y;
 88  *       }]);
 89  * </pre><div class="jxgbox" id="JXG0e835e0b-ed0c-4b85-b682-78158c0e6f5c" style="width: 300px; height: 300px;"></div>
 90  * <script type="text/javascript">
 91  * (function() {
 92  *   var t1_board = JXG.JSXGraph.initBoard('JXG0e835e0b-ed0c-4b85-b682-78158c0e6f5c', {boundingbox: [-3, 6, 5, -3], axis: true, showcopyright: false, shownavigation: false});
 93  *   var checkbox = t1_board.create('checkbox', [0, 3, 'Change Y'], {});
 94  *   var p = t1_board.create('point', [
 95  *       function(){ return 0.5;}, // X-coordinate
 96  *       function() {
 97  *           y = 0.5;
 98  *           if (checkbox.Value()) {
 99  *               y += 0.5;
100  *           }
101  *           return y;
102  *       }]);
103  * })();
104  * </script><pre>
105  *
106  * The checkbox can be supplied with custom-made events by using the property rendNodeCheckbox.
107  * @example
108  * var checkbox = board.create('checkbox', [0, 4, 'Click me']),
109  *     p = board.create('point', [1, 1]);
110  *
111  * JXG.addEvent(checkbox.rendNodeCheckbox, 'change', function() {
112  *     if (this.Value()) {
113  *         p.moveTo([4, 1]);
114  *     } else {
115  *         p.moveTo([1, 1]);
116  *     }
117  * }, checkbox);
118  * </pre><div class="jxgbox" id="JXGb2f2345a-057d-44ce-bd7a-6aaff70bc810" style="width: 300px; height: 300px;"></div>
119  * <script type="text/javascript">
120  * (function() {
121  * var board = JXG.JSXGraph.initBoard('JXGb2f2345a-057d-44ce-bd7a-6aaff70bc810', {boundingbox: [-3, 6, 5, -3], axis: true, showcopyright: false, shownavigation: false});
122  * var checkbox = board.create('checkbox', [0, 4, 'Click me']),
123  *     p = board.create('point', [1, 1]);
124  *
125  * JXG.addEvent(checkbox.rendNodeCheckbox, 'change', function() {
126  *     if (this.Value()) {
127  *         p.moveTo([4, 1]);
128  *     } else {
129  *         p.moveTo([1, 1]);
130  *     }
131  * }, checkbox);
132  * })();
133  * </script><pre>
134  *
135  * @example
136  *         var i1 = board.create('input', [-3, 4, 'sin(x)', 'f(x)='], {cssStyle: 'width:4em', maxlength: 2});
137  *         var c1 = board.create('checkbox', [-3, 2, 'label 1'], {});
138  *         var b1 = board.create('button', [-3, -1, 'Change texts', function () {
139  *                 i1.setText('g(x)');
140  *                 i1.set('cos(x)');
141  *                 c1.setText('label 2');
142  *                 b1.setText('Texts are changed');
143  *             }],
144  *             {cssStyle: 'width:400px'});
145  *
146  * </pre><div id="JXG11cac8gg-2354-47e7-9da4-eb298e53de05" class="jxgbox" style="width: 300px; height: 300px;"></div>
147  * <script type="text/javascript">
148  *     (function() {
149  *         var board = JXG.JSXGraph.initBoard('JXG11cac8gg-2354-47e7-9da4-eb298e53de05',
150  *             {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});
151  *             var i1 = board.create('input', [-3, 4, 'sin(x)', 'f(x)='], {cssStyle: 'width:4em', maxlength: 2});
152  *             var c1 = board.create('checkbox', [-3, 2, 'label 1'], {});
153  *             var b1 = board.create('button', [-3, -1, 'Change texts', function () {
154  *                     i1.setText('g(x)');
155  *                     i1.set('cos(x)');
156  *                     c1.setText('label 2');
157  *                     b1.setText('Texts are changed');
158  *                 }],
159  *                 {cssStyle: 'width:400px'});
160  *
161  *     })();
162  *
163  * </script><pre>
164  */
165 JXG.createCheckbox = function (board, parents, attributes) {
166     var t,
167         par,
168         attr = Type.copyAttributes(attributes, board.options, "checkbox");
169 
170     //if (parents.length !== 3) {
171     //throw new Error("JSXGraph: Can't create checkbox with parent types '" +
172     //    (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
173     //    "\nPossible parents are: [[x,y], label]");
174     //}
175 
176     par = [
177         parents[0],
178         parents[1],
179         '<span style="display:inline">' +
180             '<input type="checkbox" /><label for=""></label>' +
181             "</span>"
182     ];
183 
184     // 1. Create checkbox element with empty label
185     t = board.create("text", par, attr);
186     t.type = Type.OBJECT_TYPE_CHECKBOX;
187 
188     t.rendNodeCheckbox = t.rendNode.childNodes[0].childNodes[0];
189     t.rendNodeLabel = t.rendNode.childNodes[0].childNodes[1];
190 
191     t.rendNodeTag = t.rendNodeCheckbox; // Needed for unified treatment in setAttribute
192     t.rendNodeTag.disabled = !!attr.disabled;
193 
194     // t.rendNodeLabel.innerHTML = parents[2];
195     t.rendNodeCheckbox.id = t.rendNode.id + "_checkbox";
196     t.rendNodeLabel.id = t.rendNode.id + "_label";
197     t.rendNodeLabel.setAttribute("for", t.rendNodeCheckbox.id);
198 
199     // 2. Set parents[2] (string|function) as label of the checkbox element.
200     // abstract.js selects the correct DOM element for the update
201     t.setText(parents[2]);
202 
203     // This sets the font-size of the checkbox itself
204     t.visPropOld.fontsize = "0px";
205     board.renderer.updateTextStyle(t, false);
206 
207     t.rendNodeCheckbox.checked = attr.checked;
208 
209     t._value = attr.checked;
210 
211     /**
212      * Returns the value of the checkbox element
213      * @name Value
214      * @memberOf Checkbox.prototype
215      * @function
216      * @returns {String} value of the checkbox.
217      */
218     t.Value = function () {
219         return this._value;
220     };
221 
222     t.update = function () {
223         if (this.needsUpdate) {
224             JXG.Text.prototype.update.call(this);
225             this._value = this.rendNodeCheckbox.checked;
226         }
227         return this;
228     };
229 
230     Env.addEvent(t.rendNodeCheckbox, "change", priv.CheckboxChangeEventHandler, t);
231 
232     return t;
233 };
234 
235 JXG.registerElement("checkbox", JXG.createCheckbox);
236 
237 // export default {
238 //     createCheckbox: JXG.createCheckbox
239 // };
240