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     ButtonClickEventHandler: function () {
 45         if (this._handler) {
 46             this._handler();
 47         }
 48         this.board.update();
 49     }
 50 };
 51 
 52 /**
 53  * @class This element is used to provide a constructor for special texts containing a
 54  * form button element.
 55  * <p>
 56  * For this element, the attribute "display" has to have the value 'html' (which is the default).
 57  * <p>
 58  * The underlying HTML button element can be accessed through the sub-object 'rendNodeButton', e.g. to
 59  * add event listeners.
 60  *
 61  * @pseudo
 62  * @description
 63  * @name Button
 64  * @augments Text
 65  * @constructor
 66  * @type JXG.Text
 67  *
 68  * @param {number,function_number,function_String,function_function} x,y,label,handler Parent elements for button elements.
 69  *  <p>
 70  *  x and y are the coordinates of the lower left corner of the text box.
 71  *   The position of the text is fixed,
 72  *  x and y are numbers. The position is variable if x or y are functions.
 73  *  <p>
 74  *  The label of the input element may be given  as string.
 75  *  <p>
 76  *  The (optional) handler function which is called when the button is pressed.
 77  *
 78  * @example
 79  *  var p = board.create('point', [0.5, 0.5], {id: 'p1'});
 80  *
 81  *  // Create a button element at position [1,2].
 82  *  var button1 = board.create('button', [1, 2, 'Change Y with JavaScript', function() {
 83  *      p.moveTo([p.X(), p.Y() + 0.5], 100);
 84  *  }], {});
 85  *
 86  *  // Create a button element at position [1,4].
 87  *  var button2 = board.create('button', [1, 4, 'Change Y with JessieCode',
 88  *      "$('p1').Y = $('p1').Y() - 0.5;"
 89  *  ], {});
 90  *
 91  * </pre><div class="jxgbox" id="JXGf19b1bce-dd00-4e35-be97-ff1817d11514" style="width: 500px; height: 300px;"></div>
 92  * <script type="text/javascript">
 93  *  var t1_board = JXG.JSXGraph.initBoard('JXGf19b1bce-dd00-4e35-be97-ff1817d11514', {boundingbox: [-3, 6, 5, -3], axis: true, showcopyright: false, shownavigation: false});
 94  *  var p = t1_board.create('point', [0, -1], {id: 'p1'});
 95  *
 96  *  // Create a button element at position [1,2].
 97  *  var button1 = t1_board.create('button', [1, 2, 'Change Y with JavaScript', function() {
 98  *      p.moveTo([p.X(), p.Y() + 0.5], 100);
 99  *  }], {});
100  *
101  *  // Create a button element at position [1,4].
102  *  var button2 = t1_board.create('button', [1, 4, 'Change Y with JessieCode',
103  *      "$('p1').Y = $('p1').Y() - 0.5;"
104  *  ], {});
105  *
106  * </script><pre>
107  *
108  * @example
109  * // A toggle button
110  * var butt = board.create('button', [-2, -2, 'Off', function() {
111  *   var txt;
112  *   butt.value = !butt.value;
113  *   if (butt.value) {
114  *   	txt = 'On';
115  *   } else {
116  *   	txt = 'Off';
117  *   }
118  * 	butt.rendNodeButton.innerHTML = txt;
119  * }]);
120  *
121  * // Set initial value for the button
122  * if (!JXG.exists(butt.value)) {
123  * 	butt.value = false;
124  * }
125  *
126  * var p = board.create('point', [2, -2], {
127  * 	visible: () => butt.value
128  * });
129  *
130  *
131  *
132  * </pre><div id="JXGa1eaab8f-c73b-4660-96ce-4ca17bcac4d6" class="jxgbox" style="width: 300px; height: 300px;"></div>
133  * <script type="text/javascript">
134  *     (function() {
135  *         var board = JXG.JSXGraph.initBoard('JXGa1eaab8f-c73b-4660-96ce-4ca17bcac4d6',
136  *             {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});
137  *     var butt = board.create('button', [-2, -2, 'Off', function() {
138  *       var txt;
139  *       butt.value = !butt.value;
140  *       if (butt.value) {
141  *       	txt = 'On';
142  *       } else {
143  *       	txt = 'Off';
144  *       }
145  *     	butt.rendNodeButton.innerHTML = txt;
146  *     }]);
147  *
148  *     // Set initial value for the button
149  *     if (!JXG.exists(butt.value)) {
150  *     	butt.value = false;
151  *     }
152  *
153  *     var p = board.create('point', [2, -2], {
154  *     	visible: () => butt.value
155  *     });
156  *
157  *     })();
158  *
159  * </script><pre>
160  *
161  * @example
162  *         var i1 = board.create('input', [-3, 4, 'sin(x)', 'f(x)='], {cssStyle: 'width:4em', maxlength: 2});
163  *         var c1 = board.create('checkbox', [-3, 2, 'label 1'], {});
164  *         var b1 = board.create('button', [-3, -1, 'Change texts', function () {
165  *                 i1.setText('g(x)');
166  *                 i1.set('cos(x)');
167  *                 c1.setText('label 2');
168  *                 b1.setText('Texts are changed');
169  *             }],
170  *             {cssStyle: 'width:400px'});
171  *
172  * </pre><div id="JXG11cac8ff-2354-47e7-9da4-eb928e53de05" class="jxgbox" style="width: 300px; height: 300px;"></div>
173  * <script type="text/javascript">
174  *     (function() {
175  *         var board = JXG.JSXGraph.initBoard('JXG11cac8ff-2354-47e7-9da4-eb928e53de05',
176  *             {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});
177  *             var i1 = board.create('input', [-3, 4, 'sin(x)', 'f(x)='], {cssStyle: 'width:4em', maxlength: 2});
178  *             var c1 = board.create('checkbox', [-3, 2, 'label 1'], {});
179  *             var b1 = board.create('button', [-3, -1, 'Change texts', function () {
180  *                     i1.setText('g(x)');
181  *                     i1.set('cos(x)');
182  *                     c1.setText('label 2');
183  *                     b1.setText('Texts are changed');
184  *                 }],
185  *                 {cssStyle: 'width:400px'});
186  *
187  *     })();
188  *
189  * </script><pre>
190  *
191  */
192 JXG.createButton = function (board, parents, attributes) {
193     var t,
194         par,
195         attr = Type.copyAttributes(attributes, board.options, "button");
196 
197     //if (parents.length < 3) {
198     //throw new Error("JSXGraph: Can't create button with parent types '" +
199     //    (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
200     //    "\nPossible parents are: [x, y, label, handler]");
201     //}
202 
203     // 1. Create empty button
204     par = [parents[0], parents[1], '<button type="button" style="width:100%;"></button>'];
205     t = board.create("text", par, attr);
206     t.type = Type.OBJECT_TYPE_BUTTON;
207 
208     t.rendNodeButton = t.rendNode.childNodes[0];
209     t.rendNodeButton.id = t.rendNode.id + "_button";
210     // t.rendNodeButton.innerHTML = parents[2];
211 
212     t.rendNodeTag = t.rendNodeButton; // Needed for unified treatment in setAttribute
213     t.rendNodeTag.disabled = !!attr.disabled;
214 
215     // 2. Set parents[2] (string|function) as content of the button.
216     // abstract.js selects the correct DOM element for the update
217     t.setText(parents[2]);
218 
219     // This sets the font-size of the button text
220     t.visPropOld.fontsize = "0px";
221     board.renderer.updateTextStyle(t, false);
222 
223     if (parents[3]) {
224         if (Type.isString(parents[3])) {
225             t._jc = new JXG.JessieCode();
226             t._jc.use(board);
227             t._handler = function () {
228                 t._jc.parse(parents[3]);
229             };
230         } else {
231             t._handler = parents[3];
232         }
233     }
234 
235     Env.addEvent(t.rendNodeButton, "click", priv.ButtonClickEventHandler, t);
236     Env.addEvent(
237         t.rendNodeButton,
238         "mousedown",
239         function (evt) {
240             if (Type.exists(evt.stopPropagation)) {
241                 evt.stopPropagation();
242             }
243         },
244         t
245     );
246     Env.addEvent(
247         t.rendNodeButton,
248         "touchstart",
249         function (evt) {
250             if (Type.exists(evt.stopPropagation)) {
251                 evt.stopPropagation();
252             }
253         },
254         t
255     );
256     Env.addEvent(
257         t.rendNodeButton,
258         "pointerdown",
259         function (evt) {
260             if (Type.exists(evt.stopPropagation)) {
261                 evt.stopPropagation();
262             }
263         },
264         t
265     );
266 
267     return t;
268 };
269 
270 JXG.registerElement("button", JXG.createButton);
271 
272 // export default {
273 //     createButton: JXG.createButton
274 // };
275