Move parseFontFaceDescriptor to CSSPropertyParser.cpp
[chromium-blink-merge.git] / third_party / WebKit / LayoutTests / svg / carto.net / resources / comboBox.js
blob93978fc38980b555a63d8659f45f9073ed10f501
1 /*
2 Scripts to create interactive comboboxes in SVG using ECMA script
3 Copyright (C) <2006> <Andreas Neumann>
4 Version 1.2.1, 2006-10-03
5 neumann@karto.baug.ethz.ch
6 http://www.carto.net/
7 http://www.carto.net/neumann/
9 Credits:
11 ----
13 current version: 1.2.1
15 version history:
16 1.0 (2006-02-20)
17 initial version
19 1.1 (2006-05-17)
20 decoupled styling from this file, fixes event handling so people can scroll outside scroller if mouse is down (events now added to root element)
22 1.2 (2006-10-02)
23 changed internally "groupId" to "id" to make it consistent with other GUI elements, introduced "parentId" as a new constructor parameter for the same reason, introduced new methods "resize()" and "moveTo()"
25 1.2.1 (2006-10-03)
26 corrected a slight bug regarding DOM hierarchy of created elements
28 -------
31 This ECMA script library is free software; you can redistribute it and/or
32 modify it under the terms of the GNU Lesser General Public
33 License as published by the Free Software Foundation; either
34 version 2.1 of the License, or (at your option) any later version.
36 This library is distributed in the hope that it will be useful,
37 but WITHOUT ANY WARRANTY; without even the implied warranty of
38 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
39 Lesser General Public License for more details.
41 You should have received a copy of the GNU Lesser General Public
42 License along with this library (lesser_gpl.txt); if not, write to the Free Software
43 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
45 ----
47 original document site: http://www.carto.net/papers/svg/gui/combobox/
48 Please contact the author in case you want to use code or ideas commercially.
49 If you use this code, please include this copyright header, the included full
50 LGPL 2.1 text and read the terms provided in the LGPL 2.1 license
51 (http://www.gnu.org/copyleft/lesser.txt)
53 -------------------------------
55 If you wish, you can modify parameters (such as "look and feel") in the function "combobox" (constructor).
56 You can adapt colors, fonts, cellpaddings, etc.
58 -------------------------------
60 Please report bugs and send improvements to neumann@karto.baug.ethz.ch
61 If you use this control, please link to the original (http://www.carto.net/papers/svg/gui/combobox/)
62 somewhere in the source-code-comment or the "about" of your project and give credits, thanks!
66 function combobox(id,parentNode,elementsArray,width,xOffset,yOffset,cellHeight,textPadding,heightNrElements,multiple,offsetValue,textStyles,boxStyles,scrollbarStyles,smallrectStyles,highlightStyles,triangleStyles,functionToCall) {
67 var nrArguments = 18;
68 var createCombobox= true;
69 if (arguments.length == nrArguments) {
70 //get constructor variables
71 this.id = id;
72 this.parentNode = parentNode;
73 this.elementsArray = elementsArray;
74 this.width = width;
75 this.xOffset = xOffset;
76 this.yOffset = yOffset;
77 this.cellHeight = cellHeight; //cellHeight in viewBox coordinates
78 this.textPadding = textPadding; //this is relative to the left of the cell
79 this.heightNrElements = heightNrElements;
80 //check if heightNrElements is bigger than elements in the array
81 if (this.heightNrElements > this.elementsArray.length) {
82 this.heightNrElements = this.elementsArray.length;
84 this.multiple = multiple;
85 this.curLowerIndex = offsetValue;
86 //check if curLowIndex is within range
87 if (this.curLowerIndex > (this.elementsArray.length - this.heightNrElements)) {
88 this.curLowerIndex = this.elementsArray.length - this.heightNrElements;
90 this.textStyles = textStyles; //array of literals containing presentation attributes for text
91 if (!this.textStyles["font-size"]) {
92 this.textStyles["font-size"] = "11";
94 this.boxStyles = boxStyles; //array of literals containing presentation attributes for the sel box
95 if (!this.boxStyles["fill"]) {
96 this.boxStyles["fill"] = "white"; //this fill value is also used for boxes under indiv. text elements (unselected status)
98 if (!this.boxStyles["stroke"]) {
99 this.boxStyles["stroke"] = "dimgray";
101 if (!this.boxStyles["stroke-width"]) {
102 this.boxStyles["stroke-width"] = 1;
104 this.scrollbarStyles = scrollbarStyles; //array of literals containing presentation attributes for the scrollbar
105 this.smallrectStyles = smallrectStyles; //array of literals containing presentation attributes for the small rectangle next to selectbox
106 this.highlightStyles = highlightStyles; //array of literals containing presentation attributes for the highlighted rectangles
107 this.triangleStyles = triangleStyles; //array of literals containing presentation attributes for the triangle in the selectionList, also applies to fill of scroller
108 this.functionToCall = functionToCall;
110 //calculate other values
111 this.triangleFourth = Math.round(this.cellHeight / 4); //this is only used internally
112 this.textPadding = textPadding; //this is relative to the left of the cell
113 this.textPaddingVertical = this.cellHeight - (this.cellHeight - this.textStyles["font-size"]) * 0.7; //this is relative to the top of the cell
114 this.scrollerMinHeight = this.cellHeight * 0.5; //minimal height of the scroller rect
116 //status variables
117 this.scrollStep = 0; //y-value to go for one element
118 this.scrollerHeight = 0; //height of dragable scroller bar
119 this.scrollActive = false; //determines if scrolling per up/down button is active
120 this.panY = false; //stores the y value of event
121 this.scrollCumulus = 0; //if value is less then a scrollstep we need to accumulate scroll values
122 this.scrollDir = ""; //later holds "up" and "down"
123 this.exists = true; //true means it exists, gets value false if method "removeSelectionList" is called
124 this.mouseDownStatus = false; //status that specifies if mouse is down or up on individual elements
125 this.pressedKeys = ""; //stores key events (pressed char values)
126 this.keyTimer = undefined;
127 this.svgRootHasEventListener = false; //status variable to define if svg root has key and mouseover listener or not
129 else {
130 createCombobox = false;
131 alert("Error ("+id+"): wrong nr of arguments! You have to pass over "+nrArguments+" parameters.");
133 if (createCombobox) {
134 //timer stuff
135 this.timer = new Timer(this); //a Timer instance for calling the functionToCall
136 this.timerMs = 200; //a constant of this object that is used in conjunction with the timer - functionToCall is called after 200 ms
138 //create combobox
139 var result = this.testParent();
140 if (result) {
141 //this.parentGroup = document.getElementById(this.id);
142 this.createOrUpdateCombobox();
144 else {
145 alert("could not create or reference 'parentNode' of combobox with id '"+this.id+"'");
148 else {
149 alert("Could not create combobox with id '"+id+"' due to errors in the constructor parameters");
153 //test if parent group exists or create a new group at the end of the file
154 combobox.prototype.testParent = function() {
155 //test if of type object
156 var nodeValid = false;
157 if (typeof(this.parentNode) == "object") {
158 if (this.parentNode.nodeName == "svg" || this.parentNode.nodeName == "g") {
159 this.parentGroup = this.parentNode;
160 nodeValid = true;
163 else if (typeof(this.parentNode) == "string") {
164 //first test if Windows group exists
165 if (!document.getElementById(this.parentNode)) {
166 this.parentGroup = document.createElementNS(svgNS,"g");
167 this.parentGroup.setAttributeNS(null,"id",this.parentNode);
168 document.documentElement.appendChild(this.parentGroup);
169 nodeValid = true;
171 else {
172 this.parentGroup = document.getElementById(this.parentNode);
173 nodeValid = true;
176 return nodeValid;
179 combobox.prototype.createOrUpdateCombobox = function() {
180 //check if there are more elements in the array than heightNrElements
181 if (this.heightNrElements < this.elementsArray.length) {
182 nrSelections = this.heightNrElements;
184 else {
185 nrSelections = this.elementsArray.length;
187 //calculate height
188 var comboboxHeight = this.cellHeight * nrSelections;
189 //rectangle below (only fill, stroke is added at a separate rect)
190 var created = true;
191 if (!this.rectBelowBox) {
192 this.rectBelowBox = document.createElementNS(svgNS,"rect");
193 this.rectBelowBox.setAttributeNS(null,"stroke","none");
194 created = false;
196 this.rectBelowBox.setAttributeNS(null,"x",this.xOffset);
197 this.rectBelowBox.setAttributeNS(null,"y",this.yOffset);
198 this.rectBelowBox.setAttributeNS(null,"width",this.width - this.cellHeight);
199 this.rectBelowBox.setAttributeNS(null,"height",comboboxHeight);
200 for (var attrib in this.boxStyles) {
201 if (attrib != "stroke" && attrib != "stroke-width") {
202 this.rectBelowBox.setAttributeNS(null,attrib,this.boxStyles[attrib]);
205 if (!created) {
206 this.parentGroup.appendChild(this.rectBelowBox);
208 //create temporary group for indiv. combo elements
209 var comboElementsGroupCreated = false;
210 if (this.comboElementsGroup) {
211 this.parentGroup.removeChild(this.comboElementsGroup);
212 comboElementsGroupCreated = true;
214 this.comboElementsGroup = document.createElementNS(svgNS,"g");
215 if (comboElementsGroupCreated) {
216 this.parentGroup.insertBefore(this.comboElementsGroup,this.rectAboveBox);
218 else {
219 this.parentGroup.appendChild(this.comboElementsGroup);
222 //create rectangle above combobox (only stroke)
223 created = true;
224 if (!this.rectAboveBox) {
225 this.rectAboveBox = document.createElementNS(svgNS,"rect");
226 this.rectAboveBox.setAttributeNS(null,"fill","none");
227 created = false;
229 this.rectAboveBox.setAttributeNS(null,"x",this.xOffset);
230 this.rectAboveBox.setAttributeNS(null,"y",this.yOffset);
231 this.rectAboveBox.setAttributeNS(null,"width",this.width - this.cellHeight);
232 this.rectAboveBox.setAttributeNS(null,"height",comboboxHeight);
233 for (var attrib in this.boxStyles) {
234 if (attrib != "fill") {
235 this.rectAboveBox.setAttributeNS(null,attrib,this.boxStyles[attrib]);
238 if (!created) {
239 this.parentGroup.appendChild(this.rectAboveBox);
241 //build textElements from array
242 //hold currentSelection Index to unroll list at new offset
243 for (var i=0;i<nrSelections;i++) {
244 //add rectangles to capture events
245 var node = document.createElementNS(svgNS,"rect");
246 node.setAttributeNS(null,"x",this.xOffset + this.textPadding / 2);
247 node.setAttributeNS(null,"y",this.yOffset + this.cellHeight * i);
248 node.setAttributeNS(null,"width",this.width - this.cellHeight - this.textPadding);
249 node.setAttributeNS(null,"height",this.cellHeight);
250 if (this.elementsArray[this.curLowerIndex + i].value) {
251 for (var attrib in this.highlightStyles) {
252 node.setAttributeNS(null,attrib,this.highlightStyles[attrib]);
255 else {
256 node.setAttributeNS(null,"fill",this.boxStyles["fill"]);
258 node.setAttributeNS(null,"id","selHighlightSelection_" + this.id + "_" + (i + this.curLowerIndex));
259 //add event-handler
260 node.addEventListener("mousedown", this, false);
261 node.addEventListener("mouseover", this, false);
262 node.addEventListener("mouseup", this, false);
263 this.comboElementsGroup.appendChild(node);
264 //add text-elements
265 var node = document.createElementNS(svgNS,"text");
266 node.setAttributeNS(null,"id","selTexts_" + this.id + "_" + (i + this.curLowerIndex));
267 node.setAttributeNS(null,"x",this.xOffset + this.textPadding);
268 node.setAttributeNS(null,"y",this.yOffset + this.textPaddingVertical + this.cellHeight * i);
269 node.setAttributeNS(null,"pointer-events","none");
270 var value = "";
271 for (var attrib in this.textStyles) {
272 value = this.textStyles[attrib];
273 if (attrib == "font-size") {
274 value += "px";
276 node.setAttributeNS(null,attrib,value);
278 var selectionText = document.createTextNode(this.elementsArray[this.curLowerIndex + i].key);
279 node.appendChild(selectionText);
280 this.comboElementsGroup.appendChild(node);
283 //create Scrollbar
284 if (this.heightNrElements < this.elementsArray.length) {
285 //calculate scrollstep
286 this.scrollerHeight = (this.heightNrElements / this.elementsArray.length) * (comboboxHeight - 2 * this.cellHeight);
287 if (this.scrollerHeight < this.scrollerMinHeight) {
288 this.scrollerHeight = this.scrollerMinHeight;
290 this.scrollStep = (comboboxHeight - 2 * this.cellHeight - this.scrollerHeight) / (this.elementsArray.length - this.heightNrElements);
291 //scrollbar
292 created = true;
293 if (!this.scrollbarRect) {
294 this.scrollbarRect = document.createElementNS(svgNS,"rect");
295 this.scrollbarRect.addEventListener("mousedown", this, false);
296 this.scrollbarRect.setAttributeNS(null,"id","selScrollbarRect_"+this.id);
297 created = false;
299 this.scrollbarRect.setAttributeNS(null,"x",this.xOffset + this.width - this.cellHeight);
300 this.scrollbarRect.setAttributeNS(null,"y",this.yOffset + this.cellHeight);
301 this.scrollbarRect.setAttributeNS(null,"width",this.cellHeight);
302 this.scrollbarRect.setAttributeNS(null,"height",comboboxHeight - this.cellHeight * 2);
303 for (var attrib in this.scrollbarStyles) {
304 this.scrollbarRect.setAttributeNS(null,attrib,this.scrollbarStyles[attrib]);
306 if (!created) {
307 this.parentGroup.appendChild(this.scrollbarRect);
309 //upper rectangle
310 created = true;
311 if (!this.scrollUpperRect) {
312 this.scrollUpperRect = document.createElementNS(svgNS,"rect");
313 this.scrollUpperRect.setAttributeNS(null,"id","selScrollUpperRect_"+this.id);
314 this.scrollUpperRect.addEventListener("mousedown", this, false);
315 this.scrollUpperRect.addEventListener("mouseup", this, false);
316 created = false;
318 this.scrollUpperRect.setAttributeNS(null,"x",this.xOffset + this.width - this.cellHeight);
319 this.scrollUpperRect.setAttributeNS(null,"y",this.yOffset);
320 this.scrollUpperRect.setAttributeNS(null,"width",this.cellHeight);
321 this.scrollUpperRect.setAttributeNS(null,"height",this.cellHeight);
322 for (var attrib in this.smallrectStyles) {
323 this.scrollUpperRect.setAttributeNS(null,attrib,this.smallrectStyles[attrib]);
325 if (!created) {
326 this.parentGroup.appendChild(this.scrollUpperRect);
328 //upper triangle
329 created = true;
330 if (!this.upperTriangle) {
331 this.upperTriangle = document.createElementNS(svgNS,"path");
332 this.upperTriangle.setAttributeNS(null,"pointer-events","none");
333 created = false;
335 var myPath = "M"+(this.xOffset + this.width - 3 * this.triangleFourth)+" "+(this.yOffset + 3 * this.triangleFourth)+" L"+(this.xOffset + this.width - this.triangleFourth)+" "+(this.yOffset + 3 * this.triangleFourth)+" L"+(this.xOffset + this.width - 2 * this.triangleFourth)+" "+(this.yOffset + this.triangleFourth)+" Z";
336 this.upperTriangle.setAttributeNS(null,"d",myPath);
337 for (var attrib in this.triangleStyles) {
338 this.upperTriangle.setAttributeNS(null,attrib,this.triangleStyles[attrib]);
340 if (!this.created) {
341 this.parentGroup.appendChild(this.upperTriangle);
343 //lower rectangle
344 created = true;
345 if (!this.scrollLowerRect) {
346 this.scrollLowerRect = document.createElementNS(svgNS,"rect");
347 this.scrollLowerRect.setAttributeNS(null,"id","selScrollLowerRect_" + this.id);
348 this.scrollLowerRect.addEventListener("mousedown", this, false);
349 this.scrollLowerRect.addEventListener("mouseup", this, false);
350 created = false;
352 this.scrollLowerRect.setAttributeNS(null,"x",this.xOffset + this.width - this.cellHeight);
353 this.scrollLowerRect.setAttributeNS(null,"y",this.yOffset + comboboxHeight - this.cellHeight);
354 this.scrollLowerRect.setAttributeNS(null,"width",this.cellHeight);
355 this.scrollLowerRect.setAttributeNS(null,"height",this.cellHeight);
356 for (var attrib in this.smallrectStyles) {
357 this.scrollLowerRect.setAttributeNS(null,attrib,this.smallrectStyles[attrib]);
359 if (!created) {
360 this.parentGroup.appendChild(this.scrollLowerRect);
362 //lower triangle
363 created = true;
364 if (!this.lowerTriangle) {
365 this.lowerTriangle = document.createElementNS(svgNS,"path");
366 this.lowerTriangle.setAttributeNS(null,"pointer-events","none");
367 created = false;
369 var myPath = "M"+(this.xOffset + this.width - 3 * this.triangleFourth)+" "+(this.yOffset + comboboxHeight - this.cellHeight + this.triangleFourth)+" L"+(this.xOffset + this.width - this.triangleFourth)+" "+(this.yOffset + comboboxHeight - this.cellHeight + this.triangleFourth)+" L"+(this.xOffset + this.width - 2 * this.triangleFourth)+" "+(this.yOffset + comboboxHeight - this.cellHeight + 3 * this.triangleFourth)+" Z";
370 this.lowerTriangle.setAttributeNS(null,"d",myPath);
371 for (var attrib in this.triangleStyles) {
372 this.lowerTriangle.setAttributeNS(null,attrib,this.triangleStyles[attrib]);
374 if (!created) {
375 this.parentGroup.appendChild(this.lowerTriangle);
377 //scrollerRect
378 created = true;
379 if (!this.scroller) {
380 this.scroller = document.createElementNS(svgNS,"rect");
381 this.scroller.setAttributeNS(null,"pointer-events","none");
382 this.scroller.setAttributeNS(null,"id","selScroller_"+this.id);
383 created = false;
385 this.scroller.setAttributeNS(null,"x",this.xOffset + this.width - this.cellHeight);
386 this.scroller.setAttributeNS(null,"y",this.yOffset + this.cellHeight + this.scrollStep * this.curLowerIndex);
387 this.scroller.setAttributeNS(null,"width",this.cellHeight);
388 this.scroller.setAttributeNS(null,"height",this.scrollerHeight);
389 for (var attrib in this.smallrectStyles) {
390 this.scroller.setAttributeNS(null,attrib,this.smallrectStyles[attrib]);
392 if (!created) {
393 this.parentGroup.appendChild(this.scroller);
398 combobox.prototype.handleEvent = function(evt) {
399 var el = evt.currentTarget;
400 var callerId = el.getAttributeNS(null,"id");
401 var myRegExp = new RegExp(this.id);
402 if (evt.type == "mouseover") {
403 if (myRegExp.test(callerId)) {
404 if (callerId.match(/\bselHighlightSelection_/)) {
405 if (this.mouseDownStatus) {
406 this.selectOrUnselect(evt);
407 evt.stopPropagation();
409 else {
410 if (!this.svgRootHasEventListener) {
411 document.documentElement.addEventListener("mouseover",this,false);
412 document.documentElement.addEventListener("keypress",this,false);
413 this.svgRootHasEventListener = true;
418 if (!myRegExp.test(evt.target.getAttributeNS(null,"id"))) {
419 //case that the event comes from the documentRoot element
420 //but not from the combobox itself
421 this.mouseDownStatus = false;
422 document.documentElement.removeEventListener("mouseover",this,false);
423 document.documentElement.removeEventListener("keypress",this,false);
424 this.svgRootHasEventListener = false;
427 if (evt.type == "mousedown") {
428 if (myRegExp.test(callerId)) {
429 if (callerId.match(/\bselHighlightSelection_/)) {
430 this.selectOrUnselect(evt);
431 this.mouseDownStatus = true;
432 document.documentElement.addEventListener("mouseup",this,false);
433 evt.stopPropagation();
436 if (callerId.match(/\bselScrollUpperRect_|\bselScrollLowerRect/)) {
437 this.scrollDir = "down";
438 this.scrollActive = true;
439 document.documentElement.addEventListener("mouseup",this,false);
440 if (callerId.match(/UpperRect/)) {
441 this.scrollDir = "up";
443 this.scroll(this.scrollDir,1,true); //1 is one element to scroll, true says that we should move scrollbar
444 this.timer.setTimeout("scrollPerButton",400)
446 if (callerId.match(/\bselScrollbarRect_/)) {
447 this.scrollBarMove(evt);
450 if (evt.type == "mouseup") {
451 if (myRegExp.test(callerId)) {
452 if (callerId.match(/\bselHighlightSelection_/)) {
453 this.mouseDownStatus = false;
454 if (this.panStatus) {
455 this.scrollBarMove(evt);
457 if (this.scrollActive) {
458 this.scrollActive = false;
459 document.documentElement.removeEventListener("mouseup",this,false);
461 evt.stopPropagation();
463 if (callerId.match(/\bselScrollUpperRect_|\bselScrollLowerRect/)) {
464 this.scrollActive = false;
467 if (el.nodeName == "svg") {
468 if (this.panStatus) {
469 //stop scroll mode
470 this.scrollBarMove(evt);
472 if (this.scrollActive) {
473 this.scrollActive = false;
474 document.documentElement.removeEventListener("mouseup",this,false);
478 if (evt.type == "mousemove") {
479 if (el.nodeName == "svg") {
480 this.scrollBarMove(evt);
482 } //add keypress event
483 if (evt.type == "keypress") {
484 if (evt.charCode) {
485 var character = String.fromCharCode(evt.charCode).toLowerCase();
487 else {
488 //case opera and others
489 var character = String.fromCharCode(evt.keyCode).toLowerCase();
490 if (evt.keyCode == 0 || evt.keyCode == 16 || evt.keyCode == 17 || evt.keyCode == 18) {
491 //shift key
492 character = "";
496 this.pressedKeys += character;
498 if (character.length > 0) {
499 if (this.keyTimer) {
500 this.timer.clearTimeout(this.keyTimer);
502 this.keyTimer = this.timer.setTimeout("resetPressedKeys",1000);
503 this.scrollToKey();
508 combobox.prototype.moveTo = function(moveX,moveY) {
509 this.xOffset = moveX;
510 this.yOffset = moveY;
511 this.createOrUpdateCombobox();
514 combobox.prototype.resize = function(newWidth) {
515 this.width = newWidth;
516 this.createOrUpdateCombobox();
519 combobox.prototype.resetPressedKeys = function() {
520 this.keyTimer = undefined;
521 this.pressedKeys = "";
524 combobox.prototype.selectOrUnselect = function(evt) {
525 var mySelEl = evt.target;
526 var result = mySelEl.getAttributeNS(null,"id").split("_");
527 var idNr = result[2]; //the numerical id in the array
528 if (this.multiple) {
529 //multiple selections are allowed
530 if (evt.type == "mousedown") {
531 if (evt.ctrlKey) {
532 if (this.elementsArray[idNr].value) {
533 mySelEl.setAttributeNS(null,"fill",this.boxStyles["fill"]);
534 if (mySelEl.hasAttributeNS(null,"fill-opacity")) {
535 mySelEl.removeAttributeNS(null,"fill-opacity");
537 this.elementsArray[idNr].value = false;
539 else {
540 for (var attrib in this.highlightStyles) {
541 mySelEl.setAttributeNS(null,attrib,this.highlightStyles[attrib]);
543 this.elementsArray[idNr].value = true;
546 else {
547 if (evt.shiftKey) {
548 var selectedArray = new Array();
549 for (var i=0;i<this.elementsArray.length;i++) {
550 //see how many and where elements are already selected
551 if (this.elementsArray[i].value) {
552 selectedArray.push(i);
555 if (selectedArray.length == 0) {
556 //if no element was selected we select the given element
557 for (var attrib in this.highlightStyles) {
558 mySelEl.setAttributeNS(null,attrib,this.highlightStyles[attrib]);
560 this.elementsArray[idNr].value = true;
562 else {
563 //now we need to calculate the distances to other
564 var distance = this.elementsArray.length;
565 var nearestElement = 0;
566 for (var i=0;i<selectedArray.length;i++) {
567 var tempDist = Math.abs(idNr - selectedArray[i]);
568 if (tempDist < distance) {
569 distance = tempDist;
570 nearestElement = selectedArray[i];
573 if (nearestElement < idNr) {
574 var lowerIndex = nearestElement;
575 var upperIndex = idNr;
577 else {
578 var lowerIndex = idNr;
579 var upperIndex = nearestElement;
581 for (var i=lowerIndex;i<=upperIndex;i++) {
582 var mySelEl = document.getElementById("selHighlightSelection_" + this.id + "_" + i);
583 for (var attrib in this.highlightStyles) {
584 mySelEl.setAttributeNS(null,attrib,this.highlightStyles[attrib]);
586 this.elementsArray[i].value = true;
590 else {
591 this.deselectAll(false);
592 for (var attrib in this.highlightStyles) {
593 mySelEl.setAttributeNS(null,attrib,this.highlightStyles[attrib]);
595 this.elementsArray[idNr].value = true;
599 if (evt.type == "mouseover") {
600 for (var attrib in this.highlightStyles) {
601 mySelEl.setAttributeNS(null,attrib,this.highlightStyles[attrib]);
603 this.elementsArray[idNr].value = true;
606 else {
607 //only one selection is allowed at the time
608 this.deselectAll(false);
609 for (var attrib in this.highlightStyles) {
610 mySelEl.setAttributeNS(null,attrib,this.highlightStyles[attrib]);
612 this.elementsArray[idNr].value = true;
614 if (this.functionToCall) {
615 this.timer.setTimeout("fireFunction",this.timerMs);
619 combobox.prototype.deselectAll = function(fireFunction) {
620 for (var i=0;i<this.elementsArray.length;i++) {
621 if (this.elementsArray[i].value) {
622 this.elementsArray[i].value = false;
623 if (i >= this.curLowerIndex && i < (this.curLowerIndex + this.heightNrElements)) {
624 var mySelEl = document.getElementById("selHighlightSelection_" + this.id + "_" + i);
625 mySelEl.setAttributeNS(null,"fill",this.boxStyles["fill"]);
626 if (mySelEl.hasAttributeNS(null,"fill-opacity")) {
627 mySelEl.removeAttributeNS(null,"fill-opacity");
632 if (fireFunction) {
633 this.timer.setTimeout("fireFunction",this.timerMs);
637 combobox.prototype.selectAll = function(fireFunction) {
638 for (var i=0;i<this.elementsArray.length;i++) {
639 if (!this.elementsArray[i].value) {
640 this.elementsArray[i].value = true;
641 if (i >= this.curLowerIndex && i < (this.curLowerIndex + this.heightNrElements)) {
642 var mySelEl = document.getElementById("selHighlightSelection_" + this.id + "_" + i);
643 for (var attrib in this.highlightStyles) {
644 mySelEl.setAttributeNS(null,attrib,this.highlightStyles[attrib]);
649 if (fireFunction) {
650 this.timer.setTimeout("fireFunction",this.timerMs);
654 combobox.prototype.invertSelection = function(fireFunction) {
655 for (var i=0;i<this.elementsArray.length;i++) {
656 if (this.elementsArray[i].value) {
657 this.elementsArray[i].value = false;
658 if (i >= this.curLowerIndex && i < (this.curLowerIndex + this.heightNrElements)) {
659 var mySelEl = document.getElementById("selHighlightSelection_" + this.id + "_" + i);
660 mySelEl.setAttributeNS(null,"fill",this.boxStyles["fill"]);
661 if (mySelEl.hasAttributeNS(null,"fill-opacity")) {
662 mySelEl.removeAttributeNS(null,"fill-opacity");
666 else {
667 this.elementsArray[i].value = true;
668 if (i >= this.curLowerIndex && i < (this.curLowerIndex + this.heightNrElements)) {
669 var mySelEl = document.getElementById("selHighlightSelection_" + this.id + "_" + i);
670 for (var attrib in this.highlightStyles) {
671 mySelEl.setAttributeNS(null,attrib,this.highlightStyles[attrib]);
676 if (fireFunction) {
677 this.timer.setTimeout("fireFunction",this.timerMs);
681 combobox.prototype.fireFunction = function() {
682 var selectedArray = new Array();
683 var selectedArrayIndizes = new Array();
684 for (var i=0;i<this.elementsArray.length;i++) {
685 //see how many and where elements are already selected
686 if (this.elementsArray[i].value) {
687 selectedArray.push(this.elementsArray[i].key);
688 selectedArrayIndizes.push(i);
691 if (typeof(this.functionToCall) == "function") {
692 this.functionToCall(this.id,selectedArray,selectedArrayIndizes);
694 if (typeof(this.functionToCall) == "object") {
695 this.functionToCall.getComboboxVals(this.id,selectedArray,selectedArrayIndizes);
697 if (typeof(this.functionToCall) == undefined) {
698 return;
702 combobox.prototype.scrollPerButton = function() {
703 if (this.scrollActive == true) {
704 this.scroll(this.scrollDir,1,true); //1 is one element to scroll, true says that we should move scrollbar
705 this.timer.setTimeout("scrollPerButton",100)
709 combobox.prototype.scroll = function(scrollDir,scrollNr,scrollBool) {
710 if (scrollNr < this.heightNrElements) {
711 if ((this.curLowerIndex > 0) && (scrollDir == "up")) {
712 if (scrollNr > this.curLowerIndex) {
713 scrollNr = this.curLowerIndex;
715 //decrement current index
716 this.curLowerIndex = this.curLowerIndex - scrollNr;
717 //move scroller
718 if (scrollBool == true) {
719 this.scroller.setAttributeNS(null,"y",parseFloat(this.scroller.getAttributeNS(null,"y"))+ this.scrollStep * -1);
721 //add upper rect elements
722 for (var i=0;i<scrollNr;i++) {
723 var node = document.createElementNS(svgNS,"rect");
724 node.setAttributeNS(null,"x",this.xOffset + this.textPadding / 2);
725 node.setAttributeNS(null,"y",this.yOffset + this.cellHeight * i);
726 node.setAttributeNS(null,"width",this.width - this.cellHeight - this.textPadding);
727 node.setAttributeNS(null,"height",this.cellHeight);
728 if (this.elementsArray[this.curLowerIndex + i].value) {
729 for (var attrib in this.highlightStyles) {
730 node.setAttributeNS(null,attrib,this.highlightStyles[attrib]);
733 else {
734 node.setAttributeNS(null,"fill",this.boxStyles["fill"]);
735 if (node.hasAttributeNS(null,"fill-opacity")) {
736 node.removeAttributeNS(null,"fill-opacity");
739 node.setAttributeNS(null,"id","selHighlightSelection_" + this.id + "_" + (i + this.curLowerIndex));
740 //add event-handler
741 node.addEventListener("mousedown", this, false);
742 node.addEventListener("mouseover", this, false);
743 node.addEventListener("mouseup", this, false);
744 this.comboElementsGroup.appendChild(node);
745 //add text-nodes
746 var node = document.createElementNS(svgNS,"text");
747 node.setAttributeNS(null,"id","selTexts_" + this.id + "_" + (i + this.curLowerIndex));
748 node.setAttributeNS(null,"x",this.xOffset + this.textPadding);
749 node.setAttributeNS(null,"y",this.yOffset + this.textPaddingVertical + this.cellHeight * i);
750 node.setAttributeNS(null,"pointer-events","none");
751 var value = "";
752 for (var attrib in this.textStyles) {
753 value = this.textStyles[attrib];
754 if (attrib == "font-size") {
755 value += "px";
757 node.setAttributeNS(null,attrib,value);
759 var selectionText = document.createTextNode(this.elementsArray[this.curLowerIndex + i].key);
760 node.appendChild(selectionText);
761 this.comboElementsGroup.appendChild(node);
763 //move middle elements
764 for (var j=i;j<this.heightNrElements;j++) {
765 var node = document.getElementById("selTexts_" + this.id + "_" + (j + this.curLowerIndex));
766 node.setAttributeNS(null,"y",parseFloat(node.getAttributeNS(null,"y")) + (this.cellHeight * scrollNr));
767 var node = document.getElementById("selHighlightSelection_" + this.id + "_" + (j + this.curLowerIndex));
768 node.setAttributeNS(null,"y",parseFloat(node.getAttributeNS(null,"y")) + (this.cellHeight * scrollNr));
770 //remove lower elements
771 for (var k=j;k<(j+scrollNr);k++) {
772 var node = document.getElementById("selTexts_" + this.id + "_" + (k + this.curLowerIndex));
773 this.comboElementsGroup.removeChild(node);
774 var node = document.getElementById("selHighlightSelection_" + this.id +"_" + (k + this.curLowerIndex));
775 this.comboElementsGroup.removeChild(node);
778 else if ((this.curLowerIndex < (this.elementsArray.length - this.heightNrElements)) && (scrollDir == "down")) {
779 //move Scroller
780 if (scrollBool == true) {
781 this.scroller.setAttributeNS(null,"y",parseFloat(this.scroller.getAttributeNS(null,"y")) + this.scrollStep);
783 //remove most upper element
784 for (var i=0;i<scrollNr;i++) {
785 var node = document.getElementById("selTexts_" + this.id + "_" + (this.curLowerIndex + i));
786 this.comboElementsGroup.removeChild(node);
787 var node = document.getElementById("selHighlightSelection_" + this.id + "_" + (this.curLowerIndex + i));
788 this.comboElementsGroup.removeChild(node);
790 //move middle elements
791 for (var j=i;j<this.heightNrElements;j++) {
792 var node = document.getElementById("selTexts_" + this.id + "_" + (j + this.curLowerIndex));
793 node.setAttributeNS(null,"y",parseFloat(node.getAttributeNS(null,"y")) - (this.cellHeight * scrollNr));
794 var node = document.getElementById("selHighlightSelection_" + this.id + "_" + (j + this.curLowerIndex));
795 node.setAttributeNS(null,"y",parseFloat(node.getAttributeNS(null,"y")) - (this.cellHeight * scrollNr));
797 //add most lower element
798 for (var k=j;k<(j+scrollNr);k++) {
799 var node = document.createElementNS(svgNS,"rect");
800 node.setAttributeNS(null,"x",this.xOffset + this.textPadding / 2);
801 node.setAttributeNS(null,"y",this.yOffset + this.cellHeight * (k - scrollNr));
802 node.setAttributeNS(null,"width",this.width - this.cellHeight - this.textPadding);
803 node.setAttributeNS(null,"height",this.cellHeight);
804 if (this.elementsArray[this.curLowerIndex + k].value) {
805 for (var attrib in this.highlightStyles) {
806 node.setAttributeNS(null,attrib,this.highlightStyles[attrib]);
809 else {
810 node.setAttributeNS(null,"fill",this.boxStyles["fill"]);
811 if (node.hasAttributeNS(null,"fill-opacity")) {
812 node.removeAttributeNS(null,"fill-opacity");
815 node.setAttribute("id","selHighlightSelection_" + this.id + "_" + (k + this.curLowerIndex));
816 //add event-handler
817 node.addEventListener("mousedown", this, false);
818 node.addEventListener("mouseover", this, false);
819 node.addEventListener("mouseup", this, false);
820 this.comboElementsGroup.appendChild(node);
821 //add text-nodes
822 var node = document.createElementNS(svgNS,"text");
823 node.setAttributeNS(null,"id","selTexts_" + this.id + "_" + (k + this.curLowerIndex));
824 node.setAttributeNS(null,"x",this.xOffset + this.textPadding);
825 node.setAttributeNS(null,"y",this.yOffset + this.textPaddingVertical + this.cellHeight * (k - scrollNr));
826 node.setAttributeNS(null,"pointer-events","none");
827 var value = "";
828 for (var attrib in this.textStyles) {
829 value = this.textStyles[attrib];
830 if (attrib == "font-size") {
831 value += "px";
833 node.setAttributeNS(null,attrib,value);
835 var selectionText = document.createTextNode(this.elementsArray[this.curLowerIndex + k].key);
836 node.appendChild(selectionText);
837 this.comboElementsGroup.appendChild(node);
839 //increment current index
840 this.curLowerIndex = this.curLowerIndex + scrollNr;
843 else {
844 //remove lower elements
845 for (var i=0;i<this.heightNrElements;i++) {
846 var node = document.getElementById("selTexts_" + this.id + "_" + (i + this.curLowerIndex));
847 this.comboElementsGroup.removeChild(node);
848 var node = document.getElementById("selHighlightSelection_" + this.id +"_" + (i + this.curLowerIndex));
849 this.comboElementsGroup.removeChild(node);
851 if (scrollDir == "down") {
852 this.curLowerIndex = this.curLowerIndex + scrollNr;
854 else {
855 this.curLowerIndex = this.curLowerIndex - scrollNr;
857 for (var i=0;i<this.heightNrElements;i++) {
858 var node = document.createElementNS(svgNS,"rect");
859 node.setAttributeNS(null,"x",this.xOffset + this.textPadding / 2);
860 node.setAttributeNS(null,"y",this.yOffset + this.cellHeight * i);
861 node.setAttributeNS(null,"width",this.width - this.cellHeight - this.textPadding);
862 node.setAttributeNS(null,"height",this.cellHeight);
863 if (this.elementsArray[this.curLowerIndex + i].value) {
864 for (var attrib in this.highlightStyles) {
865 node.setAttributeNS(null,attrib,this.highlightStyles[attrib]);
868 else {
869 node.setAttributeNS(null,"fill",this.boxStyles["fill"]);
870 if (node.hasAttributeNS(null,"fill-opacity")) {
871 node.removeAttributeNS(null,"fill-opacity");
874 node.setAttributeNS(null,"id","selHighlightSelection_" + this.id + "_" + (i + this.curLowerIndex));
875 //add event-handler
876 node.addEventListener("mousedown", this, false);
877 node.addEventListener("mouseover", this, false);
878 node.addEventListener("mouseup", this, false);
879 this.comboElementsGroup.appendChild(node);
880 //add text-nodes
881 var node = document.createElementNS(svgNS,"text");
882 node.setAttributeNS(null,"id","selTexts_" + this.id + "_" + (i + this.curLowerIndex));
883 node.setAttributeNS(null,"x",this.xOffset + this.textPadding);
884 node.setAttributeNS(null,"y",this.yOffset + this.textPaddingVertical + this.cellHeight * i);
885 node.setAttributeNS(null,"pointer-events","none");
886 var value = "";
887 for (var attrib in this.textStyles) {
888 value = this.textStyles[attrib];
889 if (attrib == "font-size") {
890 value += "px";
892 node.setAttributeNS(null,attrib,value);
894 var selectionText = document.createTextNode(this.elementsArray[this.curLowerIndex + i].key);
895 node.appendChild(selectionText);
896 this.comboElementsGroup.appendChild(node);
901 //event listener for Scrollbar element
902 combobox.prototype.scrollBarMove = function(evt) {
903 var scrollerMinY = parseFloat(this.scrollbarRect.getAttributeNS(null,"y"));
904 var scrollerMaxY = parseFloat(this.scrollbarRect.getAttributeNS(null,"y")) + parseFloat(this.scrollbarRect.getAttributeNS(null,"height")) - parseFloat(this.scroller.getAttributeNS(null,"height"));
905 if (evt.type == "mousedown") {
906 this.panStatus = true;
907 //add event listeners to root element
908 var svgroot = document.documentElement;
909 svgroot.addEventListener("mousemove", this, false);
910 svgroot.addEventListener("mouseup", this, false);
911 for (var attrib in this.triangleStyles) {
912 this.scroller.setAttributeNS(null,attrib,this.triangleStyles[attrib]);
914 var coordPoint = myMapApp.calcCoord(evt,this.parentGroup);
915 this.panY = coordPoint.y;
916 var oldY = parseFloat(this.scroller.getAttributeNS(null,"y"));
917 var newY = this.panY - parseFloat(this.scroller.getAttributeNS(null,"height")) / 2;
918 if (newY < scrollerMinY) {
919 newY = scrollerMinY;
920 //maybe recalculate this.panY ??
922 if (newY > scrollerMaxY) {
923 newY = scrollerMaxY;
925 var panDiffY = newY - oldY;
926 var scrollDir = "down";
927 this.scrollCumulus = 0;
928 if(Math.abs(panDiffY) > this.scrollStep) {
929 var scrollNr = Math.abs(Math.round(panDiffY / this.scrollStep));
930 if (panDiffY > 0) {
931 this.scrollCumulus = panDiffY - this.scrollStep * scrollNr;
933 else {
934 this.scrollCumulus = panDiffY + this.scrollStep * scrollNr;
935 scrollDir = "up";
937 newY = oldY + panDiffY;
938 this.scroller.setAttributeNS(null,"y",newY);
939 this.scroll(scrollDir,scrollNr,false);
942 if (evt.type == "mouseup") {
943 if (this.panStatus == true) {
944 var newY = parseFloat(this.scroller.getAttributeNS(null,"y"));
945 for (var attrib in this.smallrectStyles) {
946 this.scroller.setAttributeNS(null,attrib,this.smallrectStyles[attrib]);
948 this.scroller.setAttributeNS(null,"y",this.yOffset + this.cellHeight + this.scrollStep * this.curLowerIndex);
950 var svgroot = document.documentElement;
951 svgroot.removeEventListener("mousemove", this, false);
952 svgroot.removeEventListener("mouseup", this, false);
953 this.panStatus = false;
955 if (evt.type == "mousemove") {
956 if (this.panStatus == true) {
957 var coordPoint = myMapApp.calcCoord(evt,this.parentGroup);
958 var panNewEvtY = coordPoint.y;
959 var panDiffY = panNewEvtY - this.panY;
960 var oldY = parseFloat(this.scroller.getAttributeNS(null,"y"));
961 var newY = oldY + panDiffY;
962 if (newY < scrollerMinY) {
963 newY = scrollerMinY;
965 if (newY > scrollerMaxY) {
966 newY = scrollerMaxY;
968 var panDiffY = newY - oldY;
969 this.scrollCumulus += panDiffY;
970 var scrollDir = "down";
971 var scrollNr = 0;
972 if(Math.abs(this.scrollCumulus) >= this.scrollStep) {
973 scrollNr = Math.abs(Math.round(this.scrollCumulus / this.scrollStep));
974 if (this.scrollCumulus > 0) {
975 this.scrollCumulus = this.scrollCumulus - this.scrollStep * scrollNr;
977 else {
978 this.scrollCumulus = this.scrollCumulus + this.scrollStep * scrollNr;
979 scrollDir = "up";
981 this.scroll(scrollDir,scrollNr,false);
983 else {
984 if (Math.abs(this.scrollCumulus) > this.scrollStep) {
985 scrollNr = 1;
986 if (panDiffY < 0) {
987 scrollDir = "up";
988 this.scrollCumulus = this.scrollCumulus + this.scrollStep;
990 else {
991 this.scrollCumulus = this.scrollCumulus - this.scrollStep;
993 panDiffY = this.scrollCumulus;
994 this.scroll(scrollDir,scrollNr,false);
996 else {
997 if (newY == scrollerMinY && this.curLowerIndex != 0) {
998 this.scroll("up",1,false);
1000 else if (newY == scrollerMaxY && this.curLowerIndex != (this.elementsArray.length - this.heightNrElements)) {
1001 this.scroll("down",1,false);
1005 newY = oldY + panDiffY;
1006 this.scroller.setAttributeNS(null,"y",newY);
1007 this.panY = panNewEvtY;
1012 combobox.prototype.scrollToKey = function() {
1013 for (var i=0;i<this.elementsArray.length;i++) {
1014 if (this.elementsArray[i].key.toLowerCase().substr(0,this.pressedKeys.length) == this.pressedKeys) {
1015 this.curLowerIndex = i;
1016 if (this.curLowerIndex > (this.elementsArray.length - this.heightNrElements)) {
1017 this.curLowerIndex = this.elementsArray.length - this.heightNrElements;
1019 this.createOrUpdateCombobox();
1020 break;
1025 combobox.prototype.elementExists = function(elementName) {
1026 var result = -1;
1027 for (i=0;i<this.elementsArray.length;i++) {
1028 if (this.elementsArray[i].key == elementName) {
1029 result = i;
1032 return result;
1035 combobox.prototype.selectElementsByName = function(elementNames,fireFunction) {
1036 var idsToSelect = new Array();
1037 for (var i=0;i<elementNames.length;i++) {
1038 var indexNr = this.elementExists(elementNames[i].key);
1039 if (indexNr != -1) {
1040 idsToSelect.push({index:indexNr,value:elementNames[i].value});
1043 if (idsToSelect.length > 0) {
1044 this.selectElementsByPosition(idsToSelect,fireFunction);
1048 combobox.prototype.selectElementsByPosition = function(positionArray,fireFunction) {
1049 for (var i=0;i<positionArray.length;i++) {
1050 if (positionArray[i].index < this.elementsArray.length) {
1051 if (positionArray[i].index >= this.curLowerIndex && positionArray[i].index < (this.curLowerIndex + this.heightNrElements)) {
1052 var node = document.getElementById("selHighlightSelection_" + this.id + "_" + positionArray[i].index);
1053 if (positionArray[i].value) {
1054 for (var attrib in this.highlightStyles) {
1055 node.setAttributeNS(null,attrib,this.highlightStyles[attrib]);
1058 else {
1059 node.setAttributeNS(null,"fill",this.boxStyles["fill"]);
1060 if (node.hasAttributeNS(null,"fill-opacity")) {
1061 node.removeAttributeNS(null,"fill-opacity");
1065 this.elementsArray[positionArray[i].index].value = positionArray[i].value;
1068 if (fireFunction) {
1069 this.timer.setTimeout("fireFunction",this.timerMs);
1073 combobox.prototype.sortList = function(direction) {
1074 //direction: asc|desc, for ascending or descending
1075 var mySelElementString = this.elementsArray[this.activeSelection];
1076 this.elementsArray.sort(function mySort(a,b) {
1077 if (a.key > b.key) {
1078 return 1;
1080 else {
1081 return -1;
1084 if (direction == "desc") {
1085 this.elementsArray.reverse();
1087 this.createOrUpdateCombobox();
1090 combobox.prototype.deleteElementsByName = function(elementNames,fireFunction) {
1091 for (var i=0;i<elementNames.length;i++) {
1092 existsPosition = this.elementExists(elementNames[i]);
1093 if (existsPosition != -1) {
1094 var tempArray = new Array;
1095 tempArray = tempArray.concat(this.elementsArray.slice(0,existsPosition),this.elementsArray.slice(existsPosition + 1,this.elementsArray.length));
1096 this.elementsArray = tempArray;
1097 if (existsPosition < this.curLowerIndex) {
1098 this.curLowerIndex--;
1102 this.createOrUpdateCombobox();
1103 if (fireFunction) {
1104 this.timer.setTimeout("fireFunction",this.timerMs);
1108 combobox.prototype.deleteElementByPosition = function(elementPosition,fireFunction) {
1109 if (elementPosition < this.elementsArray.length) {
1110 var tempArray = new Array;
1111 tempArray = tempArray.concat(this.elementsArray.slice(0,elementPosition),this.elementsArray.slice(elementPosition + 1,this.elementsArray.length));
1112 this.elementsArray = tempArray;
1113 if (elementPosition < this.curLowerIndex) {
1114 this.curLowerIndex -= 1;
1117 this.createOrUpdateCombobox();
1118 if (fireFunction) {
1119 this.timer.setTimeout("fireFunction",this.timerMs);
1123 combobox.prototype.addElementAtPosition = function(element,position,fireFunction) {
1124 if (position > this.elementsArray.length) {
1125 this.elementsArray.push(element);
1126 position = this.elementsArray.length - 1;
1128 else {
1129 var tempArray = new Array;
1130 tempArray = tempArray.concat(this.elementsArray.slice(0,position),element,this.elementsArray.slice(position,this.elementsArray.length));
1131 this.elementsArray = tempArray;
1133 if (position < this.curLowerIndex) {
1134 this.curLowerIndex += 1;
1136 this.createOrUpdateCombobox();
1137 if (fireFunction) {
1138 this.timer.setTimeout("fireFunction",this.timerMs);
1142 combobox.prototype.addElementsAlphabetically = function(elementsArr,direction,fireFunction) {
1143 this.elementsArray = this.elementsArray.concat(elementsArr);
1144 this.sortList(direction);
1145 if (fireFunction) {
1146 this.timer.setTimeout("fireFunction",this.timerMs);
1150 combobox.prototype.getCurrentSelections = function() {
1151 var selectedArray = new Array();
1152 for (var i=0;i<this.elementsArray.length;i++) {
1153 //see how many and where elements are already selected
1154 if (this.elementsArray[i].value) {
1155 selectedArray.push(this.elementsArray[i].key);
1158 return selectedArray;
1161 combobox.prototype.getCurrentSelectionsIndex = function() {
1162 var selectedArrayIndizes = new Array();
1163 for (var i=0;i<this.elementsArray.length;i++) {
1164 //see how many and where elements are already selected
1165 if (this.elementsArray[i].value) {
1166 selectedArrayIndizes.push(i);
1169 return selectedArrayIndizes;
1172 combobox.prototype.removeCombobox = function() {
1173 //remove all Elements of combobox
1174 this.exists = false;
1175 while (this.parentGroup.hasChildNodes()) {
1176 this.parentGroup.removeChild(this.parentGroup.firstChild);