      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             InputInputEventHandler: function (evt) {
     54                 this._value = this.rendNodeInput.value;
     55                 this.board.update();
     56             }
     57         };
     58
     59     /**
     60      * @class This element is used to provide a constructor for special texts containing a
     61      * HTML form input element.
     62      * <p>
     63      * If the width of element is set with the attribute "cssStyle", the width of the
     64      * label must be added.
     65      * <p>
     66      * For this element, the attribute "display" has to have the value 'html' (which is the default).
     67      * @pseudo
     68      * @description
     69      * @name Input
     70      * @augments Text
     71      * @constructor
     72      * @type JXG.Text
     73      *
     74      * @param {number,function_number,function_String_String} x,y,value,label Parent elements for input elements.
     75      *                     <p>
     76      *                     x and y are the coordinates of the lower left corner of the text box. 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 default value of the input element may be given as string.
     80      *                     <p>
     81      *                     The label of the input element may be given  as string.
     82      *
     83      * @example
     84      *  // Create an input element at position [1,4].
     85      *  var input = board.create('input', [0, 1, 'sin(x)*x', 'f(x)='], {cssStyle: 'width: 100px'});
     86      *  var f = board.jc.snippet(input.Value(), true, 'x', false);
     87      *  var graph = board.create('functiongraph',[f,
     88      *          function() {
     89      *            var c = new JXG.Coords(JXG.COORDS_BY_SCREEN,[0,0],board);
     90      *            return c.usrCoords[1];
     91      *          },
     92      *          function() {
     93      *            var c = new JXG.Coords(JXG.COORDS_BY_SCREEN,[board.canvasWidth,0],board);
     94      *            return c.usrCoords[1];
     95      *          }
     96      *        ]);
     97      *
     98      *  board.create('text', [1, 3, '<button onclick="updateGraph()">Update graph</button>']);
     99      *
    100      *  var updateGraph = function() {
    101      *      graph.Y = board.jc.snippet(input.Value(), true, 'x', false);
    102      *      graph.updateCurve();
    103      *      board.update();
    104      *  }
    105      * </pre><div class="jxgbox" id="JXGc70f55f1-21ba-4719-a37d-a93ae2943faa" style="width: 500px; height: 300px;"></div>
    106      * <script type="text/javascript">
    107      *   var t1_board = JXG.JSXGraph.initBoard('JXGc70f55f1-21ba-4719-a37d-a93ae2943faa', {boundingbox: [-3, 6, 5, -3], axis: true, showcopyright: false, shownavigation: false});
    108      *   var input = t1_board.create('input', [1, 4, 'sin(x)*x', 'f(x)='], {cssStyle: 'width: 100px'});
    109      *   var f = t1_board.jc.snippet(input.Value(), true, 'x', false);
    110      *   var graph = t1_board.create('functiongraph',[f,
    111      *          function() {
    112      *            var c = new JXG.Coords(JXG.COORDS_BY_SCREEN,[0,0],t1_board);
    113      *            return c.usrCoords[1];
    114      *          },
    115      *          function() {
    116      *            var c = new JXG.Coords(JXG.COORDS_BY_SCREEN,[t1_board.canvasWidth,0],t1_board);
    117      *            return c.usrCoords[1];
    118      *          }
    119      *        ]);
    120      *
    121      *  t1_board.create('text', [1, 3, '<button onclick="updateGraph()">Update graph</button>']);
    122      *
    123      *  var updateGraph = function() {
    124      *      graph.Y = t1_board.jc.snippet(input.Value(), true, 'x', false);
    125      *      graph.updateCurve();
    126      *      t1_board.update();
    127      *  }
    128      * </script><pre>
    129      */
    130     JXG.createInput = function (board, parents, attributes) {
    131         var t, par,
    132             attr = Type.copyAttributes(attributes, board.options, 'input');
    133
    134         par = [parents[0], parents[1],
    135             '<span style="display:inline; white-space:nowrap; padding:0px;">' +
    136             '<span></span><input type="text" maxlength="' +
    137                 attr.maxlength +
    138                 '" style="width:100%"/>' +
    139             '</span>'
    140             ];
    141
    142         //t = JXG.createText(board, par, attr);
    143         t = board.create('text', par, attr);
    144         t.type = Type.OBJECT_TYPE_INPUT;
    145
    146         t.rendNodeLabel = t.rendNode.childNodes[0].childNodes[0];
    147         t.rendNodeInput = t.rendNode.childNodes[0].childNodes[1];
    148         t.rendNodeLabel.innerHTML = parents[3];
    149         t.rendNodeInput.value = parents[2];
    150         t.rendNodeTag = t.rendNodeInput; // Needed for unified treatment in setAttribute
    151         t.rendNodeTag.disabled = !!attr.disabled;
    152         t.rendNodeLabel.id = t.rendNode.id + '_label';
    153         t.rendNodeInput.id = t.rendNode.id + '_input';
    154
    155         t._value = parents[2];
    156         t.update = function () {
    157             if (this.needsUpdate) {
    158                 JXG.Text.prototype.update.call(this);
    159                 this._value = this.rendNodeInput.value;
    160             }
    161             return this;
    162         };
    163
    164         /**
    165          * Returns the value (content) of the input element
    166          * @name Value
    167          * @memberOf Input.prototype
    168          * @function
    169          * @returns {String} content of the input field.
    170          */
    171         t.Value = function () {
    172             return this._value;
    173         };
    174
    175         /**
    176          * Sets value of the input element.
    177          * @name set
    178          * @memberOf Input.prototype
    179          * @function
    180          *
    181          * @param {String} val
    182          * @returns {JXG.GeometryElement} Reference to the element.
    183          *
    184          * @example
    185          *         var i1 = board.create('input', [-3, 4, 'sin(x)', 'f(x)='], {cssStyle: 'width:4em', maxlength: 2});
    186          *         var c1 = board.create('checkbox', [-3, 2, 'label 1'], {});
    187          *         var b1 = board.create('button', [-3, -1, 'Change texts', function () {
    188          *                 i1.setText('g(x)');
    189          *                 i1.set('cos(x)');
    190          *                 c1.setText('label 2');
    191          *                 b1.setText('Texts are changed');
    192          *             }],
    193          *             {cssStyle: 'width:400px'});
    194          *
    195          * </pre><div id="JXG11cac8ff-2354-47e7-9da4-eb298e53de05" class="jxgbox" style="width: 300px; height: 300px;"></div>
    196          * <script type="text/javascript">
    197          *     (function() {
    198          *         var board = JXG.JSXGraph.initBoard('JXG11cac8ff-2354-47e7-9da4-eb298e53de05',
    199          *             {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false});
    200          *             var i1 = board.create('input', [-3, 4, 'sin(x)', 'f(x)='], {cssStyle: 'width:4em', maxlength: 2});
    201          *             var c1 = board.create('checkbox', [-3, 2, 'label 1'], {});
    202          *             var b1 = board.create('button', [-3, -1, 'Change texts', function () {
    203          *                     i1.setText('g(x)');
    204          *                     i1.set('cos(x)');
    205          *                     c1.setText('label 2');
    206          *                     b1.setText('Texts are changed');
    207          *                 }],
    208          *                 {cssStyle: 'width:400px'});
    209          *
    210          *     })();
    211          *
    212          * </script><pre>
    213          *
    214          */
    215         t.set = function (val) {
    216             this._value = val;
    217             this.rendNodeInput.value = val;
    218             return this;
    219         };
    220
    221         Env.addEvent(t.rendNodeInput, 'input', priv.InputInputEventHandler, t);
    222         Env.addEvent(t.rendNodeInput, 'mousedown', function(evt) { if (Type.exists(evt.stopPropagation)) { evt.stopPropagation(); } }, t);
    223         Env.addEvent(t.rendNodeInput, 'touchstart', function(evt) { if (Type.exists(evt.stopPropagation)) { evt.stopPropagation(); } }, t);
    224         Env.addEvent(t.rendNodeInput, 'pointerdown', function(evt) { if (Type.exists(evt.stopPropagation)) { evt.stopPropagation(); } }, t);
    225
    226         // This sets the font-size of the input HTML element
    227         t.visPropOld.fontsize = "0px";
    228         board.renderer.updateTextStyle(t, false);
    229
    230         return t;
    231     };
    232
    233     JXG.registerElement('input', JXG.createInput);
    234
    235     return {
    236         createInput: JXG.createInput
    237     };
    238 });
    239