diff --git a/webconsole-plugins/root-cause/README.md b/webconsole-plugins/root-cause/README.md new file mode 100644 index 00000000000..2ae6de5b5d8 --- /dev/null +++ b/webconsole-plugins/root-cause/README.md @@ -0,0 +1,5 @@ +# Root Cause OSGI Web Console Plugin + +A Felix Webconsole Plugin for [Root Cause Tool](https://github.com/apache/felix/tree/trunk/rootcause) + +![Plugin Demo](doc/root-cause-plugin.gif) \ No newline at end of file diff --git a/webconsole-plugins/root-cause/doc/root-cause-plugin.gif b/webconsole-plugins/root-cause/doc/root-cause-plugin.gif new file mode 100644 index 00000000000..9eaeaedb493 Binary files /dev/null and b/webconsole-plugins/root-cause/doc/root-cause-plugin.gif differ diff --git a/webconsole-plugins/root-cause/pom.xml b/webconsole-plugins/root-cause/pom.xml new file mode 100644 index 00000000000..bc3c3a29051 --- /dev/null +++ b/webconsole-plugins/root-cause/pom.xml @@ -0,0 +1,138 @@ + + + + + 4.0.0 + + org.apache.felix + felix-parent + 5 + ../../../pom/pom.xml + + + org.apache.felix.webconsole.plugins.rootcause + bundle + 1.0.0-SNAPSHOT + + felix-root-cause-webconsole-plugin + Root Cause plugin for Apache Felix Web Console + + + 8 + + + + scm:svn:http://svn.apache.org/repos/asf/felix/trunk/webconsole-plugins/root-cause + + + scm:svn:https://svn.apache.org/repos/asf/felix/trunk/webconsole-plugins/root-cause + + + http://svn.apache.org/viewvc/felix/trunk/webconsole-plugins/root-cause + + + + + + + org.apache.felix + maven-bundle-plugin + 3.2.0 + true + + + ${project.artifactId} + ${project.description} + + org.apache.felix.rootcause, + org.apache.felix.utils;inline=org/apache/felix/utils/json/JSONWriter** + + + sun.misc.*;resolution:=optional, + * + + + org.apache.felix.webconsole.plugins.rootcause.* + + + + + + org.apache.rat + apache-rat-plugin + + + src/** + + + src/main/resources/root-cause/** + + + + + + + + org.osgi + osgi.core + 6.0.0 + provided + + + org.osgi + osgi.cmpn + 6.0.0 + provided + + + org.osgi + osgi.annotation + 6.0.0 + provided + + + org.osgi + org.osgi.service.component.annotations + 1.3.0 + provided + + + org.osgi + org.osgi.service.metatype.annotations + 1.3.0 + provided + + + org.apache.felix + org.apache.felix.webconsole + 4.3.8 + provided + + + javax.servlet + servlet-api + 2.3 + provided + + + org.apache.felix + org.apache.felix.utils + 1.11.4 + provided + + + org.apache.felix + org.apache.felix.rootcause + 0.1.0 + + + diff --git a/webconsole-plugins/root-cause/src/main/java/org/apache/felix/webconsole/plugins/rootcause/internal/RootCausePlugin.java b/webconsole-plugins/root-cause/src/main/java/org/apache/felix/webconsole/plugins/rootcause/internal/RootCausePlugin.java new file mode 100644 index 00000000000..9796912be1a --- /dev/null +++ b/webconsole-plugins/root-cause/src/main/java/org/apache/felix/webconsole/plugins/rootcause/internal/RootCausePlugin.java @@ -0,0 +1,177 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.felix.webconsole.plugins.rootcause.internal; + +import static org.apache.felix.webconsole.WebConsoleConstants.PLUGIN_CATEGORY; +import static org.apache.felix.webconsole.WebConsoleConstants.PLUGIN_LABEL; + +import java.io.IOException; +import java.io.StringWriter; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Optional; +import java.util.stream.Collectors; +import javax.servlet.Servlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.apache.felix.rootcause.DSComp; +import org.apache.felix.rootcause.RootCauseCommand; +import org.apache.felix.rootcause.RootCausePrinter; +import org.apache.felix.utils.json.JSONWriter; +import org.apache.felix.webconsole.AbstractWebConsolePlugin; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.runtime.ServiceComponentRuntime; + + +@Component( + service = Servlet.class, + property = { + PLUGIN_LABEL + "=" + RootCausePlugin.LABEL, + PLUGIN_CATEGORY + "=" + RootCausePlugin.CATEGORY, + }) +public class RootCausePlugin extends AbstractWebConsolePlugin { + + // lives under OSGI Menu. + public static final String CATEGORY = "OSGi"; + + public static final String LABEL = "root-cause"; // used for the URL + public static final String TITLE = "Root Cause"; // used for the menu item title (UI) + public static final String RESOURCE_PREFIX = "/" + LABEL + "/"; + + private String pluginHtml; + + @Reference + private RootCauseCommand rootCauseCommand; + + @Reference + private ServiceComponentRuntime runtime; + + @Activate + protected void activate() { + this.pluginHtml = getPluginHtml(); + } + + @Override + protected void renderContent(HttpServletRequest request, HttpServletResponse response) + throws IOException { + if (isHtmlRequest(request)) { + response.getWriter().write(getPluginHtml()); + } else if (request.getPathInfo().equalsIgnoreCase("/" + LABEL + "/rootcause.json")) { + response.setContentType("application/json"); + String name = request.getParameter("name"); + response.getWriter().write(getRootCauses(name)); + } else if (request.getPathInfo().equalsIgnoreCase("/" + LABEL + "/components.json")) { + response.setContentType("application/json"); + response.getWriter().write(getComponentNamesJsonArray()); + } + } + + // I know, strange, does not override anything... + // see: https://github.com/justinedelson/felix/blob/df21d1b2eb10543de05727dce890cd6a9a347375/webconsole/src/main/java/org/apache/felix/webconsole/AbstractWebConsolePlugin.java#L230 + // This method is called by this plugin to return a URL of a "resource" file + public URL getResource(final String path) { + if (path.startsWith(RESOURCE_PREFIX)) { + // get resource from this project/bundle "resources" folder + return this.getClass().getResource(path); + } + return null; + } + + @Override + public String getLabel() { + return LABEL; + } + + @Override + public String getTitle() { + return TITLE; + } + + protected boolean isHtmlRequest(HttpServletRequest request) { + return ("/" + LABEL).equalsIgnoreCase(request.getPathInfo()); + } + + /** + * Returns the plugin's HTML as String + * The HTML in this case comes fom the plugin.html file in the "resources" folder. + */ + private String getPluginHtml() { + if (null == this.pluginHtml) { + this.pluginHtml = readResourceString("plugin.html"); + } + return this.pluginHtml; + } + + /** + * Read resource file from the RESOURCE_PREFIX folder. + */ + private String readResourceString(String name) { + return readTemplateFile(RESOURCE_PREFIX + name); + } + + private String getComponentNamesJsonArray() throws IOException{ + List componentNames = Optional.of(runtime) + .map(ServiceComponentRuntime::getComponentDescriptionDTOs) + .map(dtos -> dtos.stream().map(dto -> dto.name).collect(Collectors.toList())) + .orElse(null); + return toJsonArray(componentNames); + } + + private String toJsonArray(List list) throws IOException { + StringWriter sw = new StringWriter(); + JSONWriter jw = new JSONWriter(sw); + jw.array(); + if (null != list) { + for(String str: list) { + jw.value(str); + } + } + jw.endArray(); + jw.flush(); + return sw.toString(); + } + + /** + * Get root cause lines as string JSON Array. + */ + private String getRootCauses (String name) throws IOException { + DSComp rootCause = null; + List causes = new ArrayList<>(); + try { + rootCause = rootCauseCommand.rootcause(name); + } catch (NoSuchElementException e){ + // thrown when component cannot be found. needs to be fixed in RootCauseCommand#rootcause + // see FELIX-6217 + log("Could not find component with name: " + name, e); + } + if (rootCause == null) { + causes.add("Component with name: \""+ name + "\" Does not exist."); + causes.add("Tip: Use the component full name, for example: " + + "\"org.apache.felix.webconsole.plugins.rootcause.internal.RootCausePlugin\""); + } else { + new RootCausePrinter(causes::add).print(rootCause); + } + + return toJsonArray(causes); + } +} diff --git a/webconsole-plugins/root-cause/src/main/resources/root-cause/jquery-ui-1.12.1.custom/README.md b/webconsole-plugins/root-cause/src/main/resources/root-cause/jquery-ui-1.12.1.custom/README.md new file mode 100644 index 00000000000..e6b460ebba7 --- /dev/null +++ b/webconsole-plugins/root-cause/src/main/resources/root-cause/jquery-ui-1.12.1.custom/README.md @@ -0,0 +1,3 @@ +This directory was generated using: + +[https://jqueryui.com/download/#!version=1.12.1&components=100000010001000001000000000000000000000000000000](https://jqueryui.com/download/#!version=1.12.1&components=100000010001000001000000000000000000000000000000) \ No newline at end of file diff --git a/webconsole-plugins/root-cause/src/main/resources/root-cause/jquery-ui-1.12.1.custom/images/ui-bg_glass_55_fbf9ee_1x400.png b/webconsole-plugins/root-cause/src/main/resources/root-cause/jquery-ui-1.12.1.custom/images/ui-bg_glass_55_fbf9ee_1x400.png new file mode 100644 index 00000000000..a9ac7d77cf0 Binary files /dev/null and b/webconsole-plugins/root-cause/src/main/resources/root-cause/jquery-ui-1.12.1.custom/images/ui-bg_glass_55_fbf9ee_1x400.png differ diff --git a/webconsole-plugins/root-cause/src/main/resources/root-cause/jquery-ui-1.12.1.custom/images/ui-bg_glass_65_ffffff_1x400.png b/webconsole-plugins/root-cause/src/main/resources/root-cause/jquery-ui-1.12.1.custom/images/ui-bg_glass_65_ffffff_1x400.png new file mode 100644 index 00000000000..a749ee11408 Binary files /dev/null and b/webconsole-plugins/root-cause/src/main/resources/root-cause/jquery-ui-1.12.1.custom/images/ui-bg_glass_65_ffffff_1x400.png differ diff --git a/webconsole-plugins/root-cause/src/main/resources/root-cause/jquery-ui-1.12.1.custom/images/ui-bg_glass_75_dadada_1x400.png b/webconsole-plugins/root-cause/src/main/resources/root-cause/jquery-ui-1.12.1.custom/images/ui-bg_glass_75_dadada_1x400.png new file mode 100644 index 00000000000..b49a2a91000 Binary files /dev/null and b/webconsole-plugins/root-cause/src/main/resources/root-cause/jquery-ui-1.12.1.custom/images/ui-bg_glass_75_dadada_1x400.png differ diff --git a/webconsole-plugins/root-cause/src/main/resources/root-cause/jquery-ui-1.12.1.custom/images/ui-bg_glass_75_e6e6e6_1x400.png b/webconsole-plugins/root-cause/src/main/resources/root-cause/jquery-ui-1.12.1.custom/images/ui-bg_glass_75_e6e6e6_1x400.png new file mode 100644 index 00000000000..de1493b0b5b Binary files /dev/null and b/webconsole-plugins/root-cause/src/main/resources/root-cause/jquery-ui-1.12.1.custom/images/ui-bg_glass_75_e6e6e6_1x400.png differ diff --git a/webconsole-plugins/root-cause/src/main/resources/root-cause/jquery-ui-1.12.1.custom/images/ui-bg_glass_95_fef1ec_1x400.png b/webconsole-plugins/root-cause/src/main/resources/root-cause/jquery-ui-1.12.1.custom/images/ui-bg_glass_95_fef1ec_1x400.png new file mode 100644 index 00000000000..03f2880e074 Binary files /dev/null and b/webconsole-plugins/root-cause/src/main/resources/root-cause/jquery-ui-1.12.1.custom/images/ui-bg_glass_95_fef1ec_1x400.png differ diff --git a/webconsole-plugins/root-cause/src/main/resources/root-cause/jquery-ui-1.12.1.custom/images/ui-bg_highlight-soft_75_cccccc_1x100.png b/webconsole-plugins/root-cause/src/main/resources/root-cause/jquery-ui-1.12.1.custom/images/ui-bg_highlight-soft_75_cccccc_1x100.png new file mode 100644 index 00000000000..b5fca606319 Binary files /dev/null and b/webconsole-plugins/root-cause/src/main/resources/root-cause/jquery-ui-1.12.1.custom/images/ui-bg_highlight-soft_75_cccccc_1x100.png differ diff --git a/webconsole-plugins/root-cause/src/main/resources/root-cause/jquery-ui-1.12.1.custom/images/ui-icons_222222_256x240.png b/webconsole-plugins/root-cause/src/main/resources/root-cause/jquery-ui-1.12.1.custom/images/ui-icons_222222_256x240.png new file mode 100644 index 00000000000..330dfc11466 Binary files /dev/null and b/webconsole-plugins/root-cause/src/main/resources/root-cause/jquery-ui-1.12.1.custom/images/ui-icons_222222_256x240.png differ diff --git a/webconsole-plugins/root-cause/src/main/resources/root-cause/jquery-ui-1.12.1.custom/images/ui-icons_2e83ff_256x240.png b/webconsole-plugins/root-cause/src/main/resources/root-cause/jquery-ui-1.12.1.custom/images/ui-icons_2e83ff_256x240.png new file mode 100644 index 00000000000..7b3cfd6058c Binary files /dev/null and b/webconsole-plugins/root-cause/src/main/resources/root-cause/jquery-ui-1.12.1.custom/images/ui-icons_2e83ff_256x240.png differ diff --git a/webconsole-plugins/root-cause/src/main/resources/root-cause/jquery-ui-1.12.1.custom/images/ui-icons_454545_256x240.png b/webconsole-plugins/root-cause/src/main/resources/root-cause/jquery-ui-1.12.1.custom/images/ui-icons_454545_256x240.png new file mode 100644 index 00000000000..fcd5e51ab88 Binary files /dev/null and b/webconsole-plugins/root-cause/src/main/resources/root-cause/jquery-ui-1.12.1.custom/images/ui-icons_454545_256x240.png differ diff --git a/webconsole-plugins/root-cause/src/main/resources/root-cause/jquery-ui-1.12.1.custom/images/ui-icons_888888_256x240.png b/webconsole-plugins/root-cause/src/main/resources/root-cause/jquery-ui-1.12.1.custom/images/ui-icons_888888_256x240.png new file mode 100644 index 00000000000..c3d02324759 Binary files /dev/null and b/webconsole-plugins/root-cause/src/main/resources/root-cause/jquery-ui-1.12.1.custom/images/ui-icons_888888_256x240.png differ diff --git a/webconsole-plugins/root-cause/src/main/resources/root-cause/jquery-ui-1.12.1.custom/images/ui-icons_cd0a0a_256x240.png b/webconsole-plugins/root-cause/src/main/resources/root-cause/jquery-ui-1.12.1.custom/images/ui-icons_cd0a0a_256x240.png new file mode 100644 index 00000000000..6f9e045825e Binary files /dev/null and b/webconsole-plugins/root-cause/src/main/resources/root-cause/jquery-ui-1.12.1.custom/images/ui-icons_cd0a0a_256x240.png differ diff --git a/webconsole-plugins/root-cause/src/main/resources/root-cause/jquery-ui-1.12.1.custom/jquery-ui.css b/webconsole-plugins/root-cause/src/main/resources/root-cause/jquery-ui-1.12.1.custom/jquery-ui.css new file mode 100644 index 00000000000..b95806ecd39 --- /dev/null +++ b/webconsole-plugins/root-cause/src/main/resources/root-cause/jquery-ui-1.12.1.custom/jquery-ui.css @@ -0,0 +1,582 @@ +/*! jQuery UI - v1.12.1 - 2020-01-26 +* http://jqueryui.com +* Includes: core.css, autocomplete.css, menu.css, theme.css +* To view and modify this theme, visit http://jqueryui.com/themeroller/?scope=.root-cause&folderName=smoothness&cornerRadiusShadow=8px&offsetLeftShadow=-8px&offsetTopShadow=-8px&thicknessShadow=8px&opacityShadow=30&bgImgOpacityShadow=0&bgTextureShadow=flat&bgColorShadow=aaaaaa&opacityOverlay=30&bgImgOpacityOverlay=0&bgTextureOverlay=flat&bgColorOverlay=aaaaaa&iconColorError=cd0a0a&fcError=cd0a0a&borderColorError=cd0a0a&bgImgOpacityError=95&bgTextureError=glass&bgColorError=fef1ec&iconColorHighlight=2e83ff&fcHighlight=363636&borderColorHighlight=fcefa1&bgImgOpacityHighlight=55&bgTextureHighlight=glass&bgColorHighlight=fbf9ee&iconColorActive=454545&fcActive=212121&borderColorActive=aaaaaa&bgImgOpacityActive=65&bgTextureActive=glass&bgColorActive=ffffff&iconColorHover=454545&fcHover=212121&borderColorHover=999999&bgImgOpacityHover=75&bgTextureHover=glass&bgColorHover=dadada&iconColorDefault=888888&fcDefault=555555&borderColorDefault=d3d3d3&bgImgOpacityDefault=75&bgTextureDefault=glass&bgColorDefault=e6e6e6&iconColorContent=222222&fcContent=222222&borderColorContent=aaaaaa&bgImgOpacityContent=75&bgTextureContent=flat&bgColorContent=ffffff&iconColorHeader=222222&fcHeader=222222&borderColorHeader=aaaaaa&bgImgOpacityHeader=75&bgTextureHeader=highlight_soft&bgColorHeader=cccccc&cornerRadius=4px&fsDefault=1.1em&fwDefault=normal&ffDefault=Verdana%2CArial%2Csans-serif +* Copyright jQuery Foundation and other contributors; Licensed MIT */ + +/* Layout helpers +----------------------------------*/ +.root-cause .ui-helper-hidden { + display: none; +} +.root-cause .ui-helper-hidden-accessible { + border: 0; + clip: rect(0 0 0 0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; +} +.root-cause .ui-helper-reset { + margin: 0; + padding: 0; + border: 0; + outline: 0; + line-height: 1.3; + text-decoration: none; + font-size: 100%; + list-style: none; +} +.root-cause .ui-helper-clearfix:before, +.root-cause .ui-helper-clearfix:after { + content: ""; + display: table; + border-collapse: collapse; +} +.root-cause .ui-helper-clearfix:after { + clear: both; +} +.root-cause .ui-helper-zfix { + width: 100%; + height: 100%; + top: 0; + left: 0; + position: absolute; + opacity: 0; + filter:Alpha(Opacity=0); /* support: IE8 */ +} + +.root-cause .ui-front { + z-index: 100; +} + + +/* Interaction Cues +----------------------------------*/ +.root-cause .ui-state-disabled { + cursor: default !important; + pointer-events: none; +} + + +/* Icons +----------------------------------*/ +.root-cause .ui-icon { + display: inline-block; + vertical-align: middle; + margin-top: -.25em; + position: relative; + text-indent: -99999px; + overflow: hidden; + background-repeat: no-repeat; +} + +.root-cause .ui-widget-icon-block { + left: 50%; + margin-left: -8px; + display: block; +} + +/* Misc visuals +----------------------------------*/ + +/* Overlays */ +.root-cause .ui-widget-overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; +} +.root-cause .ui-autocomplete { + position: absolute; + top: 0; + left: 0; + cursor: default; +} +.root-cause .ui-menu { + list-style: none; + padding: 0; + margin: 0; + display: block; + outline: 0; +} +.root-cause .ui-menu .ui-menu { + position: absolute; +} +.root-cause .ui-menu .ui-menu-item { + margin: 0; + cursor: pointer; + /* support: IE10, see #8844 */ + list-style-image: url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"); +} +.root-cause .ui-menu .ui-menu-item-wrapper { + position: relative; + padding: 3px 1em 3px .4em; +} +.root-cause .ui-menu .ui-menu-divider { + margin: 5px 0; + height: 0; + font-size: 0; + line-height: 0; + border-width: 1px 0 0 0; +} +.root-cause .ui-menu .ui-state-focus, +.root-cause .ui-menu .ui-state-active { + margin: -1px; +} + +/* icon support */ +.root-cause .ui-menu-icons { + position: relative; +} +.root-cause .ui-menu-icons .ui-menu-item-wrapper { + padding-left: 2em; +} + +/* left-aligned */ +.root-cause .ui-menu .ui-icon { + position: absolute; + top: 0; + bottom: 0; + left: .2em; + margin: auto 0; +} + +/* right-aligned */ +.root-cause .ui-menu .ui-menu-icon { + left: auto; + right: 0; +} + +/* Component containers +----------------------------------*/ +.root-cause .ui-widget { + font-family: Verdana,Arial,sans-serif; + font-size: 1.1em; +} +.root-cause .ui-widget .ui-widget { + font-size: 1em; +} +.root-cause .ui-widget input, +.root-cause .ui-widget select, +.root-cause .ui-widget textarea, +.root-cause .ui-widget button { + font-family: Verdana,Arial,sans-serif; + font-size: 1em; +} +.root-cause .ui-widget.ui-widget-content { + border: 1px solid #d3d3d3; +} +.root-cause .ui-widget-content { + border: 1px solid #aaaaaa; + background: #ffffff; + color: #222222; +} +.root-cause .ui-widget-content a { + color: #222222; +} +.root-cause .ui-widget-header { + border: 1px solid #aaaaaa; + background: #cccccc url("images/ui-bg_highlight-soft_75_cccccc_1x100.png") 50% 50% repeat-x; + color: #222222; + font-weight: bold; +} +.root-cause .ui-widget-header a { + color: #222222; +} + +/* Interaction states +----------------------------------*/ +.root-cause .ui-state-default, +.root-cause .ui-widget-content .ui-state-default, +.root-cause .ui-widget-header .ui-state-default, +.root-cause .ui-button, + +/* We use html here because we need a greater specificity to make sure disabled +works properly when clicked or hovered */ +html .root-cause .ui-button.ui-state-disabled:hover, +html .root-cause .ui-button.ui-state-disabled:active { + border: 1px solid #d3d3d3; + background: #e6e6e6 url("images/ui-bg_glass_75_e6e6e6_1x400.png") 50% 50% repeat-x; + font-weight: normal; + color: #555555; +} +.root-cause .ui-state-default a, +.root-cause .ui-state-default a:link, +.root-cause .ui-state-default a:visited, +a.root-cause .ui-button, +a:link.root-cause .ui-button, +a:visited.root-cause .ui-button, +.root-cause .ui-button { + color: #555555; + text-decoration: none; +} +.root-cause .ui-state-hover, +.root-cause .ui-widget-content .ui-state-hover, +.root-cause .ui-widget-header .ui-state-hover, +.root-cause .ui-state-focus, +.root-cause .ui-widget-content .ui-state-focus, +.root-cause .ui-widget-header .ui-state-focus, +.root-cause .ui-button:hover, +.root-cause .ui-button:focus { + border: 1px solid #999999; + background: #dadada url("images/ui-bg_glass_75_dadada_1x400.png") 50% 50% repeat-x; + font-weight: normal; + color: #212121; +} +.root-cause .ui-state-hover a, +.root-cause .ui-state-hover a:hover, +.root-cause .ui-state-hover a:link, +.root-cause .ui-state-hover a:visited, +.root-cause .ui-state-focus a, +.root-cause .ui-state-focus a:hover, +.root-cause .ui-state-focus a:link, +.root-cause .ui-state-focus a:visited, +a.root-cause .ui-button:hover, +a.root-cause .ui-button:focus { + color: #212121; + text-decoration: none; +} + +.root-cause .ui-visual-focus { + box-shadow: 0 0 3px 1px rgb(94, 158, 214); +} +.root-cause .ui-state-active, +.root-cause .ui-widget-content .ui-state-active, +.root-cause .ui-widget-header .ui-state-active, +a.root-cause .ui-button:active, +.root-cause .ui-button:active, +.root-cause .ui-button.ui-state-active:hover { + border: 1px solid #aaaaaa; + background: #ffffff url("images/ui-bg_glass_65_ffffff_1x400.png") 50% 50% repeat-x; + font-weight: normal; + color: #212121; +} +.root-cause .ui-icon-background, +.root-cause .ui-state-active .ui-icon-background { + border: #aaaaaa; + background-color: #212121; +} +.root-cause .ui-state-active a, +.root-cause .ui-state-active a:link, +.root-cause .ui-state-active a:visited { + color: #212121; + text-decoration: none; +} + +/* Interaction Cues +----------------------------------*/ +.root-cause .ui-state-highlight, +.root-cause .ui-widget-content .ui-state-highlight, +.root-cause .ui-widget-header .ui-state-highlight { + border: 1px solid #fcefa1; + background: #fbf9ee url("images/ui-bg_glass_55_fbf9ee_1x400.png") 50% 50% repeat-x; + color: #363636; +} +.root-cause .ui-state-checked { + border: 1px solid #fcefa1; + background: #fbf9ee; +} +.root-cause .ui-state-highlight a, +.root-cause .ui-widget-content .ui-state-highlight a, +.root-cause .ui-widget-header .ui-state-highlight a { + color: #363636; +} +.root-cause .ui-state-error, +.root-cause .ui-widget-content .ui-state-error, +.root-cause .ui-widget-header .ui-state-error { + border: 1px solid #cd0a0a; + background: #fef1ec url("images/ui-bg_glass_95_fef1ec_1x400.png") 50% 50% repeat-x; + color: #cd0a0a; +} +.root-cause .ui-state-error a, +.root-cause .ui-widget-content .ui-state-error a, +.root-cause .ui-widget-header .ui-state-error a { + color: #cd0a0a; +} +.root-cause .ui-state-error-text, +.root-cause .ui-widget-content .ui-state-error-text, +.root-cause .ui-widget-header .ui-state-error-text { + color: #cd0a0a; +} +.root-cause .ui-priority-primary, +.root-cause .ui-widget-content .ui-priority-primary, +.root-cause .ui-widget-header .ui-priority-primary { + font-weight: bold; +} +.root-cause .ui-priority-secondary, +.root-cause .ui-widget-content .ui-priority-secondary, +.root-cause .ui-widget-header .ui-priority-secondary { + opacity: .7; + filter:Alpha(Opacity=70); /* support: IE8 */ + font-weight: normal; +} +.root-cause .ui-state-disabled, +.root-cause .ui-widget-content .ui-state-disabled, +.root-cause .ui-widget-header .ui-state-disabled { + opacity: .35; + filter:Alpha(Opacity=35); /* support: IE8 */ + background-image: none; +} +.root-cause .ui-state-disabled .ui-icon { + filter:Alpha(Opacity=35); /* support: IE8 - See #6059 */ +} + +/* Icons +----------------------------------*/ + +/* states and images */ +.root-cause .ui-icon { + width: 16px; + height: 16px; +} +.root-cause .ui-icon, +.root-cause .ui-widget-content .ui-icon { + background-image: url("images/ui-icons_222222_256x240.png"); +} +.root-cause .ui-widget-header .ui-icon { + background-image: url("images/ui-icons_222222_256x240.png"); +} +.root-cause .ui-state-hover .ui-icon, +.root-cause .ui-state-focus .ui-icon, +.root-cause .ui-button:hover .ui-icon, +.root-cause .ui-button:focus .ui-icon { + background-image: url("images/ui-icons_454545_256x240.png"); +} +.root-cause .ui-state-active .ui-icon, +.root-cause .ui-button:active .ui-icon { + background-image: url("images/ui-icons_454545_256x240.png"); +} +.root-cause .ui-state-highlight .ui-icon, +.root-cause .ui-button .ui-state-highlight.ui-icon { + background-image: url("images/ui-icons_2e83ff_256x240.png"); +} +.root-cause .ui-state-error .ui-icon, +.root-cause .ui-state-error-text .ui-icon { + background-image: url("images/ui-icons_cd0a0a_256x240.png"); +} +.root-cause .ui-button .ui-icon { + background-image: url("images/ui-icons_888888_256x240.png"); +} + +/* positioning */ +.root-cause .ui-icon-blank { background-position: 16px 16px; } +.root-cause .ui-icon-caret-1-n { background-position: 0 0; } +.root-cause .ui-icon-caret-1-ne { background-position: -16px 0; } +.root-cause .ui-icon-caret-1-e { background-position: -32px 0; } +.root-cause .ui-icon-caret-1-se { background-position: -48px 0; } +.root-cause .ui-icon-caret-1-s { background-position: -65px 0; } +.root-cause .ui-icon-caret-1-sw { background-position: -80px 0; } +.root-cause .ui-icon-caret-1-w { background-position: -96px 0; } +.root-cause .ui-icon-caret-1-nw { background-position: -112px 0; } +.root-cause .ui-icon-caret-2-n-s { background-position: -128px 0; } +.root-cause .ui-icon-caret-2-e-w { background-position: -144px 0; } +.root-cause .ui-icon-triangle-1-n { background-position: 0 -16px; } +.root-cause .ui-icon-triangle-1-ne { background-position: -16px -16px; } +.root-cause .ui-icon-triangle-1-e { background-position: -32px -16px; } +.root-cause .ui-icon-triangle-1-se { background-position: -48px -16px; } +.root-cause .ui-icon-triangle-1-s { background-position: -65px -16px; } +.root-cause .ui-icon-triangle-1-sw { background-position: -80px -16px; } +.root-cause .ui-icon-triangle-1-w { background-position: -96px -16px; } +.root-cause .ui-icon-triangle-1-nw { background-position: -112px -16px; } +.root-cause .ui-icon-triangle-2-n-s { background-position: -128px -16px; } +.root-cause .ui-icon-triangle-2-e-w { background-position: -144px -16px; } +.root-cause .ui-icon-arrow-1-n { background-position: 0 -32px; } +.root-cause .ui-icon-arrow-1-ne { background-position: -16px -32px; } +.root-cause .ui-icon-arrow-1-e { background-position: -32px -32px; } +.root-cause .ui-icon-arrow-1-se { background-position: -48px -32px; } +.root-cause .ui-icon-arrow-1-s { background-position: -65px -32px; } +.root-cause .ui-icon-arrow-1-sw { background-position: -80px -32px; } +.root-cause .ui-icon-arrow-1-w { background-position: -96px -32px; } +.root-cause .ui-icon-arrow-1-nw { background-position: -112px -32px; } +.root-cause .ui-icon-arrow-2-n-s { background-position: -128px -32px; } +.root-cause .ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } +.root-cause .ui-icon-arrow-2-e-w { background-position: -160px -32px; } +.root-cause .ui-icon-arrow-2-se-nw { background-position: -176px -32px; } +.root-cause .ui-icon-arrowstop-1-n { background-position: -192px -32px; } +.root-cause .ui-icon-arrowstop-1-e { background-position: -208px -32px; } +.root-cause .ui-icon-arrowstop-1-s { background-position: -224px -32px; } +.root-cause .ui-icon-arrowstop-1-w { background-position: -240px -32px; } +.root-cause .ui-icon-arrowthick-1-n { background-position: 1px -48px; } +.root-cause .ui-icon-arrowthick-1-ne { background-position: -16px -48px; } +.root-cause .ui-icon-arrowthick-1-e { background-position: -32px -48px; } +.root-cause .ui-icon-arrowthick-1-se { background-position: -48px -48px; } +.root-cause .ui-icon-arrowthick-1-s { background-position: -64px -48px; } +.root-cause .ui-icon-arrowthick-1-sw { background-position: -80px -48px; } +.root-cause .ui-icon-arrowthick-1-w { background-position: -96px -48px; } +.root-cause .ui-icon-arrowthick-1-nw { background-position: -112px -48px; } +.root-cause .ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } +.root-cause .ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } +.root-cause .ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } +.root-cause .ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } +.root-cause .ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } +.root-cause .ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } +.root-cause .ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } +.root-cause .ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } +.root-cause .ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } +.root-cause .ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } +.root-cause .ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } +.root-cause .ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } +.root-cause .ui-icon-arrowreturn-1-w { background-position: -64px -64px; } +.root-cause .ui-icon-arrowreturn-1-n { background-position: -80px -64px; } +.root-cause .ui-icon-arrowreturn-1-e { background-position: -96px -64px; } +.root-cause .ui-icon-arrowreturn-1-s { background-position: -112px -64px; } +.root-cause .ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } +.root-cause .ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } +.root-cause .ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } +.root-cause .ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } +.root-cause .ui-icon-arrow-4 { background-position: 0 -80px; } +.root-cause .ui-icon-arrow-4-diag { background-position: -16px -80px; } +.root-cause .ui-icon-extlink { background-position: -32px -80px; } +.root-cause .ui-icon-newwin { background-position: -48px -80px; } +.root-cause .ui-icon-refresh { background-position: -64px -80px; } +.root-cause .ui-icon-shuffle { background-position: -80px -80px; } +.root-cause .ui-icon-transfer-e-w { background-position: -96px -80px; } +.root-cause .ui-icon-transferthick-e-w { background-position: -112px -80px; } +.root-cause .ui-icon-folder-collapsed { background-position: 0 -96px; } +.root-cause .ui-icon-folder-open { background-position: -16px -96px; } +.root-cause .ui-icon-document { background-position: -32px -96px; } +.root-cause .ui-icon-document-b { background-position: -48px -96px; } +.root-cause .ui-icon-note { background-position: -64px -96px; } +.root-cause .ui-icon-mail-closed { background-position: -80px -96px; } +.root-cause .ui-icon-mail-open { background-position: -96px -96px; } +.root-cause .ui-icon-suitcase { background-position: -112px -96px; } +.root-cause .ui-icon-comment { background-position: -128px -96px; } +.root-cause .ui-icon-person { background-position: -144px -96px; } +.root-cause .ui-icon-print { background-position: -160px -96px; } +.root-cause .ui-icon-trash { background-position: -176px -96px; } +.root-cause .ui-icon-locked { background-position: -192px -96px; } +.root-cause .ui-icon-unlocked { background-position: -208px -96px; } +.root-cause .ui-icon-bookmark { background-position: -224px -96px; } +.root-cause .ui-icon-tag { background-position: -240px -96px; } +.root-cause .ui-icon-home { background-position: 0 -112px; } +.root-cause .ui-icon-flag { background-position: -16px -112px; } +.root-cause .ui-icon-calendar { background-position: -32px -112px; } +.root-cause .ui-icon-cart { background-position: -48px -112px; } +.root-cause .ui-icon-pencil { background-position: -64px -112px; } +.root-cause .ui-icon-clock { background-position: -80px -112px; } +.root-cause .ui-icon-disk { background-position: -96px -112px; } +.root-cause .ui-icon-calculator { background-position: -112px -112px; } +.root-cause .ui-icon-zoomin { background-position: -128px -112px; } +.root-cause .ui-icon-zoomout { background-position: -144px -112px; } +.root-cause .ui-icon-search { background-position: -160px -112px; } +.root-cause .ui-icon-wrench { background-position: -176px -112px; } +.root-cause .ui-icon-gear { background-position: -192px -112px; } +.root-cause .ui-icon-heart { background-position: -208px -112px; } +.root-cause .ui-icon-star { background-position: -224px -112px; } +.root-cause .ui-icon-link { background-position: -240px -112px; } +.root-cause .ui-icon-cancel { background-position: 0 -128px; } +.root-cause .ui-icon-plus { background-position: -16px -128px; } +.root-cause .ui-icon-plusthick { background-position: -32px -128px; } +.root-cause .ui-icon-minus { background-position: -48px -128px; } +.root-cause .ui-icon-minusthick { background-position: -64px -128px; } +.root-cause .ui-icon-close { background-position: -80px -128px; } +.root-cause .ui-icon-closethick { background-position: -96px -128px; } +.root-cause .ui-icon-key { background-position: -112px -128px; } +.root-cause .ui-icon-lightbulb { background-position: -128px -128px; } +.root-cause .ui-icon-scissors { background-position: -144px -128px; } +.root-cause .ui-icon-clipboard { background-position: -160px -128px; } +.root-cause .ui-icon-copy { background-position: -176px -128px; } +.root-cause .ui-icon-contact { background-position: -192px -128px; } +.root-cause .ui-icon-image { background-position: -208px -128px; } +.root-cause .ui-icon-video { background-position: -224px -128px; } +.root-cause .ui-icon-script { background-position: -240px -128px; } +.root-cause .ui-icon-alert { background-position: 0 -144px; } +.root-cause .ui-icon-info { background-position: -16px -144px; } +.root-cause .ui-icon-notice { background-position: -32px -144px; } +.root-cause .ui-icon-help { background-position: -48px -144px; } +.root-cause .ui-icon-check { background-position: -64px -144px; } +.root-cause .ui-icon-bullet { background-position: -80px -144px; } +.root-cause .ui-icon-radio-on { background-position: -96px -144px; } +.root-cause .ui-icon-radio-off { background-position: -112px -144px; } +.root-cause .ui-icon-pin-w { background-position: -128px -144px; } +.root-cause .ui-icon-pin-s { background-position: -144px -144px; } +.root-cause .ui-icon-play { background-position: 0 -160px; } +.root-cause .ui-icon-pause { background-position: -16px -160px; } +.root-cause .ui-icon-seek-next { background-position: -32px -160px; } +.root-cause .ui-icon-seek-prev { background-position: -48px -160px; } +.root-cause .ui-icon-seek-end { background-position: -64px -160px; } +.root-cause .ui-icon-seek-start { background-position: -80px -160px; } +/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ +.root-cause .ui-icon-seek-first { background-position: -80px -160px; } +.root-cause .ui-icon-stop { background-position: -96px -160px; } +.root-cause .ui-icon-eject { background-position: -112px -160px; } +.root-cause .ui-icon-volume-off { background-position: -128px -160px; } +.root-cause .ui-icon-volume-on { background-position: -144px -160px; } +.root-cause .ui-icon-power { background-position: 0 -176px; } +.root-cause .ui-icon-signal-diag { background-position: -16px -176px; } +.root-cause .ui-icon-signal { background-position: -32px -176px; } +.root-cause .ui-icon-battery-0 { background-position: -48px -176px; } +.root-cause .ui-icon-battery-1 { background-position: -64px -176px; } +.root-cause .ui-icon-battery-2 { background-position: -80px -176px; } +.root-cause .ui-icon-battery-3 { background-position: -96px -176px; } +.root-cause .ui-icon-circle-plus { background-position: 0 -192px; } +.root-cause .ui-icon-circle-minus { background-position: -16px -192px; } +.root-cause .ui-icon-circle-close { background-position: -32px -192px; } +.root-cause .ui-icon-circle-triangle-e { background-position: -48px -192px; } +.root-cause .ui-icon-circle-triangle-s { background-position: -64px -192px; } +.root-cause .ui-icon-circle-triangle-w { background-position: -80px -192px; } +.root-cause .ui-icon-circle-triangle-n { background-position: -96px -192px; } +.root-cause .ui-icon-circle-arrow-e { background-position: -112px -192px; } +.root-cause .ui-icon-circle-arrow-s { background-position: -128px -192px; } +.root-cause .ui-icon-circle-arrow-w { background-position: -144px -192px; } +.root-cause .ui-icon-circle-arrow-n { background-position: -160px -192px; } +.root-cause .ui-icon-circle-zoomin { background-position: -176px -192px; } +.root-cause .ui-icon-circle-zoomout { background-position: -192px -192px; } +.root-cause .ui-icon-circle-check { background-position: -208px -192px; } +.root-cause .ui-icon-circlesmall-plus { background-position: 0 -208px; } +.root-cause .ui-icon-circlesmall-minus { background-position: -16px -208px; } +.root-cause .ui-icon-circlesmall-close { background-position: -32px -208px; } +.root-cause .ui-icon-squaresmall-plus { background-position: -48px -208px; } +.root-cause .ui-icon-squaresmall-minus { background-position: -64px -208px; } +.root-cause .ui-icon-squaresmall-close { background-position: -80px -208px; } +.root-cause .ui-icon-grip-dotted-vertical { background-position: 0 -224px; } +.root-cause .ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } +.root-cause .ui-icon-grip-solid-vertical { background-position: -32px -224px; } +.root-cause .ui-icon-grip-solid-horizontal { background-position: -48px -224px; } +.root-cause .ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } +.root-cause .ui-icon-grip-diagonal-se { background-position: -80px -224px; } + + +/* Misc visuals +----------------------------------*/ + +/* Corner radius */ +.root-cause .ui-corner-all, +.root-cause .ui-corner-top, +.root-cause .ui-corner-left, +.root-cause .ui-corner-tl { + border-top-left-radius: 4px; +} +.root-cause .ui-corner-all, +.root-cause .ui-corner-top, +.root-cause .ui-corner-right, +.root-cause .ui-corner-tr { + border-top-right-radius: 4px; +} +.root-cause .ui-corner-all, +.root-cause .ui-corner-bottom, +.root-cause .ui-corner-left, +.root-cause .ui-corner-bl { + border-bottom-left-radius: 4px; +} +.root-cause .ui-corner-all, +.root-cause .ui-corner-bottom, +.root-cause .ui-corner-right, +.root-cause .ui-corner-br { + border-bottom-right-radius: 4px; +} + +/* Overlays */ +.root-cause .ui-widget-overlay { + background: #aaaaaa; + opacity: .3; + filter: Alpha(Opacity=30); /* support: IE8 */ +} +.root-cause .ui-widget-shadow { + -webkit-box-shadow: -8px -8px 8px #aaaaaa; + box-shadow: -8px -8px 8px #aaaaaa; +} diff --git a/webconsole-plugins/root-cause/src/main/resources/root-cause/jquery-ui-1.12.1.custom/jquery-ui.js b/webconsole-plugins/root-cause/src/main/resources/root-cause/jquery-ui-1.12.1.custom/jquery-ui.js new file mode 100644 index 00000000000..08a5afaa63e --- /dev/null +++ b/webconsole-plugins/root-cause/src/main/resources/root-cause/jquery-ui-1.12.1.custom/jquery-ui.js @@ -0,0 +1,2659 @@ +/*! jQuery UI - v1.12.1 - 2020-01-26 +* http://jqueryui.com +* Includes: widget.js, position.js, keycode.js, unique-id.js, widgets/autocomplete.js, widgets/menu.js +* Copyright jQuery Foundation and other contributors; Licensed MIT */ + +(function( factory ) { + if ( typeof define === "function" && define.amd ) { + + // AMD. Register as an anonymous module. + define([ "jquery" ], factory ); + } else { + + // Browser globals + factory( jQuery ); + } +}(function( $ ) { + +$.ui = $.ui || {}; + +var version = $.ui.version = "1.12.1"; + + +/*! + * jQuery UI Widget 1.12.1 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + */ + +//>>label: Widget +//>>group: Core +//>>description: Provides a factory for creating stateful widgets with a common API. +//>>docs: http://api.jqueryui.com/jQuery.widget/ +//>>demos: http://jqueryui.com/widget/ + + + +var widgetUuid = 0; +var widgetSlice = Array.prototype.slice; + +$.cleanData = ( function( orig ) { + return function( elems ) { + var events, elem, i; + for ( i = 0; ( elem = elems[ i ] ) != null; i++ ) { + try { + + // Only trigger remove when necessary to save time + events = $._data( elem, "events" ); + if ( events && events.remove ) { + $( elem ).triggerHandler( "remove" ); + } + + // Http://bugs.jquery.com/ticket/8235 + } catch ( e ) {} + } + orig( elems ); + }; +} )( $.cleanData ); + +$.widget = function( name, base, prototype ) { + var existingConstructor, constructor, basePrototype; + + // ProxiedPrototype allows the provided prototype to remain unmodified + // so that it can be used as a mixin for multiple widgets (#8876) + var proxiedPrototype = {}; + + var namespace = name.split( "." )[ 0 ]; + name = name.split( "." )[ 1 ]; + var fullName = namespace + "-" + name; + + if ( !prototype ) { + prototype = base; + base = $.Widget; + } + + if ( $.isArray( prototype ) ) { + prototype = $.extend.apply( null, [ {} ].concat( prototype ) ); + } + + // Create selector for plugin + $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) { + return !!$.data( elem, fullName ); + }; + + $[ namespace ] = $[ namespace ] || {}; + existingConstructor = $[ namespace ][ name ]; + constructor = $[ namespace ][ name ] = function( options, element ) { + + // Allow instantiation without "new" keyword + if ( !this._createWidget ) { + return new constructor( options, element ); + } + + // Allow instantiation without initializing for simple inheritance + // must use "new" keyword (the code above always passes args) + if ( arguments.length ) { + this._createWidget( options, element ); + } + }; + + // Extend with the existing constructor to carry over any static properties + $.extend( constructor, existingConstructor, { + version: prototype.version, + + // Copy the object used to create the prototype in case we need to + // redefine the widget later + _proto: $.extend( {}, prototype ), + + // Track widgets that inherit from this widget in case this widget is + // redefined after a widget inherits from it + _childConstructors: [] + } ); + + basePrototype = new base(); + + // We need to make the options hash a property directly on the new instance + // otherwise we'll modify the options hash on the prototype that we're + // inheriting from + basePrototype.options = $.widget.extend( {}, basePrototype.options ); + $.each( prototype, function( prop, value ) { + if ( !$.isFunction( value ) ) { + proxiedPrototype[ prop ] = value; + return; + } + proxiedPrototype[ prop ] = ( function() { + function _super() { + return base.prototype[ prop ].apply( this, arguments ); + } + + function _superApply( args ) { + return base.prototype[ prop ].apply( this, args ); + } + + return function() { + var __super = this._super; + var __superApply = this._superApply; + var returnValue; + + this._super = _super; + this._superApply = _superApply; + + returnValue = value.apply( this, arguments ); + + this._super = __super; + this._superApply = __superApply; + + return returnValue; + }; + } )(); + } ); + constructor.prototype = $.widget.extend( basePrototype, { + + // TODO: remove support for widgetEventPrefix + // always use the name + a colon as the prefix, e.g., draggable:start + // don't prefix for widgets that aren't DOM-based + widgetEventPrefix: existingConstructor ? ( basePrototype.widgetEventPrefix || name ) : name + }, proxiedPrototype, { + constructor: constructor, + namespace: namespace, + widgetName: name, + widgetFullName: fullName + } ); + + // If this widget is being redefined then we need to find all widgets that + // are inheriting from it and redefine all of them so that they inherit from + // the new version of this widget. We're essentially trying to replace one + // level in the prototype chain. + if ( existingConstructor ) { + $.each( existingConstructor._childConstructors, function( i, child ) { + var childPrototype = child.prototype; + + // Redefine the child widget using the same prototype that was + // originally used, but inherit from the new version of the base + $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, + child._proto ); + } ); + + // Remove the list of existing child constructors from the old constructor + // so the old child constructors can be garbage collected + delete existingConstructor._childConstructors; + } else { + base._childConstructors.push( constructor ); + } + + $.widget.bridge( name, constructor ); + + return constructor; +}; + +$.widget.extend = function( target ) { + var input = widgetSlice.call( arguments, 1 ); + var inputIndex = 0; + var inputLength = input.length; + var key; + var value; + + for ( ; inputIndex < inputLength; inputIndex++ ) { + for ( key in input[ inputIndex ] ) { + value = input[ inputIndex ][ key ]; + if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) { + + // Clone objects + if ( $.isPlainObject( value ) ) { + target[ key ] = $.isPlainObject( target[ key ] ) ? + $.widget.extend( {}, target[ key ], value ) : + + // Don't extend strings, arrays, etc. with objects + $.widget.extend( {}, value ); + + // Copy everything else by reference + } else { + target[ key ] = value; + } + } + } + } + return target; +}; + +$.widget.bridge = function( name, object ) { + var fullName = object.prototype.widgetFullName || name; + $.fn[ name ] = function( options ) { + var isMethodCall = typeof options === "string"; + var args = widgetSlice.call( arguments, 1 ); + var returnValue = this; + + if ( isMethodCall ) { + + // If this is an empty collection, we need to have the instance method + // return undefined instead of the jQuery instance + if ( !this.length && options === "instance" ) { + returnValue = undefined; + } else { + this.each( function() { + var methodValue; + var instance = $.data( this, fullName ); + + if ( options === "instance" ) { + returnValue = instance; + return false; + } + + if ( !instance ) { + return $.error( "cannot call methods on " + name + + " prior to initialization; " + + "attempted to call method '" + options + "'" ); + } + + if ( !$.isFunction( instance[ options ] ) || options.charAt( 0 ) === "_" ) { + return $.error( "no such method '" + options + "' for " + name + + " widget instance" ); + } + + methodValue = instance[ options ].apply( instance, args ); + + if ( methodValue !== instance && methodValue !== undefined ) { + returnValue = methodValue && methodValue.jquery ? + returnValue.pushStack( methodValue.get() ) : + methodValue; + return false; + } + } ); + } + } else { + + // Allow multiple hashes to be passed on init + if ( args.length ) { + options = $.widget.extend.apply( null, [ options ].concat( args ) ); + } + + this.each( function() { + var instance = $.data( this, fullName ); + if ( instance ) { + instance.option( options || {} ); + if ( instance._init ) { + instance._init(); + } + } else { + $.data( this, fullName, new object( options, this ) ); + } + } ); + } + + return returnValue; + }; +}; + +$.Widget = function( /* options, element */ ) {}; +$.Widget._childConstructors = []; + +$.Widget.prototype = { + widgetName: "widget", + widgetEventPrefix: "", + defaultElement: "
", + + options: { + classes: {}, + disabled: false, + + // Callbacks + create: null + }, + + _createWidget: function( options, element ) { + element = $( element || this.defaultElement || this )[ 0 ]; + this.element = $( element ); + this.uuid = widgetUuid++; + this.eventNamespace = "." + this.widgetName + this.uuid; + + this.bindings = $(); + this.hoverable = $(); + this.focusable = $(); + this.classesElementLookup = {}; + + if ( element !== this ) { + $.data( element, this.widgetFullName, this ); + this._on( true, this.element, { + remove: function( event ) { + if ( event.target === element ) { + this.destroy(); + } + } + } ); + this.document = $( element.style ? + + // Element within the document + element.ownerDocument : + + // Element is window or document + element.document || element ); + this.window = $( this.document[ 0 ].defaultView || this.document[ 0 ].parentWindow ); + } + + this.options = $.widget.extend( {}, + this.options, + this._getCreateOptions(), + options ); + + this._create(); + + if ( this.options.disabled ) { + this._setOptionDisabled( this.options.disabled ); + } + + this._trigger( "create", null, this._getCreateEventData() ); + this._init(); + }, + + _getCreateOptions: function() { + return {}; + }, + + _getCreateEventData: $.noop, + + _create: $.noop, + + _init: $.noop, + + destroy: function() { + var that = this; + + this._destroy(); + $.each( this.classesElementLookup, function( key, value ) { + that._removeClass( value, key ); + } ); + + // We can probably remove the unbind calls in 2.0 + // all event bindings should go through this._on() + this.element + .off( this.eventNamespace ) + .removeData( this.widgetFullName ); + this.widget() + .off( this.eventNamespace ) + .removeAttr( "aria-disabled" ); + + // Clean up events and states + this.bindings.off( this.eventNamespace ); + }, + + _destroy: $.noop, + + widget: function() { + return this.element; + }, + + option: function( key, value ) { + var options = key; + var parts; + var curOption; + var i; + + if ( arguments.length === 0 ) { + + // Don't return a reference to the internal hash + return $.widget.extend( {}, this.options ); + } + + if ( typeof key === "string" ) { + + // Handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } + options = {}; + parts = key.split( "." ); + key = parts.shift(); + if ( parts.length ) { + curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] ); + for ( i = 0; i < parts.length - 1; i++ ) { + curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; + curOption = curOption[ parts[ i ] ]; + } + key = parts.pop(); + if ( arguments.length === 1 ) { + return curOption[ key ] === undefined ? null : curOption[ key ]; + } + curOption[ key ] = value; + } else { + if ( arguments.length === 1 ) { + return this.options[ key ] === undefined ? null : this.options[ key ]; + } + options[ key ] = value; + } + } + + this._setOptions( options ); + + return this; + }, + + _setOptions: function( options ) { + var key; + + for ( key in options ) { + this._setOption( key, options[ key ] ); + } + + return this; + }, + + _setOption: function( key, value ) { + if ( key === "classes" ) { + this._setOptionClasses( value ); + } + + this.options[ key ] = value; + + if ( key === "disabled" ) { + this._setOptionDisabled( value ); + } + + return this; + }, + + _setOptionClasses: function( value ) { + var classKey, elements, currentElements; + + for ( classKey in value ) { + currentElements = this.classesElementLookup[ classKey ]; + if ( value[ classKey ] === this.options.classes[ classKey ] || + !currentElements || + !currentElements.length ) { + continue; + } + + // We are doing this to create a new jQuery object because the _removeClass() call + // on the next line is going to destroy the reference to the current elements being + // tracked. We need to save a copy of this collection so that we can add the new classes + // below. + elements = $( currentElements.get() ); + this._removeClass( currentElements, classKey ); + + // We don't use _addClass() here, because that uses this.options.classes + // for generating the string of classes. We want to use the value passed in from + // _setOption(), this is the new value of the classes option which was passed to + // _setOption(). We pass this value directly to _classes(). + elements.addClass( this._classes( { + element: elements, + keys: classKey, + classes: value, + add: true + } ) ); + } + }, + + _setOptionDisabled: function( value ) { + this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null, !!value ); + + // If the widget is becoming disabled, then nothing is interactive + if ( value ) { + this._removeClass( this.hoverable, null, "ui-state-hover" ); + this._removeClass( this.focusable, null, "ui-state-focus" ); + } + }, + + enable: function() { + return this._setOptions( { disabled: false } ); + }, + + disable: function() { + return this._setOptions( { disabled: true } ); + }, + + _classes: function( options ) { + var full = []; + var that = this; + + options = $.extend( { + element: this.element, + classes: this.options.classes || {} + }, options ); + + function processClassString( classes, checkOption ) { + var current, i; + for ( i = 0; i < classes.length; i++ ) { + current = that.classesElementLookup[ classes[ i ] ] || $(); + if ( options.add ) { + current = $( $.unique( current.get().concat( options.element.get() ) ) ); + } else { + current = $( current.not( options.element ).get() ); + } + that.classesElementLookup[ classes[ i ] ] = current; + full.push( classes[ i ] ); + if ( checkOption && options.classes[ classes[ i ] ] ) { + full.push( options.classes[ classes[ i ] ] ); + } + } + } + + this._on( options.element, { + "remove": "_untrackClassesElement" + } ); + + if ( options.keys ) { + processClassString( options.keys.match( /\S+/g ) || [], true ); + } + if ( options.extra ) { + processClassString( options.extra.match( /\S+/g ) || [] ); + } + + return full.join( " " ); + }, + + _untrackClassesElement: function( event ) { + var that = this; + $.each( that.classesElementLookup, function( key, value ) { + if ( $.inArray( event.target, value ) !== -1 ) { + that.classesElementLookup[ key ] = $( value.not( event.target ).get() ); + } + } ); + }, + + _removeClass: function( element, keys, extra ) { + return this._toggleClass( element, keys, extra, false ); + }, + + _addClass: function( element, keys, extra ) { + return this._toggleClass( element, keys, extra, true ); + }, + + _toggleClass: function( element, keys, extra, add ) { + add = ( typeof add === "boolean" ) ? add : extra; + var shift = ( typeof element === "string" || element === null ), + options = { + extra: shift ? keys : extra, + keys: shift ? element : keys, + element: shift ? this.element : element, + add: add + }; + options.element.toggleClass( this._classes( options ), add ); + return this; + }, + + _on: function( suppressDisabledCheck, element, handlers ) { + var delegateElement; + var instance = this; + + // No suppressDisabledCheck flag, shuffle arguments + if ( typeof suppressDisabledCheck !== "boolean" ) { + handlers = element; + element = suppressDisabledCheck; + suppressDisabledCheck = false; + } + + // No element argument, shuffle and use this.element + if ( !handlers ) { + handlers = element; + element = this.element; + delegateElement = this.widget(); + } else { + element = delegateElement = $( element ); + this.bindings = this.bindings.add( element ); + } + + $.each( handlers, function( event, handler ) { + function handlerProxy() { + + // Allow widgets to customize the disabled handling + // - disabled as an array instead of boolean + // - disabled class as method for disabling individual parts + if ( !suppressDisabledCheck && + ( instance.options.disabled === true || + $( this ).hasClass( "ui-state-disabled" ) ) ) { + return; + } + return ( typeof handler === "string" ? instance[ handler ] : handler ) + .apply( instance, arguments ); + } + + // Copy the guid so direct unbinding works + if ( typeof handler !== "string" ) { + handlerProxy.guid = handler.guid = + handler.guid || handlerProxy.guid || $.guid++; + } + + var match = event.match( /^([\w:-]*)\s*(.*)$/ ); + var eventName = match[ 1 ] + instance.eventNamespace; + var selector = match[ 2 ]; + + if ( selector ) { + delegateElement.on( eventName, selector, handlerProxy ); + } else { + element.on( eventName, handlerProxy ); + } + } ); + }, + + _off: function( element, eventName ) { + eventName = ( eventName || "" ).split( " " ).join( this.eventNamespace + " " ) + + this.eventNamespace; + element.off( eventName ).off( eventName ); + + // Clear the stack to avoid memory leaks (#10056) + this.bindings = $( this.bindings.not( element ).get() ); + this.focusable = $( this.focusable.not( element ).get() ); + this.hoverable = $( this.hoverable.not( element ).get() ); + }, + + _delay: function( handler, delay ) { + function handlerProxy() { + return ( typeof handler === "string" ? instance[ handler ] : handler ) + .apply( instance, arguments ); + } + var instance = this; + return setTimeout( handlerProxy, delay || 0 ); + }, + + _hoverable: function( element ) { + this.hoverable = this.hoverable.add( element ); + this._on( element, { + mouseenter: function( event ) { + this._addClass( $( event.currentTarget ), null, "ui-state-hover" ); + }, + mouseleave: function( event ) { + this._removeClass( $( event.currentTarget ), null, "ui-state-hover" ); + } + } ); + }, + + _focusable: function( element ) { + this.focusable = this.focusable.add( element ); + this._on( element, { + focusin: function( event ) { + this._addClass( $( event.currentTarget ), null, "ui-state-focus" ); + }, + focusout: function( event ) { + this._removeClass( $( event.currentTarget ), null, "ui-state-focus" ); + } + } ); + }, + + _trigger: function( type, event, data ) { + var prop, orig; + var callback = this.options[ type ]; + + data = data || {}; + event = $.Event( event ); + event.type = ( type === this.widgetEventPrefix ? + type : + this.widgetEventPrefix + type ).toLowerCase(); + + // The original event may come from any element + // so we need to reset the target on the new event + event.target = this.element[ 0 ]; + + // Copy original event properties over to the new event + orig = event.originalEvent; + if ( orig ) { + for ( prop in orig ) { + if ( !( prop in event ) ) { + event[ prop ] = orig[ prop ]; + } + } + } + + this.element.trigger( event, data ); + return !( $.isFunction( callback ) && + callback.apply( this.element[ 0 ], [ event ].concat( data ) ) === false || + event.isDefaultPrevented() ); + } +}; + +$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { + $.Widget.prototype[ "_" + method ] = function( element, options, callback ) { + if ( typeof options === "string" ) { + options = { effect: options }; + } + + var hasOptions; + var effectName = !options ? + method : + options === true || typeof options === "number" ? + defaultEffect : + options.effect || defaultEffect; + + options = options || {}; + if ( typeof options === "number" ) { + options = { duration: options }; + } + + hasOptions = !$.isEmptyObject( options ); + options.complete = callback; + + if ( options.delay ) { + element.delay( options.delay ); + } + + if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) { + element[ method ]( options ); + } else if ( effectName !== method && element[ effectName ] ) { + element[ effectName ]( options.duration, options.easing, callback ); + } else { + element.queue( function( next ) { + $( this )[ method ](); + if ( callback ) { + callback.call( element[ 0 ] ); + } + next(); + } ); + } + }; +} ); + +var widget = $.widget; + + +/*! + * jQuery UI Position 1.12.1 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/position/ + */ + +//>>label: Position +//>>group: Core +//>>description: Positions elements relative to other elements. +//>>docs: http://api.jqueryui.com/position/ +//>>demos: http://jqueryui.com/position/ + + +( function() { +var cachedScrollbarWidth, + max = Math.max, + abs = Math.abs, + rhorizontal = /left|center|right/, + rvertical = /top|center|bottom/, + roffset = /[\+\-]\d+(\.[\d]+)?%?/, + rposition = /^\w+/, + rpercent = /%$/, + _position = $.fn.position; + +function getOffsets( offsets, width, height ) { + return [ + parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ), + parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 ) + ]; +} + +function parseCss( element, property ) { + return parseInt( $.css( element, property ), 10 ) || 0; +} + +function getDimensions( elem ) { + var raw = elem[ 0 ]; + if ( raw.nodeType === 9 ) { + return { + width: elem.width(), + height: elem.height(), + offset: { top: 0, left: 0 } + }; + } + if ( $.isWindow( raw ) ) { + return { + width: elem.width(), + height: elem.height(), + offset: { top: elem.scrollTop(), left: elem.scrollLeft() } + }; + } + if ( raw.preventDefault ) { + return { + width: 0, + height: 0, + offset: { top: raw.pageY, left: raw.pageX } + }; + } + return { + width: elem.outerWidth(), + height: elem.outerHeight(), + offset: elem.offset() + }; +} + +$.position = { + scrollbarWidth: function() { + if ( cachedScrollbarWidth !== undefined ) { + return cachedScrollbarWidth; + } + var w1, w2, + div = $( "
" + + "
" ), + innerDiv = div.children()[ 0 ]; + + $( "body" ).append( div ); + w1 = innerDiv.offsetWidth; + div.css( "overflow", "scroll" ); + + w2 = innerDiv.offsetWidth; + + if ( w1 === w2 ) { + w2 = div[ 0 ].clientWidth; + } + + div.remove(); + + return ( cachedScrollbarWidth = w1 - w2 ); + }, + getScrollInfo: function( within ) { + var overflowX = within.isWindow || within.isDocument ? "" : + within.element.css( "overflow-x" ), + overflowY = within.isWindow || within.isDocument ? "" : + within.element.css( "overflow-y" ), + hasOverflowX = overflowX === "scroll" || + ( overflowX === "auto" && within.width < within.element[ 0 ].scrollWidth ), + hasOverflowY = overflowY === "scroll" || + ( overflowY === "auto" && within.height < within.element[ 0 ].scrollHeight ); + return { + width: hasOverflowY ? $.position.scrollbarWidth() : 0, + height: hasOverflowX ? $.position.scrollbarWidth() : 0 + }; + }, + getWithinInfo: function( element ) { + var withinElement = $( element || window ), + isWindow = $.isWindow( withinElement[ 0 ] ), + isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9, + hasOffset = !isWindow && !isDocument; + return { + element: withinElement, + isWindow: isWindow, + isDocument: isDocument, + offset: hasOffset ? $( element ).offset() : { left: 0, top: 0 }, + scrollLeft: withinElement.scrollLeft(), + scrollTop: withinElement.scrollTop(), + width: withinElement.outerWidth(), + height: withinElement.outerHeight() + }; + } +}; + +$.fn.position = function( options ) { + if ( !options || !options.of ) { + return _position.apply( this, arguments ); + } + + // Make a copy, we don't want to modify arguments + options = $.extend( {}, options ); + + var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions, + target = $( options.of ), + within = $.position.getWithinInfo( options.within ), + scrollInfo = $.position.getScrollInfo( within ), + collision = ( options.collision || "flip" ).split( " " ), + offsets = {}; + + dimensions = getDimensions( target ); + if ( target[ 0 ].preventDefault ) { + + // Force left top to allow flipping + options.at = "left top"; + } + targetWidth = dimensions.width; + targetHeight = dimensions.height; + targetOffset = dimensions.offset; + + // Clone to reuse original targetOffset later + basePosition = $.extend( {}, targetOffset ); + + // Force my and at to have valid horizontal and vertical positions + // if a value is missing or invalid, it will be converted to center + $.each( [ "my", "at" ], function() { + var pos = ( options[ this ] || "" ).split( " " ), + horizontalOffset, + verticalOffset; + + if ( pos.length === 1 ) { + pos = rhorizontal.test( pos[ 0 ] ) ? + pos.concat( [ "center" ] ) : + rvertical.test( pos[ 0 ] ) ? + [ "center" ].concat( pos ) : + [ "center", "center" ]; + } + pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center"; + pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center"; + + // Calculate offsets + horizontalOffset = roffset.exec( pos[ 0 ] ); + verticalOffset = roffset.exec( pos[ 1 ] ); + offsets[ this ] = [ + horizontalOffset ? horizontalOffset[ 0 ] : 0, + verticalOffset ? verticalOffset[ 0 ] : 0 + ]; + + // Reduce to just the positions without the offsets + options[ this ] = [ + rposition.exec( pos[ 0 ] )[ 0 ], + rposition.exec( pos[ 1 ] )[ 0 ] + ]; + } ); + + // Normalize collision option + if ( collision.length === 1 ) { + collision[ 1 ] = collision[ 0 ]; + } + + if ( options.at[ 0 ] === "right" ) { + basePosition.left += targetWidth; + } else if ( options.at[ 0 ] === "center" ) { + basePosition.left += targetWidth / 2; + } + + if ( options.at[ 1 ] === "bottom" ) { + basePosition.top += targetHeight; + } else if ( options.at[ 1 ] === "center" ) { + basePosition.top += targetHeight / 2; + } + + atOffset = getOffsets( offsets.at, targetWidth, targetHeight ); + basePosition.left += atOffset[ 0 ]; + basePosition.top += atOffset[ 1 ]; + + return this.each( function() { + var collisionPosition, using, + elem = $( this ), + elemWidth = elem.outerWidth(), + elemHeight = elem.outerHeight(), + marginLeft = parseCss( this, "marginLeft" ), + marginTop = parseCss( this, "marginTop" ), + collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + + scrollInfo.width, + collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + + scrollInfo.height, + position = $.extend( {}, basePosition ), + myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() ); + + if ( options.my[ 0 ] === "right" ) { + position.left -= elemWidth; + } else if ( options.my[ 0 ] === "center" ) { + position.left -= elemWidth / 2; + } + + if ( options.my[ 1 ] === "bottom" ) { + position.top -= elemHeight; + } else if ( options.my[ 1 ] === "center" ) { + position.top -= elemHeight / 2; + } + + position.left += myOffset[ 0 ]; + position.top += myOffset[ 1 ]; + + collisionPosition = { + marginLeft: marginLeft, + marginTop: marginTop + }; + + $.each( [ "left", "top" ], function( i, dir ) { + if ( $.ui.position[ collision[ i ] ] ) { + $.ui.position[ collision[ i ] ][ dir ]( position, { + targetWidth: targetWidth, + targetHeight: targetHeight, + elemWidth: elemWidth, + elemHeight: elemHeight, + collisionPosition: collisionPosition, + collisionWidth: collisionWidth, + collisionHeight: collisionHeight, + offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ], + my: options.my, + at: options.at, + within: within, + elem: elem + } ); + } + } ); + + if ( options.using ) { + + // Adds feedback as second argument to using callback, if present + using = function( props ) { + var left = targetOffset.left - position.left, + right = left + targetWidth - elemWidth, + top = targetOffset.top - position.top, + bottom = top + targetHeight - elemHeight, + feedback = { + target: { + element: target, + left: targetOffset.left, + top: targetOffset.top, + width: targetWidth, + height: targetHeight + }, + element: { + element: elem, + left: position.left, + top: position.top, + width: elemWidth, + height: elemHeight + }, + horizontal: right < 0 ? "left" : left > 0 ? "right" : "center", + vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle" + }; + if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) { + feedback.horizontal = "center"; + } + if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) { + feedback.vertical = "middle"; + } + if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) { + feedback.important = "horizontal"; + } else { + feedback.important = "vertical"; + } + options.using.call( this, props, feedback ); + }; + } + + elem.offset( $.extend( position, { using: using } ) ); + } ); +}; + +$.ui.position = { + fit: { + left: function( position, data ) { + var within = data.within, + withinOffset = within.isWindow ? within.scrollLeft : within.offset.left, + outerWidth = within.width, + collisionPosLeft = position.left - data.collisionPosition.marginLeft, + overLeft = withinOffset - collisionPosLeft, + overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset, + newOverRight; + + // Element is wider than within + if ( data.collisionWidth > outerWidth ) { + + // Element is initially over the left side of within + if ( overLeft > 0 && overRight <= 0 ) { + newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - + withinOffset; + position.left += overLeft - newOverRight; + + // Element is initially over right side of within + } else if ( overRight > 0 && overLeft <= 0 ) { + position.left = withinOffset; + + // Element is initially over both left and right sides of within + } else { + if ( overLeft > overRight ) { + position.left = withinOffset + outerWidth - data.collisionWidth; + } else { + position.left = withinOffset; + } + } + + // Too far left -> align with left edge + } else if ( overLeft > 0 ) { + position.left += overLeft; + + // Too far right -> align with right edge + } else if ( overRight > 0 ) { + position.left -= overRight; + + // Adjust based on position and margin + } else { + position.left = max( position.left - collisionPosLeft, position.left ); + } + }, + top: function( position, data ) { + var within = data.within, + withinOffset = within.isWindow ? within.scrollTop : within.offset.top, + outerHeight = data.within.height, + collisionPosTop = position.top - data.collisionPosition.marginTop, + overTop = withinOffset - collisionPosTop, + overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset, + newOverBottom; + + // Element is taller than within + if ( data.collisionHeight > outerHeight ) { + + // Element is initially over the top of within + if ( overTop > 0 && overBottom <= 0 ) { + newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - + withinOffset; + position.top += overTop - newOverBottom; + + // Element is initially over bottom of within + } else if ( overBottom > 0 && overTop <= 0 ) { + position.top = withinOffset; + + // Element is initially over both top and bottom of within + } else { + if ( overTop > overBottom ) { + position.top = withinOffset + outerHeight - data.collisionHeight; + } else { + position.top = withinOffset; + } + } + + // Too far up -> align with top + } else if ( overTop > 0 ) { + position.top += overTop; + + // Too far down -> align with bottom edge + } else if ( overBottom > 0 ) { + position.top -= overBottom; + + // Adjust based on position and margin + } else { + position.top = max( position.top - collisionPosTop, position.top ); + } + } + }, + flip: { + left: function( position, data ) { + var within = data.within, + withinOffset = within.offset.left + within.scrollLeft, + outerWidth = within.width, + offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left, + collisionPosLeft = position.left - data.collisionPosition.marginLeft, + overLeft = collisionPosLeft - offsetLeft, + overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft, + myOffset = data.my[ 0 ] === "left" ? + -data.elemWidth : + data.my[ 0 ] === "right" ? + data.elemWidth : + 0, + atOffset = data.at[ 0 ] === "left" ? + data.targetWidth : + data.at[ 0 ] === "right" ? + -data.targetWidth : + 0, + offset = -2 * data.offset[ 0 ], + newOverRight, + newOverLeft; + + if ( overLeft < 0 ) { + newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - + outerWidth - withinOffset; + if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) { + position.left += myOffset + atOffset + offset; + } + } else if ( overRight > 0 ) { + newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + + atOffset + offset - offsetLeft; + if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) { + position.left += myOffset + atOffset + offset; + } + } + }, + top: function( position, data ) { + var within = data.within, + withinOffset = within.offset.top + within.scrollTop, + outerHeight = within.height, + offsetTop = within.isWindow ? within.scrollTop : within.offset.top, + collisionPosTop = position.top - data.collisionPosition.marginTop, + overTop = collisionPosTop - offsetTop, + overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop, + top = data.my[ 1 ] === "top", + myOffset = top ? + -data.elemHeight : + data.my[ 1 ] === "bottom" ? + data.elemHeight : + 0, + atOffset = data.at[ 1 ] === "top" ? + data.targetHeight : + data.at[ 1 ] === "bottom" ? + -data.targetHeight : + 0, + offset = -2 * data.offset[ 1 ], + newOverTop, + newOverBottom; + if ( overTop < 0 ) { + newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - + outerHeight - withinOffset; + if ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) { + position.top += myOffset + atOffset + offset; + } + } else if ( overBottom > 0 ) { + newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + + offset - offsetTop; + if ( newOverTop > 0 || abs( newOverTop ) < overBottom ) { + position.top += myOffset + atOffset + offset; + } + } + } + }, + flipfit: { + left: function() { + $.ui.position.flip.left.apply( this, arguments ); + $.ui.position.fit.left.apply( this, arguments ); + }, + top: function() { + $.ui.position.flip.top.apply( this, arguments ); + $.ui.position.fit.top.apply( this, arguments ); + } + } +}; + +} )(); + +var position = $.ui.position; + + +/*! + * jQuery UI Keycode 1.12.1 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + */ + +//>>label: Keycode +//>>group: Core +//>>description: Provide keycodes as keynames +//>>docs: http://api.jqueryui.com/jQuery.ui.keyCode/ + + +var keycode = $.ui.keyCode = { + BACKSPACE: 8, + COMMA: 188, + DELETE: 46, + DOWN: 40, + END: 35, + ENTER: 13, + ESCAPE: 27, + HOME: 36, + LEFT: 37, + PAGE_DOWN: 34, + PAGE_UP: 33, + PERIOD: 190, + RIGHT: 39, + SPACE: 32, + TAB: 9, + UP: 38 +}; + + +/*! + * jQuery UI Unique ID 1.12.1 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + */ + +//>>label: uniqueId +//>>group: Core +//>>description: Functions to generate and remove uniqueId's +//>>docs: http://api.jqueryui.com/uniqueId/ + + + +var uniqueId = $.fn.extend( { + uniqueId: ( function() { + var uuid = 0; + + return function() { + return this.each( function() { + if ( !this.id ) { + this.id = "ui-id-" + ( ++uuid ); + } + } ); + }; + } )(), + + removeUniqueId: function() { + return this.each( function() { + if ( /^ui-id-\d+$/.test( this.id ) ) { + $( this ).removeAttr( "id" ); + } + } ); + } +} ); + + + +var safeActiveElement = $.ui.safeActiveElement = function( document ) { + var activeElement; + + // Support: IE 9 only + // IE9 throws an "Unspecified error" accessing document.activeElement from an