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