      1 /*
      2     Copyright 2008-2022
      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      * </script><pre>
    166      *
    167      * @example
    168      *         var i1 = board.create('input', [-3, 4, 'sin(x)', 'f(x)='], {cssStyle: 'width:4em', maxlength: 2});
    169      *         var c1 = board.create('checkbox', [-3, 2, 'label 1'], {});
    170      *         var b1 = board.create('button', [-3, -1, 'Change texts', function () {
    171      *                 i1.setText('g(x)');
    172      *                 i1.set('cos(x)');
    173      *                 c1.setText('label 2');
    174      *                 b1.setText('Texts are changed');
    175      *             }],
    176      *             {cssStyle: 'width:400px'});
    177      *
    178      * </pre><div id="JXG11cac8ff-2354-47e7-9da4-eb928e53de05" class="jxgbox" style="width: 300px; height: 300px;"></div>
    179      * <script type="text/javascript">
    180      *     (function() {
    181      *         var board = JXG.JSXGraph.initBoard('JXG11cac8ff-2354-47e7-9da4-eb928e53de05',
    182      *             {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});
    183      *             var i1 = board.create('input', [-3, 4, 'sin(x)', 'f(x)='], {cssStyle: 'width:4em', maxlength: 2});
    184      *             var c1 = board.create('checkbox', [-3, 2, 'label 1'], {});
    185      *             var b1 = board.create('button', [-3, -1, 'Change texts', function () {
    186      *                     i1.setText('g(x)');
    187      *                     i1.set('cos(x)');
    188      *                     c1.setText('label 2');
    189      *                     b1.setText('Texts are changed');
    190      *                 }],
    191      *                 {cssStyle: 'width:400px'});
    192      *
    193      *     })();
    194      *
    195      * </script><pre>
    196      *
    197      */
    198     JXG.createButton = function (board, parents, attributes) {
    199         var t, par,
    200             attr = Type.copyAttributes(attributes, board.options, 'button');
    201
    202         //if (parents.length < 3) {
    203             //throw new Error("JSXGraph: Can't create button with parent types '" +
    204             //    (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." +
    205             //    "\nPossible parents are: [x, y, label, handler]");
    206         //}
    207
    208         par = [parents[0], parents[1], '<button type="button" style="width:100%;"></button>'];
    209
    210         t = board.create('text', par, attr);
    211         t.type = Type.OBJECT_TYPE_BUTTON;
    212
    213         t.rendNodeButton = t.rendNode.childNodes[0];
    214         t.rendNodeButton.id = t.rendNode.id + '_button';
    215         t.rendNodeButton.innerHTML = parents[2];
    216
    217         t.rendNodeTag = t.rendNodeButton; // Needed for unified treatment in setAttribute
    218         t.rendNodeTag.disabled = !!attr.disabled;
    219
    220         // This sets the font-size of the button text
    221         t.visPropOld.fontsize = "0px";
    222         board.renderer.updateTextStyle(t, false);
    223
    224         if (parents[3]) {
    225             if (Type.isString(parents[3])) {
    226                 t._jc = new JXG.JessieCode();
    227                 t._jc.use(board);
    228                 t._handler = function () {
    229                     t._jc.parse(parents[3]);
    230                 };
    231             } else {
    232                 t._handler = parents[3];
    233             }
    234         }
    235
    236         Env.addEvent(t.rendNodeButton, 'click', priv.ButtonClickEventHandler, t);
    237         Env.addEvent(t.rendNodeButton, 'mousedown', function (evt) { if (Type.exists(evt.stopPropagation)) { evt.stopPropagation(); } }, t);
    238         Env.addEvent(t.rendNodeButton, 'touchstart', function (evt) { if (Type.exists(evt.stopPropagation)) { evt.stopPropagation(); } }, t);
    239         Env.addEvent(t.rendNodeButton, 'pointerdown', function (evt) { if (Type.exists(evt.stopPropagation)) { evt.stopPropagation(); } }, t);
    240
    241         return t;
    242     };
    243
    244     JXG.registerElement('button', JXG.createButton);
    245
    246     return {
    247         createButton: JXG.createButton
    248     };
    249 });
    250