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             ButtonClickEventHandler: function () {
 54                 if (this._handler) {
 55                     this._handler();
 56                 }
 57                 this.board.update();
 58             }
 59         };
 60 
 61     /**
 62      * @class This element is used to provide a constructor for special texts containing a
 63      * form button element.
 64      * <p>
 65      * For this element, the attribute "display" has to have the value 'html' (which is the default).
 66      *
 67      * @pseudo
 68      * @description
 69      * @name Button
 70      * @augments Text
 71      * @constructor
 72      * @type JXG.Text
 73      *
 74      * @param {number,function_number,function_String_function} x,y,label,handler Parent elements for button elements.
 75      *                     <p>
 76      *                     x and y are the coordinates of the lower left corner of the text box.
 77      *                      The position of the text is fixed,
 78      *                     x and y are numbers. The position is variable if x or y are functions.
 79      *                     <p>
 80      *                     The label of the input element may be given  as string.
 81      *                     <p>
 82      *                     The (optional) handler function which is called when the button is pressed.
 83      *
 84      * @example
 85      *  var p = board.create('point', [0.5, 0.5], {id: 'p1'});
 86      *
 87      *  // Create a button element at position [1,2].
 88      *  var button1 = board.create('button', [1, 2, 'Change Y with JavaScript', function() {
 89      *      p.moveTo([p.X(), p.Y() + 0.5], 100);
 90      *  }], {});
 91      *
 92      *  // Create a button element at position [1,4].
 93      *  var button2 = board.create('button', [1, 4, 'Change Y with JessieCode',
 94      *      "$('p1').Y = $('p1').Y() - 0.5;"
 95      *  ], {});
 96      *
 97      * </pre><div class="jxgbox" id="JXGf19b1bce-dd00-4e35-be97-ff1817d11514" style="width: 500px; height: 300px;"></div>
 98      * <script type="text/javascript">
 99      *  var t1_board = JXG.JSXGraph.initBoard('JXGf19b1bce-dd00-4e35-be97-ff1817d11514', {boundingbox: [-3, 6, 5, -3], axis: true, showcopyright: false, shownavigation: false});
100      *  var p = t1_board.create('point', [0, -1], {id: 'p1'});
101      *
102      *  // Create a button element at position [1,2].
103      *  var button1 = t1_board.create('button', [1, 2, 'Change Y with JavaScript', function() {
104      *      p.moveTo([p.X(), p.Y() + 0.5], 100);
105      *  }], {});
106      *
107      *  // Create a button element at position [1,4].
108      *  var button2 = t1_board.create('button', [1, 4, 'Change Y with JessieCode',
109      *      "$('p1').Y = $('p1').Y() - 0.5;"
110      *  ], {});
111      *
112      * </script><pre>
113      *
114      * @example
115      * // A toggle button
116      * var butt = board.create('button', [-2, -2, 'Off', function() {
117      *   var txt;
118      *   butt.value = !butt.value;
119      *   if (butt.value) {
120      *   	txt = 'On';
121      *   } else {
122      *   	txt = 'Off';
123      *   }
124      * 	butt.rendNodeButton.innerHTML = txt;
125      * }]);
126      * 
127      * // Set initial value for the button
128      * if (!JXG.exists(butt.value)) {
129      * 	butt.value = false;
130      * }
131      * 
132      * var p = board.create('point', [2, -2], {
133      * 	visible: () => butt.value
134      * });
135      * 
136      * 
137      * 
138      * </pre><div id="JXGa1eaab8f-c73b-4660-96ce-4ca17bcac4d6" class="jxgbox" style="width: 300px; height: 300px;"></div>
139      * <script type="text/javascript">
140      *     (function() {
141      *         var board = JXG.JSXGraph.initBoard('JXGa1eaab8f-c73b-4660-96ce-4ca17bcac4d6',
142      *             {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});
143      *     var butt = board.create('button', [-2, -2, 'Off', function() {
144      *       var txt;
145      *       butt.value = !butt.value;
146      *       if (butt.value) {
147      *       	txt = 'On';
148      *       } else {
149      *       	txt = 'Off';
150      *       }
151      *     	butt.rendNodeButton.innerHTML = txt;
152      *     }]);
153      *     
154      *     // Set initial value for the button
155      *     if (!JXG.exists(butt.value)) {
156      *     	butt.value = false;
157      *     }
158      *     
159      *     var p = board.create('point', [2, -2], {
160      *     	visible: () => butt.value
161      *     });
162      *     
163      *     
164      * 
165      *     })();
166      * 
167      * </script><pre>
168      * 
169      */
170     JXG.createButton = function (board, parents, attributes) {
171         var t, par,
172             attr = Type.copyAttributes(attributes, board.options, 'button');
173 
174         //if (parents.length < 3) {
175             //throw new Error("JSXGraph: Can't create button with parent types '" +
176             //    (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
177             //    "\nPossible parents are: [x, y, label, handler]");
178         //}
179 
180         par = [parents[0], parents[1], '<button type="button" style="width:100%;"></button>'];
181 
182         t = board.create('text', par, attr);
183         t.type = Type.OBJECT_TYPE_BUTTON;
184 
185         t.rendNodeButton = t.rendNode.childNodes[0];
186         t.rendNodeButton.id = t.rendNode.id + '_button';
187         t.rendNodeButton.innerHTML = parents[2];
188 
189         t.rendNodeTag = t.rendNodeButton; // Needed for unified treatment in setAttribute
190         t.rendNodeTag.disabled = !!attr.disabled;
191 
192         // This sets the font-size of the button text
193         t.visPropOld.fontsize = "0px";
194         board.renderer.updateTextStyle(t, false);
195 
196         if (parents[3]) {
197             if (Type.isString(parents[3])) {
198                 t._jc = new JXG.JessieCode();
199                 t._jc.use(board);
200                 t._handler = function () {
201                     t._jc.parse(parents[3]);
202                 };
203             } else {
204                 t._handler = parents[3];
205             }
206         }
207 
208         Env.addEvent(t.rendNodeButton, 'click', priv.ButtonClickEventHandler, t);
209 
210         Env.addEvent(t.rendNodeButton, 'mousedown', function (evt) { if (Type.exists(evt.stopPropagation)) { evt.stopPropagation(); } }, t);
211         Env.addEvent(t.rendNodeButton, 'touchstart', function (evt) { if (Type.exists(evt.stopPropagation)) { evt.stopPropagation(); } }, t);
212         Env.addEvent(t.rendNodeButton, 'pointerdown', function (evt) { if (Type.exists(evt.stopPropagation)) { evt.stopPropagation(); } }, t);
213 
214         return t;
215     };
216 
217     JXG.registerElement('button', JXG.createButton);
218 
219     return {
220         createButton: JXG.createButton
221     };
222 });
223