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,function} 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 must be given as string. 80 * <p> 81 * The label of the input element may be given as string or function. 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 // 1. Create input element with empty label 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 // 2. Set parents[3] (string|function) as label of the input element. 156 // abstract.js selects the correct DOM element for the update 157 t.setText(parents[3]); 158 159 t._value = parents[2]; 160 t.update = function () { 161 if (this.needsUpdate) { 162 JXG.Text.prototype.update.call(this); 163 this._value = this.rendNodeInput.value; 164 } 165 return this; 166 }; 167 168 /** 169 * Returns the value (content) of the input element 170 * @name Value 171 * @memberOf Input.prototype 172 * @function 173 * @returns {String} content of the input field. 174 */ 175 t.Value = function () { 176 return this._value; 177 }; 178 179 /** 180 * Sets value of the input element. 181 * @name set 182 * @memberOf Input.prototype 183 * @function 184 * 185 * @param {String} val 186 * @returns {JXG.GeometryElement} Reference to the element. 187 * 188 * @example 189 * var i1 = board.create('input', [-3, 4, 'sin(x)', 'f(x)='], {cssStyle: 'width:4em', maxlength: 2}); 190 * var c1 = board.create('checkbox', [-3, 2, 'label 1'], {}); 191 * var b1 = board.create('button', [-3, -1, 'Change texts', function () { 192 * i1.setText('g(x)'); 193 * i1.set('cos(x)'); 194 * c1.setText('label 2'); 195 * b1.setText('Texts are changed'); 196 * }], 197 * {cssStyle: 'width:400px'}); 198 * 199 * </pre><div id="JXG11cac8ff-2354-47e7-9da4-eb298e53de05" class="jxgbox" style="width: 300px; height: 300px;"></div> 200 * <script type="text/javascript"> 201 * (function() { 202 * var board = JXG.JSXGraph.initBoard('JXG11cac8ff-2354-47e7-9da4-eb298e53de05', 203 * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); 204 * var i1 = board.create('input', [-3, 4, 'sin(x)', 'f(x)='], {cssStyle: 'width:4em', maxlength: 2}); 205 * var c1 = board.create('checkbox', [-3, 2, 'label 1'], {}); 206 * var b1 = board.create('button', [-3, -1, 'Change texts', function () { 207 * i1.setText('g(x)'); 208 * i1.set('cos(x)'); 209 * c1.setText('label 2'); 210 * b1.setText('Texts are changed'); 211 * }], 212 * {cssStyle: 'width:400px'}); 213 * 214 * })(); 215 * 216 * </script><pre> 217 * 218 */ 219 t.set = function (val) { 220 this._value = val; 221 this.rendNodeInput.value = val; 222 return this; 223 }; 224 225 Env.addEvent(t.rendNodeInput, 'input', priv.InputInputEventHandler, t); 226 Env.addEvent(t.rendNodeInput, 'mousedown', function(evt) { if (Type.exists(evt.stopPropagation)) { evt.stopPropagation(); } }, t); 227 Env.addEvent(t.rendNodeInput, 'touchstart', function(evt) { if (Type.exists(evt.stopPropagation)) { evt.stopPropagation(); } }, t); 228 Env.addEvent(t.rendNodeInput, 'pointerdown', function(evt) { if (Type.exists(evt.stopPropagation)) { evt.stopPropagation(); } }, t); 229 230 // This sets the font-size of the input HTML element 231 t.visPropOld.fontsize = "0px"; 232 board.renderer.updateTextStyle(t, false); 233 234 return t; 235 }; 236 237 JXG.registerElement('input', JXG.createInput); 238 239 return { 240 createInput: JXG.createInput 241 }; 242 }); 243