public function subMenu($uid, $objSuffix = '', $key = false)
 {
     $tsfe = $this->getTypoScriptFrontendController();
     $tsfe->register['parentMenu'] = $this;
     $this->I = [];
     if ($key !== false) {
         $this->I['key'] = $key;
     } else {
         // subMenu expects a valid I[key] to work on _SUB_MENU
         foreach ($this->menuArr as $key => $value) {
             if ($value['uid'] == $uid) {
                 $this->I['key'] = $key;
             }
         }
     }
     return parent::subMenu($uid, $objSuffix);
 }
    /**
     * Putting things together, in particular the JavaScript code needed for the DHTML menu.
     *
     * @return mixed Returns the value of a call to the parent function, parent::extProc_finish();
     * @todo Define visibility
     */
    public function extProc_finish()
    {
        $dirL = $this->mconf['directionLeft'] ? '-GL_getObj(id).width' : '';
        $dirU = $this->mconf['directionUp'] ? '-GL_getObj(id).height' : '';
        $parentLayerId = end($GLOBALS['TSFE']->applicationData['GMENU_LAYERS']['WMparentId']);
        $DoTop = array();
        $GLV_menuOn = array();
        $relCode = array();
        $relFlag = 0;
        if ($this->mconf['relativeToParentLayer'] && $parentLayerId) {
            $relCode['X'] .= 'GLV_curLayerX["' . $parentLayerId . '"]+';
            $relCode['Y'] .= 'GLV_curLayerY["' . $parentLayerId . '"]+';
            if ($this->mconf['relativeToParentLayer.']['addWidth']) {
                $relCode['X'] .= 'GLV_curLayerWidth["' . $parentLayerId . '"]+';
            }
            if ($this->mconf['relativeToParentLayer.']['addHeight']) {
                $relCode['Y'] .= 'GLV_curLayerHeight["' . $parentLayerId . '"]+';
            }
        }
        if ($this->mconf['relativeToTriggerItem']) {
            $DoTop[] = '
		var parentObject = GL_getObj(GLV_menuXY[WMid][id][2]);
		var TI_width = parentObject.width;
		var TI_height = parentObject.height;
		var anchorObj = GL_getObj(GLV_menuXY[WMid][id][3]);
		var TI_x = anchorObj.x;
		var TI_y = anchorObj.y;
			';
            $relCode['X'] .= 'TI_x+';
            $relCode['Y'] .= 'TI_y+';
            if ($this->mconf['relativeToTriggerItem.']['addWidth']) {
                $relCode['X'] .= 'TI_width+';
            }
            if ($this->mconf['relativeToTriggerItem.']['addHeight']) {
                $relCode['Y'] .= 'TI_height+';
            }
            $relFlag = 1;
        }
        if ($relFlag) {
            $DoTop[] = 'GLV_menuOn["' . $this->WMid . '"].left = (' . $relCode['X'] . intval($this->mconf['leftOffset']) . $dirL . ')+"px";';
            $DoTop[] = 'GLV_menuOn["' . $this->WMid . '"].top =  (' . $relCode['Y'] . intval($this->mconf['topOffset']) . $dirU . ')+"px";';
        } else {
            // X position (y is fixed)
            if (!strcmp($this->mconf['lockPosition'], 'x')) {
                $DoTop[] = 'GLV_menuOn["' . $this->WMid . '"].left = (' . $relCode['X'] . 'GLV_menuXY["' . $this->WMid . '"][id][0]-(' . intval($this->mconf['xPosOffset']) . ')' . $dirL . ')+"px";';
                if ($this->isSetIntval($this->mconf['topOffset'])) {
                    $DoTop[] = 'GLV_menuOn["' . $this->WMid . '"].top = (' . $relCode['Y'] . intval($this->mconf['topOffset']) . $dirU . ')+"px";';
                }
            } elseif ($this->isSetIntval($this->mconf['xPosOffset'])) {
                $GLV_menuOn[] = $DoTop[] = 'GLV_menuOn["' . $this->WMid . '"].left = (GLV_x-(' . intval($this->mconf['xPosOffset']) . ')' . $dirL . ')+"px";';
                if ($this->isSetIntval($this->mconf['topOffset'])) {
                    $DoTop[] = 'GLV_menuOn["' . $this->WMid . '"].top = (' . $relCode['Y'] . intval($this->mconf['topOffset']) . $dirU . ')+"px";';
                }
            }
            // Y position	(x is fixed)
            if (!strcmp($this->mconf['lockPosition'], 'y')) {
                $DoTop[] = 'GLV_menuOn["' . $this->WMid . '"].top = (' . $relCode['Y'] . 'GLV_menuXY["' . $this->WMid . '"][id][1]-(' . intval($this->mconf['yPosOffset']) . ')' . $dirU . ')+"px";';
                if ($this->isSetIntval($this->mconf['leftOffset'])) {
                    $DoTop[] = 'GLV_menuOn["' . $this->WMid . '"].left = (' . $relCode['X'] . intval($this->mconf['leftOffset']) . $dirL . ')+"px";';
                }
            } elseif ($this->isSetIntval($this->mconf['yPosOffset'])) {
                $GLV_menuOn[] = $DoTop[] = 'GLV_menuOn["' . $this->WMid . '"].top = (GLV_y-(' . intval($this->mconf['yPosOffset']) . ')' . $dirU . ')+"px";';
                if ($this->isSetIntval($this->mconf['leftOffset'])) {
                    $DoTop[] = 'GLV_menuOn["' . $this->WMid . '"].left = (' . $relCode['X'] . intval($this->mconf['leftOffset']) . $dirL . ')+"px";';
                }
            }
        }
        // BordersWithIn:
        $DoTop[] = $this->extCalcBorderWithin('left', $this->WMbordersWithin[0]);
        $DoTop[] = $this->extCalcBorderWithin('top', $this->WMbordersWithin[1]);
        $DoTop[] = $this->extCalcBorderWithin('right', $this->WMbordersWithin[2]);
        $DoTop[] = $this->extCalcBorderWithin('bottom', $this->WMbordersWithin[3]);
        $DoTop[] = $this->extCalcBorderWithin('left', $this->WMbordersWithin[4]);
        $DoTop[] = $this->extCalcBorderWithin('top', $this->WMbordersWithin[5]);
        if ($this->mconf['freezeMouseover'] && !$this->mconf['freezeMouseover.']['alwaysKeep']) {
            $this->WMhideCode .= '
GL' . $this->WMid . '_out("");';
        }
        $TEST = '';
        if (count($GLOBALS['TSFE']->applicationData['GMENU_LAYERS']['WMid'])) {
            foreach ($GLOBALS['TSFE']->applicationData['GMENU_LAYERS']['WMid'] as $mIdStr) {
                $this->WMhideCode .= '
GL_hideAll("' . $mIdStr . '");';
                $this->WMrestoreScript .= '
GL_restoreMenu("' . $mIdStr . '");';
                $this->WMresetSubMenus .= '
if (!GLV_doReset["' . $mIdStr . '"] && GLV_currentLayer["' . $mIdStr . '"]!=null)	resetSubMenu=0;';
            }
        }
        // IESelectFix - Adds IFRAME tag to HTML, Hides IFRAME layer below menu
        if ($this->mconf['ieSelectFix']) {
            $this->WMhideCode .= '
	GL_iframer(\'' . $this->WMid . '\',\'\',false);';
            $this->divLayers['iframe'] = '<iframe id="Iframe' . $this->WMid . '" scrolling="no" frameborder="0" style="position:absolute; top:0px; left:0px; background-color:transparent; layer-background-color:transparent; display:none;"></iframe>';
        }
        $GLOBALS['TSFE']->applicationData['GMENU_LAYERS']['WMid'] = array_merge($this->WMtempStore, $GLOBALS['TSFE']->applicationData['GMENU_LAYERS']['WMid']);
        $GLOBALS['TSFE']->additionalHeaderData['gmenu_layer_shared'] = '<script type="text/javascript" src="' . \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::siteRelPath('statictemplates') . 'media/scripts/jsfunc.layermenu.js"></script>';
        $GLOBALS['TSFE']->JSCode .= '

GLV_curLayerWidth["' . $this->WMid . '"]=0;
GLV_curLayerHeight["' . $this->WMid . '"]=0;
GLV_curLayerX["' . $this->WMid . '"]=0;
GLV_curLayerY["' . $this->WMid . '"]=0;
GLV_menuOn["' . $this->WMid . '"] = null;
GLV_gap["' . $this->WMid . '"]=' . \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange($this->mconf['hideMenuWhenNotOver'], 0, 600) . ';
GLV_currentLayer["' . $this->WMid . '"] = null;
GLV_currentROitem["' . $this->WMid . '"] = null;
GLV_hasBeenOver["' . $this->WMid . '"]=0;
GLV_doReset["' . $this->WMid . '"]=false;
GLV_lastKey["' . $this->WMid . '"] = "' . $this->WMlastKey . '";
GLV_onlyOnLoad["' . $this->WMid . '"] = ' . ($this->WMonlyOnLoad ? 1 : 0) . ';
GLV_dontHideOnMouseUp["' . $this->WMid . '"] = ' . ($this->mconf['dontHideOnMouseUp'] ? 1 : 0) . ';
GLV_dontFollowMouse["' . $this->WMid . '"] = ' . ($this->mconf['dontFollowMouse'] ? 1 : 0) . ';
GLV_date = new Date();
GLV_timeout["' . $this->WMid . '"] = GLV_date.getTime();
GLV_timeoutRef["' . $this->WMid . '"] = ' . \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange($this->mconf['hideMenuTimer'], 0, 20000) . ';
GLV_menuXY["' . $this->WMid . '"] = new Array();
' . implode(LF, $this->WMxyArray) . '
' . $this->WMrestoreVars;
        if ($this->mconf['freezeMouseover']) {
            $GLOBALS['TSFE']->JSCode .= '
// Alternative rollover/out functions for use with GMENU_LAYER
function GL' . $this->WMid . '_over(mitm_id) {
	GL' . $this->WMid . '_out("");	// removes any old roll over state of an item. Needed for alwaysKeep and Opera browsers.
	switch(mitm_id) {
' . implode(LF, $this->VMmouseoverActions) . '
	}
	GLV_currentROitem["' . $this->WMid . '"]=mitm_id;
}
function GL' . $this->WMid . '_out(mitm_id) {
	if (!mitm_id)	mitm_id=GLV_currentROitem["' . $this->WMid . '"];
	switch(mitm_id) {
' . implode(LF, $this->VMmouseoutActions) . '
	}
}
';
        }
        $GLOBALS['TSFE']->JSCode .= '
function GL' . $this->WMid . '_getMouse(e) {
	if (GLV_menuOn["' . $this->WMid . '"]!=null && !GLV_dontFollowMouse["' . $this->WMid . '"]){
' . implode(LF, $GLV_menuOn) . '
	}
	GL_mouseMoveEvaluate("' . $this->WMid . '");
}
function GL' . $this->WMid . '_hideCode() {
' . $this->WMhideCode . '
}
function GL' . $this->WMid . '_doTop(WMid,id) {
' . trim(implode(LF, $DoTop)) . '
}
function GL' . $this->WMid . '_restoreMenu() {
' . $this->WMrestoreScript . '
}
function GL' . $this->WMid . '_resetSubMenus() {
	var resetSubMenu=1;
' . $this->WMresetSubMenus . '
	return resetSubMenu;
}

GLV_timeout_pointers[GLV_timeout_count] = "' . $this->WMid . '";
GLV_timeout_count++;

';
        $GLOBALS['TSFE']->JSeventFuncCalls['onload']['GL_initLayers()'] = 'GL_initLayers();';
        $GLOBALS['TSFE']->JSeventFuncCalls['onload'][$this->WMid] = 'GL_restoreMenu("' . $this->WMid . '");';
        // Should be called BEFORE any of the 'local' getMouse functions!
        // is put inside in a try catch block to avoid JS errors in IE
        $GLOBALS['TSFE']->JSeventFuncCalls['onmousemove']['GL_getMouse(e)'] = 'try{GL_getMouse(e);}catch(ex){};';
        $GLOBALS['TSFE']->JSeventFuncCalls['onmousemove'][$this->WMid] = 'try{GL' . $this->WMid . '_getMouse(e);}catch(ex){};';
        $GLOBALS['TSFE']->JSeventFuncCalls['onmouseup'][$this->WMid] = 'GL_mouseUp(\'' . $this->WMid . '\',e);';
        $GLOBALS['TSFE']->divSection .= implode($this->divLayers, LF) . LF;
        return parent::extProc_finish();
    }