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