1 /*
  2     Copyright 2008-2026
  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 Text from "../base/text.js";
 42 import Type from "../utils/type.js";
 43 
 44 var priv = {
 45     /**
 46      * @class
 47      * @ignore
 48      */
 49     CheckboxChangeEventHandler: function () {
 50         this._value = this.rendNodeCheckbox.checked;
 51         this.board.update();
 52     }
 53 };
 54 
 55 /**
 56  * @class A text element that contains an HTML checkbox tag.
 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         setTextBackup,
176         attr = Type.copyAttributes(attributes, board.options, 'checkbox');
177 
178     //if (parents.length !== 3) {
179     //throw new Error("JSXGraph: Can't create checkbox with parent types '" +
180     //    (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
181     //    "\nPossible parents are: [[x,y], label]");
182     //}
183 
184     par = [
185         parents[0],
186         parents[1],
187         '<span style="display:inline">' +
188             '<input type="checkbox" /><label for=""></label>' +
189             "</span>"
190     ];
191 
192     // Make sure the setText method is the original one. The JessieCode parser changes it during parsing.
193     setTextBackup = Text.prototype.setText;
194     Text.prototype.setText = Text.prototype._setText;
195 
196     // 1. Create checkbox element with empty label
197     t = board.create("text", par, attr);
198     t.type = Type.OBJECT_TYPE_CHECKBOX;
199 
200     // Restore whichever setText method was set before this contructor was called.
201     Text.prototype.setText = setTextBackup;
202 
203 
204     t.rendNodeCheckbox = t.rendNode.childNodes[0].childNodes[0];
205     t.rendNodeLabel = t.rendNode.childNodes[0].childNodes[1];
206 
207     t.rendNodeTag = t.rendNodeCheckbox; // Needed for unified treatment in setAttribute
208     t.rendNodeTag.disabled = !!attr.disabled;
209 
210     t.rendNodeCheckbox.id = t.rendNode.id + "_checkbox";
211     t.rendNodeLabel.id = t.rendNode.id + "_label";
212     t.rendNodeLabel.setAttribute("for", t.rendNodeCheckbox.id);
213 
214     // 2. Set parents[2] (string|function) as label of the checkbox element.
215     // abstract.js selects the correct DOM element for the update
216     t.setText(parents[2]);
217 
218     // This sets the font-size of the checkbox itself
219     t.visPropOld.fontsize = '0px';
220     board.renderer.updateTextStyle(t, false);
221 
222     t.rendNodeCheckbox.checked = attr.checked;
223 
224     t._value = attr.checked;
225 
226     /**
227      * Returns the value of the checkbox element
228      * @name Value
229      * @memberOf Checkbox.prototype
230      * @function
231      * @returns {String} value of the checkbox.
232      */
233     t.Value = function () {
234         return this._value;
235     };
236 
237      /**
238      * @class
239      * @ignore
240      */
241     t.update = function () {
242         if (this.needsUpdate) {
243             JXG.Text.prototype.update.call(this);
244             this._value = this.rendNodeCheckbox.checked;
245         }
246         return this;
247     };
248 
249     Env.addEvent(t.rendNodeCheckbox, "change", priv.CheckboxChangeEventHandler, t);
250 
251     return t;
252 };
253 
254 JXG.registerElement("checkbox", JXG.createCheckbox);
255 
256 // export default {
257 //     createCheckbox: JXG.createCheckbox
258 // };
259