1 /* 2 Copyright 2008-2026 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.js"; 40 import Env from "../utils/env.js"; 41 import Text from "../base/text.js"; 42 import Type from "../utils/type.js"; 43 44 var priv = { 45 ButtonClickEventHandler: function () { 46 if (this._handler) { 47 this._handler(); 48 } 49 this.board.update(); 50 } 51 }; 52 53 /** 54 * @class A text element that contains an HTML button tag. 55 * For this element, the attribute "display" has to have the value 'html' (which is the default). 56 * 57 * <p><b>Setting a CSS class:</b> The attribute <tt>cssClass</tt> affects the HTML div element that contains the button element. To change the CSS properties of the HTML button element a selector of the form 58 * <tt>.mybutton > button { ... }</tt> has to be used. See the example below. 59 * 60 * <p><b>Access the button element with JavaScript:</b> 61 * The underlying HTML button element can be accessed through the sub-object 'rendNodeButton', e.g. to 62 * add event listeners. 63 * 64 * @pseudo 65 * @name Button 66 * @augments Text 67 * @constructor 68 * @type JXG.Text 69 * 70 * @param {number,function_number,function_String,function_function} x,y,label,handler Parent elements for button elements. 71 * <p> 72 * x and y are the coordinates of the lower left corner of the text box. 73 * The position of the text is fixed, 74 * x and y are numbers. The position is variable if x or y are functions. 75 * <p> 76 * The label of the input element may be given as string. 77 * <p> 78 * The (optional) handler function which is called when the button is pressed. 79 * 80 * @example 81 * var p = board.create('point', [0.5, 0.5], {id: 'p1'}); 82 * 83 * // Create a button element at position [1,2]. 84 * var button1 = board.create('button', [1, 2, 'Change Y with JavaScript', function() { 85 * p.moveTo([p.X(), p.Y() + 0.5], 100); 86 * }], {}); 87 * 88 * // Create a button element at position [1,4]. 89 * var button2 = board.create('button', [1, 4, 'Change Y with JessieCode', 90 * "$('p1').Y = $('p1').Y() - 0.5;" 91 * ], {}); 92 * 93 * </pre><div class="jxgbox" id="JXGf19b1bce-dd00-4e35-be97-ff1817d11514" style="width: 500px; height: 300px;"></div> 94 * <script type="text/javascript"> 95 * var t1_board = JXG.JSXGraph.initBoard('JXGf19b1bce-dd00-4e35-be97-ff1817d11514', {boundingbox: [-3, 6, 5, -3], axis: true, showcopyright: false, shownavigation: false}); 96 * var p = t1_board.create('point', [0, -1], {id: 'p1'}); 97 * 98 * // Create a button element at position [1,2]. 99 * var button1 = t1_board.create('button', [1, 2, 'Change Y with JavaScript', function() { 100 * p.moveTo([p.X(), p.Y() + 0.5], 100); 101 * }], {}); 102 * 103 * // Create a button element at position [1,4]. 104 * var button2 = t1_board.create('button', [1, 4, 'Change Y with JessieCode', 105 * "$('p1').Y = $('p1').Y() - 0.5;" 106 * ], {}); 107 * 108 * </script><pre> 109 * 110 * @example 111 * // A toggle button 112 * var butt = board.create('button', [-2, -2, 'Off', function() { 113 * var txt; 114 * butt.value = !butt.value; 115 * if (butt.value) { 116 * txt = 'On'; 117 * } else { 118 * txt = 'Off'; 119 * } 120 * butt.rendNodeButton.innerHTML = txt; 121 * }]); 122 * 123 * // Set initial value for the button 124 * if (!JXG.exists(butt.value)) { 125 * butt.value = false; 126 * } 127 * 128 * var p = board.create('point', [2, -2], { 129 * visible: () => butt.value 130 * }); 131 * 132 * 133 * 134 * </pre><div id="JXGa1eaab8f-c73b-4660-96ce-4ca17bcac4d6" class="jxgbox" style="width: 300px; height: 300px;"></div> 135 * <script type="text/javascript"> 136 * (function() { 137 * var board = JXG.JSXGraph.initBoard('JXGa1eaab8f-c73b-4660-96ce-4ca17bcac4d6', 138 * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); 139 * var butt = board.create('button', [-2, -2, 'Off', function() { 140 * var txt; 141 * butt.value = !butt.value; 142 * if (butt.value) { 143 * txt = 'On'; 144 * } else { 145 * txt = 'Off'; 146 * } 147 * butt.rendNodeButton.innerHTML = txt; 148 * }]); 149 * 150 * // Set initial value for the button 151 * if (!JXG.exists(butt.value)) { 152 * butt.value = false; 153 * } 154 * 155 * var p = board.create('point', [2, -2], { 156 * visible: () => butt.value 157 * }); 158 * 159 * })(); 160 * 161 * </script><pre> 162 * 163 * @example 164 * var i1 = board.create('input', [-3, 4, 'sin(x)', 'f(x)='], {cssStyle: 'width:4em', maxlength: 2}); 165 * var c1 = board.create('checkbox', [-3, 2, 'label 1'], {}); 166 * var b1 = board.create('button', [-3, -1, 'Change texts', function () { 167 * i1.setText('g(x)'); 168 * i1.set('cos(x)'); 169 * c1.setText('label 2'); 170 * b1.setText('Texts are changed'); 171 * }], 172 * {cssStyle: 'width:200px'}); 173 * 174 * </pre><div id="JXG11cac8ff-2354-47e7-9da4-eb928e53de05" class="jxgbox" style="width: 300px; height: 300px;"></div> 175 * <script type="text/javascript"> 176 * (function() { 177 * var board = JXG.JSXGraph.initBoard('JXG11cac8ff-2354-47e7-9da4-eb928e53de05', 178 * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); 179 * var i1 = board.create('input', [-3, 4, 'sin(x)', 'f(x)='], {cssStyle: 'width:4em', maxlength: 2}); 180 * var c1 = board.create('checkbox', [-3, 2, 'label 1'], {}); 181 * var b1 = board.create('button', [-3, -1, 'Change texts', function () { 182 * i1.setText('g(x)'); 183 * i1.set('cos(x)'); 184 * c1.setText('label 2'); 185 * b1.setText('Texts are changed'); 186 * }], 187 * {cssStyle: 'width:200px'}); 188 * 189 * })(); 190 * 191 * </script><pre> 192 * 193 * @example 194 * // Set the CSS class of the button 195 * 196 * // CSS: 197 * <style> 198 * .mybutton > button { 199 * background-color: #04AA6D; 200 * border: none; 201 * color: white; 202 * padding: 1px 3px; 203 * text-align: center; 204 * text-decoration: none; 205 * display: inline-block; 206 * font-size: 16px; 207 * } 208 * </style> 209 * 210 * // JavaScript: 211 * var button = board.create('button', 212 * [1, 4, 'answers', function () {}], 213 * {cssClass:'mybutton', highlightCssClass: 'mybutton'}); 214 * 215 * </pre> 216 * <style> 217 * .mybutton > button { 218 * background-color: #04AA6D; 219 * border: none; 220 * color: white; 221 * padding: 1px 3px; 222 * text-align: center; 223 * text-decoration: none; 224 * display: inline-block; 225 * font-size: 16px; 226 * } 227 * </style> 228 * <div id="JXG2da6cf73-8c2e-495c-bd31-42de43b71cf8" class="jxgbox" style="width: 300px; height: 300px;"></div> 229 * <script type="text/javascript"> 230 * (function() { 231 * var board = JXG.JSXGraph.initBoard('JXG2da6cf73-8c2e-495c-bd31-42de43b71cf8', 232 * {boundingbox: [-8, 8, 8,-8], axis: true, showcopyright: false, shownavigation: false}); 233 * var button = board.create('button', [1, 4, 'answers', function () { 234 * }], {cssClass:'mybutton', highlightCssClass: 'mybutton'}); 235 * 236 * })(); 237 * 238 * </script><pre> 239 * 240 */ 241 JXG.createButton = function (board, parents, attributes) { 242 var t, 243 par, 244 setTextBackup, 245 attr = Type.copyAttributes(attributes, board.options, 'button'); 246 247 //if (parents.length < 3) { 248 //throw new Error("JSXGraph: Can't create button with parent types '" + 249 // (typeof parents[0]) + "' and '" + (typeof parents[1]) + "'." + 250 // "\nPossible parents are: [x, y, label, handler]"); 251 //} 252 253 // Make sure the setText method is the original one. The JessieCode parser changes it during parsing. 254 setTextBackup = Text.prototype.setText; 255 Text.prototype.setText = Text.prototype._setText; 256 257 // 1. Create empty button 258 par = [parents[0], parents[1], '<button type="button" style="width:100%; height:100%;" tabindex="0"></button>']; 259 t = board.create("text", par, attr); 260 t.type = Type.OBJECT_TYPE_BUTTON; 261 262 // Restore whichever setText method was set before this contructor was called. 263 Text.prototype.setText = setTextBackup; 264 265 t.rendNodeButton = t.rendNode.childNodes[0]; 266 t.rendNodeButton.id = t.rendNode.id + "_button"; 267 268 t.rendNodeTag = t.rendNodeButton; // Needed for unified treatment in setAttribute 269 t.rendNodeTag.disabled = !!attr.disabled; 270 271 // 2. Set parents[2] (string|function) as content of the button. 272 // abstract.js selects the correct DOM element for the update 273 t.setText(parents[2]); 274 275 // This sets the font size of the button text 276 t.visPropOld.fontsize = '0px'; 277 board.renderer.updateTextStyle(t, false); 278 279 if (parents[3]) { 280 if (Type.isString(parents[3])) { 281 t._jc = new JXG.JessieCode(); 282 t._jc.use(board); 283 t._handler = function () { 284 t._jc.parse(parents[3]); 285 }; 286 } else { 287 t._handler = parents[3]; 288 } 289 } 290 291 Env.addEvent(t.rendNodeButton, "click", priv.ButtonClickEventHandler, t); 292 Env.addEvent( 293 t.rendNodeButton, 294 "mousedown", 295 function (evt) { 296 if (Type.exists(evt.stopPropagation)) { 297 evt.stopPropagation(); 298 } 299 }, 300 t 301 ); 302 Env.addEvent( 303 t.rendNodeButton, 304 "touchstart", 305 function (evt) { 306 if (Type.exists(evt.stopPropagation)) { 307 evt.stopPropagation(); 308 } 309 }, 310 t 311 ); 312 Env.addEvent( 313 t.rendNodeButton, 314 "pointerdown", 315 function (evt) { 316 if (Type.exists(evt.stopPropagation)) { 317 evt.stopPropagation(); 318 } 319 }, 320 t 321 ); 322 323 return t; 324 }; 325 326 JXG.registerElement("button", JXG.createButton); 327 328 // export default { 329 // createButton: JXG.createButton 330 // }; 331