diff --git a/distro/web.xml b/distro/web.xml index 7e23ce4..efa36ab 100644 --- a/distro/web.xml +++ b/distro/web.xml @@ -5,6 +5,11 @@ 52°North Web Processing Service, Git: 1665e1b7b2188755161d4f0f3a6acf562d0444e1 @ 2015-03-21 00:30:20 A web processing framework supporting the OGC WPS 1.0.0 specification + + algorithmDirectory + /home/gcube/wps_algorithms/algorithms + + 0 diff --git a/pom.xml b/pom.xml index 10fac50..132842c 100644 --- a/pom.xml +++ b/pom.xml @@ -104,9 +104,32 @@ xerces xercesImpl 2.11.0 - runtime - + + + org.gcube.core + common-smartgears + + + org.gcube.core + common-smartgears-app + + + + + org.gcube.common + common-authorization + + + org.gcube.core + common-scope + + + + + + + org.geotools gt-main @@ -279,6 +302,10 @@ commons-logging commons-logging + + xml-apis + xml-apis + diff --git a/src/main/java/org/gcube/data/analysis/wps/CancelComputation.java b/src/main/java/org/gcube/data/analysis/wps/CancelComputation.java new file mode 100644 index 0000000..b97c2f7 --- /dev/null +++ b/src/main/java/org/gcube/data/analysis/wps/CancelComputation.java @@ -0,0 +1,162 @@ +package org.gcube.data.analysis.wps; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.util.UUID; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang.StringUtils; +import org.n52.wps.commons.XMLUtil; +import org.n52.wps.server.database.DatabaseFactory; +import org.n52.wps.server.database.IDatabase; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class CancelComputation extends HttpServlet { + + private final static Logger LOGGER = LoggerFactory.getLogger(CancelComputation.class); + private static final long serialVersionUID = -268198171054599696L; + // This is required for URL generation for response documents. + public final static String SERVLET_PATH = "RetrieveResultServlet"; + // in future parameterize + //private final boolean indentXML = false; + + private final int uuid_length = 36; + + @Override + public void init(ServletConfig config) throws ServletException { + super.init(config); + } + + public static String empty = " " + + " " + + ""; + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + + // id of result to retrieve. + String id = request.getParameter("id"); + + LOGGER.debug("CANCEL COMPUTATION -> RETRIEVING ID " + id); + if (StringUtils.isEmpty(id)) { + errorResponse("id parameter missing", response); + } else { + LOGGER.debug("CANCEL COMPUTATION -> ID RETRIEVED " + id); + if (!isIDValid(id)) { + errorResponse("id parameter not valid", response); + } + LOGGER.debug("CANCEL COMPUTATION -> ID IS VALID " + id); + IDatabase db = DatabaseFactory.getDatabase(); + long len = db.getContentLengthForStoreResponse(id); + LOGGER.debug("CANCEL COMPUTATION -> INITIAL ID RESPONSE LENGTH " + len); + + try { + LOGGER.debug("CANCEL COMPUTATION -> DELETING ID " + id); + + try { +// String empty = ""; + InputStream stream = new ByteArrayInputStream(empty.getBytes("UTF-8")); + db.updateResponse(id, stream); + stream.close(); + } catch (Exception e) { + LOGGER.error("error reading th einput stream",e); + } + LOGGER.debug("CANCEL COMPUTATION -> ID DELETED " + id); + len = db.getContentLengthForStoreResponse(id); + LOGGER.debug("CANCEL COMPUTATION -> ID RESPONSE LENGTH " + len); + } catch (Exception e) { + LOGGER.error("error in do get",e); + } finally { + } + } + } + + protected void errorResponse(String error, HttpServletResponse response) throws IOException { + response.setContentType("text/html"); + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + PrintWriter writer = response.getWriter(); + writer.write("Error" + error + ""); + writer.flush(); + LOGGER.warn("Error processing response: " + error); + } + + protected void copyResponseStream(InputStream inputStream, OutputStream outputStream, String id, long contentLength) throws IOException { + long contentWritten = 0; + try { + byte[] buffer = new byte[8192]; + int bufferRead; + while ((bufferRead = inputStream.read(buffer)) != -1) { + outputStream.write(buffer, 0, bufferRead); + contentWritten += bufferRead; + } + } catch (IOException e) { + String exceptionMessage = contentLength > -1 ? String.format("Error writing response to output stream for id %s, %d of %d bytes written", id, contentWritten, contentLength) : String.format("Error writing response to output stream for id %s, %d bytes written", id, contentWritten); + throw new IOException(exceptionMessage, e); + } + LOGGER.info("{} bytes written in response to id {}", contentWritten, id); + } + + protected void copyResponseAsXML(InputStream inputStream, OutputStream outputStream, boolean indent, String id) throws IOException { + try { + XMLUtil.copyXML(inputStream, outputStream, indent); + } catch (IOException e) { + throw new IOException("Error writing XML response for id " + id, e); + } + } + + public static Throwable getRootCause(Throwable t) { + return t.getCause() == null ? t : getRootCause(t.getCause()); + } + + public boolean isIDValid(String id) { + + if (id.length() <= uuid_length) { + + try { + UUID checkUUID = UUID.fromString(id); + + if (checkUUID.toString().equals(id)) { + return true; + } else { + return false; + } + } catch (Exception e) { + return false; + } + + } else { + + String uuidPartOne = id.substring(0, uuid_length); + String uuidPartTwo = id.substring(id.length() - uuid_length, id.length()); + + return isUUIDValid(uuidPartOne) && isUUIDValid(uuidPartTwo); + } + } + + public boolean isUUIDValid(String uuid) { + + // the following can be used to check whether the id is a valid UUID + try { + UUID checkUUID = UUID.fromString(uuid); + + if (checkUUID.toString().equals(uuid)) { + return true; + } else { + return false; + } + } catch (Exception e) { + return false; + } + } +} diff --git a/src/main/java/org/gcube/data/analysis/wps/ExecuteResponse.java b/src/main/java/org/gcube/data/analysis/wps/ExecuteResponse.java new file mode 100644 index 0000000..4007bd9 --- /dev/null +++ b/src/main/java/org/gcube/data/analysis/wps/ExecuteResponse.java @@ -0,0 +1,31 @@ +package org.gcube.data.analysis.wps; + +import java.io.InputStream; + +import org.n52.wps.server.ExceptionReport; +import org.n52.wps.server.request.ExecuteRequest; +import org.n52.wps.server.response.ExecuteResponseBuilder; +import org.n52.wps.server.response.Response; + +public class ExecuteResponse extends Response { + + private ExecuteResponseBuilder builder; + + public ExecuteResponse(ExecuteRequest request) throws ExceptionReport{ + super(request); + this.builder = ((ExecuteRequest)this.request).getExecuteResponseBuilder(); + } + + @Override + public InputStream getAsStream() throws ExceptionReport{ + return this.builder.getAsStream(); + } + + public ExecuteResponseBuilder getExecuteResponseBuilder(){ + return builder; + } + + public String getMimeType(){ + return builder.getMimeType(); + } +} \ No newline at end of file diff --git a/src/main/java/org/gcube/data/analysis/wps/GetCapabilitiesBuilder.java b/src/main/java/org/gcube/data/analysis/wps/GetCapabilitiesBuilder.java new file mode 100644 index 0000000..8fb2875 --- /dev/null +++ b/src/main/java/org/gcube/data/analysis/wps/GetCapabilitiesBuilder.java @@ -0,0 +1,132 @@ +package org.gcube.data.analysis.wps; + +import java.io.InputStream; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.io.IOUtils; +import org.gcube.common.scope.api.ScopeProvider; +import org.gcube.data.analysis.wps.repository.GcubeAlgorithmRepository; +import org.gcube.dataanalysis.ecoengine.processing.factories.ProcessorsFactory; +import org.gcube.dataanalysis.wps.statisticalmanager.synchserver.infrastructure.InfrastructureDialoguer; +import org.gcube.dataanalysis.wps.statisticalmanager.synchserver.mapping.ConfigurationManager; +import org.gcube.dataanalysis.wps.statisticalmanager.synchserver.mapping.TokenManager; +import org.n52.wps.commons.WPSConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class GetCapabilitiesBuilder { + + public static String processString = "\n\t#CLASS#\n\t#TITLE#\n"; + + private static final Logger LOGGER= LoggerFactory.getLogger(GetCapabilitiesBuilder.class); + + public String getClassification(String algorithmName, ConfigurationManager configManager) throws Exception{ + //get algorithms classification: + LOGGER.debug("Searching for a classification of "+algorithmName); + HashMap> algorithmsClassification = ProcessorsFactory.getAllFeaturesUser(configManager.getConfig()); + String rightClassification = "Others"; + for (String classification:algorithmsClassification.keySet()){ + List algorithms = algorithmsClassification.get(classification); + if (algorithms.contains(algorithmName)){ + LOGGER.debug("Found classification"+classification); + return classification; + } + } + LOGGER.debug("No classification found for "+algorithmName); + return rightClassification; + } + + public String buildGetCapabilities(Map parameters) throws Exception { + + LinkedHashMap basicInputs = new LinkedHashMap(); + //DONE get scope and username from SmartGears to build the get capabilities + /* OLD CODE + if (parameters != null) { + if (parameters.get(ConfigurationManager.scopeParameter) != null) + basicInputs.put(ConfigurationManager.scopeParameter, parameters.get(ConfigurationManager.scopeParameter)[0]); + if (parameters.get(ConfigurationManager.usernameParameter) != null) + basicInputs.put(ConfigurationManager.usernameParameter, parameters.get(ConfigurationManager.usernameParameter)[0]); + } else {// case for testing purposes only + if (AbstractEcologicalEngineMapper.simulationMode){ + basicInputs.put(ConfigurationManager.scopeParameter, ConfigurationManager.defaultScope); + basicInputs.put(ConfigurationManager.usernameParameter, ConfigurationManager.defaultUsername); + } + } + */ + ConfigurationManager configManager = new ConfigurationManager(); + TokenManager tokenm = new TokenManager(); + tokenm.getCredentials(); + String scope = tokenm.getScope(); + String username = tokenm.getUserName(); + String token = tokenm.getToken(); + basicInputs.put(ConfigurationManager.scopeParameter, scope); + basicInputs.put(ConfigurationManager.usernameParameter, username); + basicInputs.put(ConfigurationManager.tokenParameter, token); + + configManager.configAlgorithmEnvironment(basicInputs); + LOGGER.debug("Initializing Capabilities Skeleton in scope " + configManager.getScope() + " with user " + configManager.getUsername()); + InputStream is = this.getClass().getClassLoader().getResourceAsStream("templates/wpsCapabilitiesSkeleton.xml"); + String stringTemplate = IOUtils.toString(is, "UTF-8"); + + //TODO: GET HOSTNAME AND PORT from container + String host = WPSConfig.getInstance().getWPSConfig().getServer().getHostname(); + String port = WPSConfig.getInstance().getWPSConfig().getServer().getHostport(); + stringTemplate = stringTemplate.replace("#HOST#", host).replace("#PORT#", port); + + LOGGER.debug("Host: " + host + " Port: " + port); + + LinkedHashMap allalgorithms = new LinkedHashMap(); + /* + String packageS = "org.gcube.dataanalysis.wps.statisticalmanager.synchserver.mappedclasses"; + List> classes = null; + try{ + LOGGER.debug("Taking classes from /classes"); + classes = GetCapabilitiesChecker.find(packageS); + }catch(Exception e){ + LOGGER.debug("Taking classes from the Jar"); + classes=GetCapabilitiesChecker.getClassesInSamePackageFromJar(packageS); + }*/ + + LOGGER.info("using classloader class {} ",Thread.currentThread().getContextClassLoader().getClass().getSimpleName()); + + + Set> algorithmsClass = GcubeAlgorithmRepository.getAllAlgorithms(); + + LOGGER.info("class found with annotation Algorithm are {}",algorithmsClass.size()); + + for (Class classfind : algorithmsClass) { + org.n52.wps.algorithm.annotation.Algorithm algorithmInfo = classfind.getAnnotation(org.n52.wps.algorithm.annotation.Algorithm.class); + if (algorithmInfo != null) { + LOGGER.debug("Retrieving local declared Algorithm: " + algorithmInfo.title()); + allalgorithms.put(algorithmInfo.title(), classfind.getName()); + } + } + + LOGGER.debug("Getting algorithms from the infrastructure"); + InfrastructureDialoguer dialoguer = new InfrastructureDialoguer(configManager.getScope()); + List algorithmsInScope = dialoguer.getAlgorithmsInScope(); + LOGGER.debug("Found {} algorithms in scope {} ",algorithmsInScope.size() ,ScopeProvider.instance.get()); + StringBuffer capabilities = new StringBuffer(); + + for (String algorithmInScope : algorithmsInScope) { + String classAlgorithm = allalgorithms.get(algorithmInScope); + if (classAlgorithm != null) { + LOGGER.debug("Approving " + classAlgorithm + " to capabilities "); + String algorithmTitle = getClassification(algorithmInScope, configManager)+":"+algorithmInScope; +// String algorithmTitle = algorithmInScope; + capabilities.append(processString.replace("#TITLE#", algorithmTitle).replace("#CLASS#", classAlgorithm)); + } + } + + stringTemplate = stringTemplate.replace("#PROCESSES#", capabilities.toString()); + LOGGER.debug("Get capabilities built"); + return stringTemplate; + } + + + +} diff --git a/src/main/java/org/gcube/data/analysis/wps/RequestHandler.java b/src/main/java/org/gcube/data/analysis/wps/RequestHandler.java new file mode 100644 index 0000000..87ed152 --- /dev/null +++ b/src/main/java/org/gcube/data/analysis/wps/RequestHandler.java @@ -0,0 +1,429 @@ +package org.gcube.data.analysis.wps; +/** + * Copyright (C) 2007 - 2014 52°North Initiative for Geospatial Open Source + * Software GmbH + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * If the program is linked with libraries which are licensed under one of + * the following licenses, the combination of the program with the linked + * library is not considered a "derivative work" of the program: + * + * • Apache License, version 2.0 + * • Apache Software License, version 1.0 + * • GNU Lesser General Public License, version 3 + * • Mozilla Public License, versions 1.0, 1.1 and 2.0 + * • Common Development and Distribution License (CDDL), version 1.0 + * + * Therefore the distribution of the program linked with libraries licensed + * under the aforementioned licenses, is permitted by the copyright holders + * if the distribution is compliant with both the GNU General Public + * License version 2 and the aforementioned licenses. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. +org.gcube.dataanalysis.wps.statisticalmanager.synchserver.weberver.handler; +*/ + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.RejectedExecutionException; + +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.apache.commons.collections.map.CaseInsensitiveMap; +import org.apache.commons.io.IOUtils; +import org.gcube.common.authorization.library.AuthorizedTasks; +import org.n52.wps.server.ExceptionReport; +import org.n52.wps.server.WebProcessingService; +import org.n52.wps.server.handler.RequestExecutor; +import org.n52.wps.server.request.CapabilitiesRequest; +import org.n52.wps.server.request.DescribeProcessRequest; +import org.n52.wps.server.request.ExecuteRequest; +import org.n52.wps.server.request.Request; +import org.n52.wps.server.request.RetrieveResultRequest; +import org.n52.wps.server.response.Response; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.xml.sax.SAXException; + + +public class RequestHandler { + + public static final String VERSION_ATTRIBUTE_NAME = "version"; + + /** Computation timeout in seconds */ + protected static RequestExecutor pool = new RequestExecutor(); + + protected OutputStream os; + + private static Logger LOGGER = LoggerFactory.getLogger(RequestHandler.class); + + protected String responseMimeType; + + protected Request req; + + // Empty constructor due to classes which extend the RequestHandler + protected RequestHandler() { + + } + private Map params; + /** + * Handles requests of type HTTP_GET (currently capabilities and + * describeProcess). A Map is used to represent the client input. + * + * @param params + * The client input + * @param os + * The OutputStream to write the response to. + * @throws ExceptionReport + * If the requested operation is not supported + */ + public RequestHandler(Map params, OutputStream os) + throws ExceptionReport { + this.os = os; + this.params=params; + //sleepingTime is 0, by default. + /*if(WPSConfiguration.getInstance().exists(PROPERTY_NAME_COMPUTATION_TIMEOUT)) { + this.sleepingTime = Integer.parseInt(WPSConfiguration.getInstance().getProperty(PROPERTY_NAME_COMPUTATION_TIMEOUT)); + } + String sleepTime = WPSConfig.getInstance().getWPSConfig().getServer().getComputationTimeoutMilliSeconds(); + */ + + + Request req; + CaseInsensitiveMap ciMap = new CaseInsensitiveMap(params); + + /* + * check if service parameter is present and equals "WPS" + * otherwise an ExceptionReport will be thrown + */ + String serviceType = Request.getMapValue("service", ciMap, true); + + if(!serviceType.equalsIgnoreCase("WPS")){ + throw new ExceptionReport("Parameter is not correct, expected: WPS, got: " + serviceType, + ExceptionReport.INVALID_PARAMETER_VALUE, "service"); + } + + /* + * check language. if not supported, return ExceptionReport + * Fix for https://bugzilla.52north.org/show_bug.cgi?id=905 + */ + String language = Request.getMapValue("language", ciMap, false); + + if(language != null){ + Request.checkLanguageSupported(language); + } + + // get the request type + String requestType = Request.getMapValue("request", ciMap, true); + + if (requestType.equalsIgnoreCase("GetCapabilities")) { + req = new CapabilitiesRequest(ciMap); + } + else if (requestType.equalsIgnoreCase("DescribeProcess")) { + req = new DescribeProcessRequest(ciMap); + } + else if (requestType.equalsIgnoreCase("Execute")) { + req = new ExecuteRequest(ciMap); + setResponseMimeType((ExecuteRequest)req); + } + else if (requestType.equalsIgnoreCase("RetrieveResult")) { + req = new RetrieveResultRequest(ciMap); + } + else { + throw new ExceptionReport( + "The requested Operation is not supported or not applicable to the specification: " + + requestType, + ExceptionReport.OPERATION_NOT_SUPPORTED, requestType); + } + + this.req = req; + } + + /** + * Handles requests of type HTTP_POST (currently executeProcess). A Document + * is used to represent the client input. This Document must first be parsed + * from an InputStream. + * + * @param is + * The client input + * @param os + * The OutputStream to write the response to. + * @throws ExceptionReport + */ + public RequestHandler(InputStream is, OutputStream os) + throws ExceptionReport { + String nodeName, localName, nodeURI, version = null; + Document doc; + this.os = os; + + boolean isCapabilitiesNode = false; + + try { + LOGGER.trace("Parsing Document..."); + System.setProperty("javax.xml.parsers.DocumentBuilderFactory", "org.apache.xerces.jaxp.DocumentBuilderFactoryImpl"); + + DocumentBuilderFactory fac = DocumentBuilderFactory.newInstance(); + fac.setNamespaceAware(true); + + // parse the InputStream to create a Document + doc = fac.newDocumentBuilder().parse(is); + + LOGGER.trace("Document Parsing OK"); + // Get the first non-comment child. + Node child = doc.getFirstChild(); + while(child.getNodeName().compareTo("#comment")==0) { + child = child.getNextSibling(); + } + LOGGER.trace("Skipped comments OK"); + nodeName = child.getNodeName(); + localName = child.getLocalName(); + nodeURI = child.getNamespaceURI(); + Node versionNode = child.getAttributes().getNamedItem("version"); + LOGGER.trace("Version OK"); + /* + * check for service parameter. this has to be present for all requests + */ + Node serviceNode = child.getAttributes().getNamedItem("service"); + + if(serviceNode == null){ + throw new ExceptionReport("Parameter not specified.", ExceptionReport.MISSING_PARAMETER_VALUE, "service"); + }else{ + if(!serviceNode.getNodeValue().equalsIgnoreCase("WPS")){ + throw new ExceptionReport("Parameter not specified.", ExceptionReport.INVALID_PARAMETER_VALUE, "service"); + } + } + LOGGER.trace("Service Node OK"); + + isCapabilitiesNode = nodeName.toLowerCase().contains("capabilities"); + if(versionNode == null && !isCapabilitiesNode) { + throw new ExceptionReport("Parameter not specified.", ExceptionReport.MISSING_PARAMETER_VALUE, "version"); + } + if(!isCapabilitiesNode){ +// version = child.getFirstChild().getTextContent();//.getNextSibling().getFirstChild().getNextSibling().getFirstChild().getNodeValue(); + version = child.getAttributes().getNamedItem("version").getNodeValue(); + } + + LOGGER.trace("Capabilities Node OK"); + /* + * check language, if not supported, return ExceptionReport + * Fix for https://bugzilla.52north.org/show_bug.cgi?id=905 + */ + Node languageNode = child.getAttributes().getNamedItem("language"); + if(languageNode != null){ + String language = languageNode.getNodeValue(); + Request.checkLanguageSupported(language); + } + + LOGGER.trace("Language Node OK "+languageNode); + + } catch (SAXException e) { + throw new ExceptionReport( + "There went something wrong with parsing the POST data: " + + e.getMessage(), + ExceptionReport.NO_APPLICABLE_CODE, e); + } catch (IOException e) { + throw new ExceptionReport( + "There went something wrong with the network connection.", + ExceptionReport.NO_APPLICABLE_CODE, e); + } catch (ParserConfigurationException e) { + throw new ExceptionReport( + "There is a internal parser configuration error", + ExceptionReport.NO_APPLICABLE_CODE, e); + } + //Fix for Bug 904 https://bugzilla.52north.org/show_bug.cgi?id=904 + if(!isCapabilitiesNode && version == null) { + LOGGER.error("EXCEPTION: Parameter not specified." + ExceptionReport.MISSING_PARAMETER_VALUE + " version"); + throw new ExceptionReport("Parameter not specified." , ExceptionReport.MISSING_PARAMETER_VALUE, "version"); + } + if(!isCapabilitiesNode && !version.equals(Request.SUPPORTED_VERSION)) { + LOGGER.error("EXCEPTION: Version not supported." + ExceptionReport.INVALID_PARAMETER_VALUE + "version"); + throw new ExceptionReport("Version not supported." , ExceptionReport.INVALID_PARAMETER_VALUE, "version"); + } + // get the request type + if (nodeURI.equals(WebProcessingService.WPS_NAMESPACE) && localName.equals("Execute")) { + LOGGER.debug("Detected Request to Execute!"); + req = new ExecuteRequest(doc); + setResponseMimeType((ExecuteRequest)req); + LOGGER.debug("Request to Execute Configured!"); + }else if (nodeURI.equals(WebProcessingService.WPS_NAMESPACE) && localName.equals("GetCapabilities")){ + LOGGER.debug("Detected GetCapabilities!"); + req = new CapabilitiesRequest(doc); + this.responseMimeType = "text/xml"; + } else if (nodeURI.equals(WebProcessingService.WPS_NAMESPACE) && localName.equals("DescribeProcess")) { + LOGGER.debug("Detected DescribeProcess!"); + req = new DescribeProcessRequest(doc); + this.responseMimeType = "text/xml"; + + } else if(!localName.equals("Execute")){ + LOGGER.error("EXCEPTION Detected NON-supported Request "+"The requested Operation not supported or not applicable to the specification: "+ nodeName + ExceptionReport.OPERATION_NOT_SUPPORTED + localName); + throw new ExceptionReport("The requested Operation not supported or not applicable to the specification: " + + nodeName, ExceptionReport.OPERATION_NOT_SUPPORTED, localName); + } + else if(nodeURI.equals(WebProcessingService.WPS_NAMESPACE)) { + LOGGER.error("specified namespace is not supported: "+ nodeURI + ExceptionReport.INVALID_PARAMETER_VALUE); + throw new ExceptionReport("specified namespace is not supported: " + + nodeURI, ExceptionReport.INVALID_PARAMETER_VALUE); + } + } + + /** + * Handle a request after its type is determined. The request is scheduled + * for execution. If the server has enough free resources, the client will + * be served immediately. If time runs out, the client will be asked to come + * back later with a reference to the result. + * + * @param req The request of the client. + * @throws ExceptionReport + */ + public void handle() throws ExceptionReport { + Response resp = null; + if(req ==null){ + throw new ExceptionReport("Internal Error",""); + } + if (req instanceof ExecuteRequest) { + LOGGER.debug("Request for execution"); + // cast the request to an executerequest + ExecuteRequest execReq = (ExecuteRequest) req; + LOGGER.debug("Accepted request for execution"); + execReq.updateStatusAccepted(); + //modification by GP 26-05-2015 to account for multi user and scopes + Callable execCallable = AuthorizedTasks.bind(execReq); + ExceptionReport exceptionReport = null; + try { + if (execReq.isStoreResponse()) { + LOGGER.debug("Execution with output storing"); + resp = new ExecuteResponse(execReq); + InputStream is = resp.getAsStream(); + IOUtils.copy(is, os); + is.close(); +// pool.submit(execReq); + pool.submit(execCallable); + return; + } + try { + LOGGER.debug("Execution without storing output"); + // retrieve status with timeout enabled + try { + resp = pool.submit(execCallable).get(); + } + catch (ExecutionException ee) { + LOGGER.warn("exception while handling ExecuteRequest.",ee); + // the computation threw an error + // probably the client input is not valid + if (ee.getCause() instanceof ExceptionReport) { + exceptionReport = (ExceptionReport) ee + .getCause(); + } else { + exceptionReport = new ExceptionReport( + "An error occurred in the computation: " + + ee.getMessage(), + ExceptionReport.NO_APPLICABLE_CODE); + } + } catch (InterruptedException ie) { + LOGGER.warn("interrupted while handling ExecuteRequest.",ie); + + // interrupted while waiting in the queue + exceptionReport = new ExceptionReport( + "The computation in the process was interrupted.", + ExceptionReport.NO_APPLICABLE_CODE); + } + } finally { + if (exceptionReport != null) { + LOGGER.warn("ExceptionReport not null",exceptionReport); + // NOT SURE, if this exceptionReport is also written to the DB, if required... test please! + throw exceptionReport; + } + // send the result to the outputstream of the client. + /* if(((ExecuteRequest) req).isQuickStatus()) { + resp = new ExecuteResponse(execReq); + }*/ + else if(resp == null) { + LOGGER.warn("null response handling ExecuteRequest."); + throw new ExceptionReport("Problem with handling threads in RequestHandler", ExceptionReport.NO_APPLICABLE_CODE); + } + if(!execReq.isStoreResponse()) { + InputStream is = resp.getAsStream(); + IOUtils.copy(is, os); + is.close(); + LOGGER.info("Served ExecuteRequest."); + } + } + } catch (RejectedExecutionException ree) { + LOGGER.warn("exception handling ExecuteRequest.", ree); + // server too busy? + throw new ExceptionReport( + "The requested process was rejected. Maybe the server is flooded with requests.", + ExceptionReport.SERVER_BUSY); + } catch (Exception e) { + LOGGER.error("exception handling ExecuteRequest.", e); + if (e instanceof ExceptionReport) { + throw (ExceptionReport)e; + } + throw new ExceptionReport("Could not read from response stream.", ExceptionReport.NO_APPLICABLE_CODE); + } + } else { + // for GetCapabilities and DescribeProcess: + + resp = req.call(); + + try { + InputStream is = null; + if (req instanceof CapabilitiesRequest){ + GetCapabilitiesBuilder builder = new GetCapabilitiesBuilder(); + String getCapabilitiesStringFromInfra = ""; + try { + getCapabilitiesStringFromInfra = builder.buildGetCapabilities(params); + } catch (Exception e) { + throw new ExceptionReport("Error in building GetCapabilities","getcapabilities",e); + } + is = IOUtils.toInputStream(getCapabilitiesStringFromInfra, "UTF-8"); + } + else + is = resp.getAsStream(); + + IOUtils.copy(is, os); + is.close(); + } catch (IOException e) { + throw new ExceptionReport("Could not read from response stream.", ExceptionReport.NO_APPLICABLE_CODE); + } + + } + } + + protected void setResponseMimeType(ExecuteRequest req) { + if(req.isRawData()){ + responseMimeType = req.getExecuteResponseBuilder().getMimeType(); + }else{ + responseMimeType = "text/xml"; + } + + + } + + + + public String getResponseMimeType(){ + if(responseMimeType == null){ + return "text/xml"; + } + return responseMimeType.toLowerCase(); + } + + +} + + + diff --git a/src/main/java/org/gcube/data/analysis/wps/WebProcessingService.java b/src/main/java/org/gcube/data/analysis/wps/WebProcessingService.java new file mode 100644 index 0000000..36cbd40 --- /dev/null +++ b/src/main/java/org/gcube/data/analysis/wps/WebProcessingService.java @@ -0,0 +1,435 @@ +package org.gcube.data.analysis.wps; +/** + * Copyright (C) 2007 - 2014 52°North Initiative for Geospatial Open Source + * Software GmbH + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * If the program is linked with libraries which are licensed under one of + * the following licenses, the combination of the program with the linked + * library is not considered a "derivative work" of the program: + * + * • Apache License, version 2.0 + * • Apache Software License, version 1.0 + * • GNU Lesser General Public License, version 3 + * • Mozilla Public License, versions 1.0, 1.1 and 2.0 + * • Common Development and Distribution License (CDDL), version 1.0 + * + * Therefore the distribution of the program linked with libraries licensed + * under the aforementioned licenses, is permitted by the copyright holders + * if the distribution is compliant with both the GNU General Public + * License version 2 and the aforementioned licenses. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. +org.gcube.dataanalysis.wps.statisticalmanager.synchserver.capabilities52.wps.server; + */ +// FvK: added Property Change Listener support +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.io.StringWriter; +import java.net.URLDecoder; +import java.util.Map; +import java.util.zip.GZIPOutputStream; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.xmlbeans.XmlException; +import org.gcube.data.analysis.wps.repository.AlgorithmUpdater; +import org.gcube.data.analysis.wps.repository.GcubeAlgorithmRepository; +import org.gcube.smartgears.ContextProvider; +import org.gcube.smartgears.context.application.ApplicationContext; +import org.n52.wps.GeneratorDocument.Generator; +import org.n52.wps.ParserDocument.Parser; +import org.n52.wps.commons.WPSConfig; +import org.n52.wps.io.GeneratorFactory; +import org.n52.wps.io.ParserFactory; +import org.n52.wps.server.CapabilitiesConfiguration; +import org.n52.wps.server.ExceptionReport; +import org.n52.wps.server.database.DatabaseFactory; +import org.n52.wps.util.XMLBeansHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This WPS supports HTTP GET for describeProcess and getCapabilities and XML-POST for execute. + * + * @author foerster + * + */ +public class WebProcessingService extends HttpServlet { + + // Universal version identifier for a Serializable class. + // Should be used here, because HttpServlet implements the java.io.Serializable + private static final long serialVersionUID = 8943233273641771839L; + public static String PROPERTY_NAME_WEBAPP_PATH = "webappPath"; + public static String BASE_DIR = null; + public static String WEBAPP_PATH = null; + public static String SERVLET_PATH = "WebProcessingService"; + public static String WPS_NAMESPACE = "http://www.opengis.net/wps/1.0.0"; + public static String DEFAULT_LANGUAGE = "en-US"; + protected static Logger LOGGER = LoggerFactory.getLogger(WebProcessingService.class); + + private static final String DIRECTORY_PARAM = "algorithmDirectory"; + + private ApplicationContext context = ContextProvider.get(); + + + + + @Override + public void init() throws ServletException { + String dir = (String)context.application().getInitParameter(DIRECTORY_PARAM); + GcubeAlgorithmRepository.setUpdater(new AlgorithmUpdater(dir)); + } + + /** + * + * Returns a preconfigured OutputStream It takes care of: - caching - content-Encoding + * + * @param hsRequest + * the HttpServletRequest + * @param hsResponse + * the HttpServlerResponse + * @return the preconfigured OutputStream + * @throws IOException + * a task of the tomcat + */ + @SuppressWarnings("unused") + private static OutputStream getConfiguredOutputStream(HttpServletRequest hsRequest, HttpServletResponse hsResponse) throws IOException { + /* + * Forbids clients to cache the response May solve problems with proxies and bad implementations + */ + + hsResponse.setHeader("Expires", "0"); + if (hsRequest.getProtocol().equals("HTTP/1.1")) { + hsResponse.setHeader("Cache-Control", "no-cache"); + } else if (hsRequest.getProtocol().equals("HTTP/1.0")) { + hsResponse.setHeader("Pragma", "no-cache"); + } + + // Enable/disable gzip compression + if (hsRequest.getHeader("Accept-Encoding") != null + && hsRequest.getHeader("Accept-Encoding").indexOf("gzip") >= 0) { + hsResponse.setHeader("Content-Encoding", "gzip"); + LOGGER.info("gzip-Compression for output enabled"); + return new GZIPOutputStream(hsResponse.getOutputStream()); + } // else { + LOGGER.info("gzip-Compression for output disabled"); + return hsResponse.getOutputStream(); + // } + } + + @Override + public void init(ServletConfig config) throws ServletException { + super.init(config); + + // this is important to set the lon lat support for correct CRS transformation. + + System.setProperty("org.geotools.referencing.forceXY", "true"); + + LOGGER.info("WebProcessingService initializing..."); + + try { + if (WPSConfig.getInstance(config) == null) { + LOGGER.error("Initialization failed! Please look at the properties file!"); + return; + } + } + catch (Exception e) { + LOGGER.error("Initialization failed! Please look at the properties file!", e); + return; + } + LOGGER.info("Initialization of wps properties successful!"); + + BASE_DIR = this.getServletContext().getRealPath(""); + + Parser[] parsers = WPSConfig.getInstance().getActiveRegisteredParser(); + ParserFactory.initialize(parsers); + + Generator[] generators = WPSConfig.getInstance().getActiveRegisteredGenerator(); + GeneratorFactory.initialize(generators); + + // call RepositoyManager to initialize + LOGGER.info("Algorithms initialized"); + + // String customWebappPath = WPSConfiguration.getInstance().getProperty(PROPERTY_NAME_WEBAPP_PATH); + String customWebappPath = WPSConfig.getInstance().getWPSConfig().getServer().getWebappPath(); + if (customWebappPath != null) { + WEBAPP_PATH = customWebappPath; + } + else { + WEBAPP_PATH = "wps"; + LOGGER.warn("No custom webapp path found, use default wps"); + } + LOGGER.info("webappPath is set to: " + customWebappPath); + + try { + CapabilitiesConfiguration.getInstance(BASE_DIR + File.separator + "config" + + File.separator + "wpsCapabilitiesSkeleton.xml"); + } + catch (IOException e) { + LOGGER.error("error while initializing capabilitiesConfiguration", e); + } + catch (XmlException e) { + LOGGER.error("error while initializing capabilitiesConfiguration", e); + } + + // Get an instance of the database for initialization of the database + DatabaseFactory.getDatabase(); + + LOGGER.info("WPS up and running!"); + + // FvK: added Property Change Listener support + // creates listener and register it to the wpsConfig instance. + // it will listen to changes of the wpsCapabilities + WPSConfig.getInstance().addPropertyChangeListener(org.n52.wps.commons.WPSConfig.WPSCAPABILITIES_SKELETON_PROPERTY_EVENT_NAME, + new PropertyChangeListener() { + @Override + public void propertyChange(final PropertyChangeEvent propertyChangeEvent) { + LOGGER.info(this.getClass().getName() + + ": Received Property Change Event: " + + propertyChangeEvent.getPropertyName()); + try { + CapabilitiesConfiguration.reloadSkeleton(); + } + catch (IOException e) { + LOGGER.error("error while initializing capabilitiesConfiguration", + e); + } + catch (XmlException e) { + LOGGER.error("error while initializing capabilitiesConfiguration", + e); + } + } + }); + + // FvK: added Property Change Listener support + // creates listener and register it to the wpsConfig instance. + // it will listen to changes of the wpsConfiguration + WPSConfig.getInstance().addPropertyChangeListener(org.n52.wps.commons.WPSConfig.WPSCONFIG_PROPERTY_EVENT_NAME, + new PropertyChangeListener() { + public void propertyChange(final PropertyChangeEvent propertyChangeEvent) { + LOGGER.info(this.getClass().getName() + + ": Received Property Change Event: " + + propertyChangeEvent.getPropertyName()); + try { + CapabilitiesConfiguration.reloadSkeleton(); + } + catch (IOException e) { + LOGGER.error("error while initializing capabilitiesConfiguration", + e); + } + catch (XmlException e) { + LOGGER.error("error while initializing capabilitiesConfiguration", + e); + } + } + }); + + } + + protected void setServerParameters(){ + //String endpoint = CapabilitiesConfiguration.ENDPOINT_URL; + + String webapp = context.application().getContextPath().replace("//", ""); + WPSConfig.getInstance().getWPSConfig().getServer().setWebappPath(webapp); + + + String host = WPSConfig.getInstance().getWPSConfig().getServer().getHostname(); + String port = WPSConfig.getInstance().getWPSConfig().getServer().getHostport(); + + if (host==null || host.toLowerCase().equals("localhost")){ + LOGGER.info("resolving hostname and port from container.xml"); + host = context.container().configuration().hostname(); + port = Integer.toString(context.container().configuration().port()); + WPSConfig.getInstance().getWPSConfig().getServer().setHostname(host); + WPSConfig.getInstance().getWPSConfig().getServer().setHostport(port); + } + + + LOGGER.debug("Setting server parameters: Host: {}, Port: {} , Webapp: {} ", host, port,webapp); + //TODO: CHANGE the porotocol to enable https via conainer configuration + String webPath = "http://" + host + ":" + port + "/" + webapp + "/WebProcessingService"; + if (CapabilitiesConfiguration.ENDPOINT_URL.contains("localhost")) + CapabilitiesConfiguration.ENDPOINT_URL=webPath; + + } + + protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { + try { + setServerParameters(); + OutputStream out = res.getOutputStream(); // closed by res.flushBuffer(); + + @SuppressWarnings("unchecked") + RequestHandler handler = new RequestHandler((Map) req.getParameterMap(), out); + String mimeType = handler.getResponseMimeType(); + res.setContentType(mimeType); + handler.handle(); + + res.setStatus(HttpServletResponse.SC_OK); + } + catch (ExceptionReport e) { + handleException(e, res); + } + catch (RuntimeException e) { + ExceptionReport er = new ExceptionReport("Error handing request: " + e.getMessage(), + ExceptionReport.NO_APPLICABLE_CODE, + e); + handleException(er, res); + } + finally { + if (res != null) { + res.flushBuffer(); + } + // out.flush(); + // out.close(); + } + } + + public final static int MAXIMUM_REQUEST_SIZE = 128 << 20; + public final static String SPECIAL_XML_POST_VARIABLE = "request"; + private static final String XML_CONTENT_TYPE = "text/xml"; + + protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { + setServerParameters(); + BufferedReader reader = null; + LOGGER.debug("Incoming Post Request"); + try { + String contentType = req.getContentType(); + String characterEncoding = req.getCharacterEncoding(); + if (characterEncoding == null || characterEncoding.length() == 0) { + characterEncoding = "UTF-8"; // default character encoding if unspecified + } + LOGGER.debug("Set Encoding to {}",characterEncoding); + int contentLength = req.getContentLength(); + if (contentLength > MAXIMUM_REQUEST_SIZE) { + LOGGER.warn("POST request rejected, request size of " + contentLength + " too large."); + ExceptionReport er = new ExceptionReport("Request body too large, limited to " + MAXIMUM_REQUEST_SIZE + + " bytes", ExceptionReport.NO_APPLICABLE_CODE); + handleException(er, res); + } + + LOGGER.debug("Received POST: Content-Type = {}, Character-Encoding = {} , Content-Length = {} " , contentType, characterEncoding, contentLength); + + int requestSize = 0; + + StringWriter writer = contentLength > 0 ? new StringWriter(contentLength) : new StringWriter(); + reader = req.getReader(); + char[] buffer = new char[8192]; + int read; + while ( (read = reader.read(buffer)) != -1 && requestSize < MAXIMUM_REQUEST_SIZE) { + writer.write(buffer, 0, read); + requestSize += read; + } + + LOGGER.debug("POST request contained {} characters", requestSize); + + // Protect against denial of service attacks. + if (requestSize >= MAXIMUM_REQUEST_SIZE && reader.read() > -1) { + LOGGER.warn("POST request rejected, request size of {} too large.",requestSize); + ExceptionReport er = new ExceptionReport("Request body too large, limited to " + MAXIMUM_REQUEST_SIZE + + " bytes", ExceptionReport.NO_APPLICABLE_CODE); + handleException(er, res); + } + + String documentString = writer.toString(); + // Perform URL decoding, if necessary + // if ("application/x-www-form-urlencoded".equals(contentType)) { + if ( (contentType).startsWith("application/x-www-form-urlencoded")) { + if (documentString.startsWith(SPECIAL_XML_POST_VARIABLE + "=")) { + // This is a hack to permit xml to be easily submitted via a form POST. + // By convention, we are allowing users to post xml if they name it + // with a POST parameter "request" although this is not + // valid per the specification. + documentString = documentString.substring(SPECIAL_XML_POST_VARIABLE.length() + 1); + LOGGER.debug("POST request form variable removed"); + } + documentString = URLDecoder.decode(documentString, characterEncoding); + LOGGER.debug("Decoded of POST:\n" + documentString + "\n"); + } + else + LOGGER.info("This is a standard xml document"); + + RequestHandler handler = new RequestHandler(new ByteArrayInputStream(documentString.getBytes("UTF-8")), + res.getOutputStream()); + LOGGER.debug("POST Request Handler created"); + String mimeType = handler.getResponseMimeType(); + LOGGER.debug("Request mimeType: "+mimeType); + res.setContentType(mimeType); + LOGGER.debug("Handling document"); + + handler.handle(); + + LOGGER.debug("STATUS OK!"); + res.setStatus(HttpServletResponse.SC_OK); + } + catch (ExceptionReport e) { + handleException(e, res); + } + catch (Exception e) { + ExceptionReport er = new ExceptionReport("Error handing request: " + e.getMessage(), ExceptionReport.NO_APPLICABLE_CODE, e); + handleException(er, res); + } + finally { + if (res != null) { + res.flushBuffer(); + } + + if (reader != null) { + reader.close(); + } + LOGGER.trace("Flushing request"); + } + } + + @Override + protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { + if (SERVLET_PATH == null) { + req.getContextPath(); + } + super.service(req, res); + } + + private static void handleException(ExceptionReport exception, HttpServletResponse res) { + res.setContentType(XML_CONTENT_TYPE); + try { + LOGGER.debug(exception.toString()); + // DO NOT MIX getWriter and getOuputStream! + exception.getExceptionDocument().save(res.getOutputStream(), + XMLBeansHelper.getXmlOptions()); + + res.setStatus(exception.getHTTPStatusCode()); + } + catch (IOException e) { + LOGGER.warn("exception occured while writing ExceptionReport to stream"); + try { + res.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, + "error occured, while writing OWS Exception output"); + } + catch (IOException ex) { + LOGGER.error("error while writing error code to client!"); + res.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } + } + } + + @Override + public void destroy() { + super.destroy(); + DatabaseFactory.getDatabase().shutdown(); + } +} \ No newline at end of file diff --git a/src/main/java/org/gcube/data/analysis/wps/repository/AlgorithmUpdater.java b/src/main/java/org/gcube/data/analysis/wps/repository/AlgorithmUpdater.java new file mode 100644 index 0000000..62895da --- /dev/null +++ b/src/main/java/org/gcube/data/analysis/wps/repository/AlgorithmUpdater.java @@ -0,0 +1,129 @@ +package org.gcube.data.analysis.wps.repository; + +import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE; +import static java.nio.file.StandardWatchEventKinds.OVERFLOW; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.WatchEvent; +import java.nio.file.WatchKey; +import java.nio.file.WatchService; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class AlgorithmUpdater { + + private static final Logger log = LoggerFactory.getLogger(AlgorithmUpdater.class); + + private String algorithmDirectory; + + private boolean mustUpdate = false; + + private WatcherThread watcherThread = null; + + public AlgorithmUpdater(String algorithmDirectory) { + super(); + this.algorithmDirectory = algorithmDirectory; + } + + protected synchronized boolean mustUpdate(){ + return mustUpdate; + } + + protected synchronized void reset(){ + mustUpdate = false; + } + + public boolean isStarted(){ + return watcherThread!=null; + } + + protected void startWhatcher(){ + watcherThread = new WatcherThread(Thread.currentThread().getContextClassLoader(), algorithmDirectory); + watcherThread.start(); + } + + private class WatcherThread extends Thread { + + private WatchService watcher; + private ClassLoader loader; + private Path dir; + + public WatcherThread(ClassLoader loader, String algorithmDirectory) { + super(); + try { + watcher = FileSystems.getDefault().newWatchService(); + this.loader = loader; + //TODO: change with something from configuration + dir = Paths.get(algorithmDirectory); + dir.register(watcher, ENTRY_CREATE); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @SuppressWarnings("unchecked") + public void run(){ + for (;;) { + + // wait for key to be signaled + WatchKey key; + try { + key = watcher.take(); + } catch (InterruptedException x) { + return; + } + + for (WatchEvent event: key.pollEvents()) { + WatchEvent.Kind kind = event.kind(); + + // This key is registered only + // for ENTRY_CREATE events, + // but an OVERFLOW event can + // occur regardless if events + // are lost or discarded. + if (kind == OVERFLOW) { + continue; + } + + // The filename is the + // context of the event. + WatchEvent ev = (WatchEvent)event; + Path filename = ev.context(); + if (filename.toString().endsWith(".jar")){ + try{ + final Class sysclass = URLClassLoader.class; + // TODO some kind of a hack. Need to invent better solution. + final Method method = sysclass.getDeclaredMethod("addURL", new Class[] { URL.class }); + method.setAccessible(true); + method.invoke(loader, new URL[] { dir.resolve(filename).toFile().toURI().toURL() }); + log.info("filename added is {} in loader {}",filename, loader.getClass().getName()); + mustUpdate = true; + }catch(Exception e){ + log.error("filename {} cannot be added to classpath",e,filename); + } + } else log.info("filename {} is not a jar",filename); + + } + + boolean valid = key.reset(); + if (!valid) { + break; + } + } + } + } + + protected void shutdown(){ + if (isStarted()){ + //TODO : kill the watcherThread + watcherThread = null; + } + } +} diff --git a/src/main/java/org/gcube/data/analysis/wps/repository/GcubeAlgorithmRepository.java b/src/main/java/org/gcube/data/analysis/wps/repository/GcubeAlgorithmRepository.java new file mode 100644 index 0000000..ff7fd8a --- /dev/null +++ b/src/main/java/org/gcube/data/analysis/wps/repository/GcubeAlgorithmRepository.java @@ -0,0 +1,120 @@ +package org.gcube.data.analysis.wps.repository; + +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Set; + +import net.opengis.wps.x100.ProcessDescriptionType; + +import org.n52.wps.algorithm.annotation.Algorithm; +import org.n52.wps.server.IAlgorithm; +import org.n52.wps.server.IAlgorithmRepository; +import org.reflections.Reflections; +import org.reflections.util.ConfigurationBuilder; +import org.reflections.util.FilterBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class GcubeAlgorithmRepository implements IAlgorithmRepository { + + private static Logger log = LoggerFactory.getLogger(GcubeAlgorithmRepository.class); + + private static AlgorithmUpdater updater = null; + + private static Reflections reflection; + + private static final String PACKAGE_TO_FIND = "org.gcube.dataanalysis.wps.statisticalmanager.synchserver.mappedclasses"; + + public GcubeAlgorithmRepository(){ + log.info("gcube algorithm repository started"); + if (updater==null) throw new RuntimeException("GcubeAlgorithmRepository cannot be initialized: updater is null"); + updateRepository(); + updater.startWhatcher(); + } + + public ProcessDescriptionType getProcessDescription(String identifier){ + updateRepository(); + log.info("getProcessDescription with identifier {} ",identifier); + try{ + Set> classes = reflection.getTypesAnnotatedWith(Algorithm.class); + for (Class _class: classes){ + if (_class.getAnnotation(Algorithm.class).identifier().equals(identifier)){ + return ((IAlgorithm)_class.newInstance()).getDescription(); + } + } + }catch(Exception e){} + throw new RuntimeException(String.format("Algorithm with process id %s not found", identifier)); + } + + public boolean containsAlgorithm(String identifier) { + updateRepository(); + log.info("containsAlgorithm with identifier {} ",identifier); + Set> classes = reflection.getTypesAnnotatedWith(Algorithm.class); + for (Class _class: classes){ + if (_class.getAnnotation(Algorithm.class).identifier().equals(identifier)){ + return true; + } + } + return false; + } + + public IAlgorithm getAlgorithm(String identifier){ + updateRepository(); + log.info("getAlgorithm with identifier {} ",identifier); + try{ + Set> classes = reflection.getTypesAnnotatedWith(Algorithm.class); + for (Class _class: classes){ + if (_class.getAnnotation(Algorithm.class).identifier().equals(identifier)){ + if (IAlgorithm.class.isAssignableFrom(_class)){ + return (IAlgorithm)_class.newInstance(); + } else { + log.warn("found algorothm class {} is no assignable from {}",_class.getName(), IAlgorithm.class.getName()); + break; + } + } + } + }catch(Exception e){} + throw new RuntimeException(String.format("Algorithm with id %s not found", identifier)); + } + + public static Set> getAllAlgorithms() { + updateRepository(); + return reflection.getTypesAnnotatedWith(Algorithm.class); + } + + private static synchronized void updateRepository(){ + if (reflection==null || updater.mustUpdate()){ + updater.reset(); + log.info("update time passed, updating repository"); + ConfigurationBuilder confBuilder = new ConfigurationBuilder() + .filterInputsBy(new FilterBuilder().include(FilterBuilder.prefix(PACKAGE_TO_FIND))) + .setUrls(((URLClassLoader)Thread.currentThread().getContextClassLoader()).getURLs()); + reflection = new Reflections(confBuilder); + } + } + + @Override + public Collection getAlgorithmNames() { + updateRepository(); + Collection toReturn = new ArrayList(); + Set> classes = reflection.getTypesAnnotatedWith(Algorithm.class); + for (Class _class: classes){ + toReturn.add(_class.getAnnotation(Algorithm.class).title()); + } + return toReturn; + } + + @Override + public void shutdown() { + reflection = null; + } + + public static boolean setUpdater(AlgorithmUpdater au){ + if (updater==null){ + updater = au; + return true; + } else return false; + } + +} diff --git a/src/main/webapp/WEB-INF/README b/src/main/webapp/WEB-INF/README index ad45008..19ce783 100644 --- a/src/main/webapp/WEB-INF/README +++ b/src/main/webapp/WEB-INF/README @@ -25,7 +25,7 @@ no. 654119), SoBigData (grant no. 654024); Version -------------------------------------------------- -1.0.0-SNAPSHOT (2017-06-09) +1.0.0-SNAPSHOT (2017-06-15) Please see the file named "changelog.xml" in this directory for the release notes. diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml index 7e23ce4..efa36ab 100644 --- a/src/main/webapp/WEB-INF/web.xml +++ b/src/main/webapp/WEB-INF/web.xml @@ -5,6 +5,11 @@ 52°North Web Processing Service, Git: 1665e1b7b2188755161d4f0f3a6acf562d0444e1 @ 2015-03-21 00:30:20 A web processing framework supporting the OGC WPS 1.0.0 specification + + algorithmDirectory + /home/gcube/wps_algorithms/algorithms + + 0 diff --git a/src/main/webapp/codemirror/LICENSE b/src/main/webapp/codemirror/LICENSE deleted file mode 100644 index 44ceed6..0000000 --- a/src/main/webapp/codemirror/LICENSE +++ /dev/null @@ -1,23 +0,0 @@ - Copyright (c) 2007-2009 Marijn Haverbeke - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - - Marijn Haverbeke - marijnh at gmail diff --git a/src/main/webapp/codemirror/codemirror.js b/src/main/webapp/codemirror/codemirror.js deleted file mode 100644 index c17c4ae..0000000 --- a/src/main/webapp/codemirror/codemirror.js +++ /dev/null @@ -1,402 +0,0 @@ -/* CodeMirror main module - * - * Implements the CodeMirror constructor and prototype, which take care - * of initializing the editor frame, and providing the outside interface. - */ - -// The CodeMirrorConfig object is used to specify a default -// configuration. If you specify such an object before loading this -// file, the values you put into it will override the defaults given -// below. You can also assign to it after loading. -var CodeMirrorConfig = window.CodeMirrorConfig || {}; - -var CodeMirror = (function(){ - function setDefaults(object, defaults) { - for (var option in defaults) { - if (!object.hasOwnProperty(option)) - object[option] = defaults[option]; - } - } - function forEach(array, action) { - for (var i = 0; i < array.length; i++) - action(array[i]); - } - - // These default options can be overridden by passing a set of - // options to a specific CodeMirror constructor. See manual.html for - // their meaning. - setDefaults(CodeMirrorConfig, { - stylesheet: "", - path: "", - parserfile: [], - basefiles: ["util.js", "stringstream.js", "select.js", "undo.js", "editor.js", "tokenize.js"], - iframeClass: null, - passDelay: 200, - passTime: 50, - lineNumberDelay: 200, - lineNumberTime: 50, - continuousScanning: false, - saveFunction: null, - onChange: null, - undoDepth: 50, - undoDelay: 800, - disableSpellcheck: true, - textWrapping: true, - readOnly: false, - width: "", - height: "300px", - autoMatchParens: false, - parserConfig: null, - tabMode: "indent", // or "spaces", "default", "shift" - reindentOnLoad: false, - activeTokens: null, - cursorActivity: null, - lineNumbers: false, - indentUnit: 2 - }); - - function addLineNumberDiv(container) { - var nums = document.createElement("DIV"), - scroller = document.createElement("DIV"); - nums.style.position = "absolute"; - nums.style.height = "100%"; - if (nums.style.setExpression) { - try {nums.style.setExpression("height", "this.previousSibling.offsetHeight + 'px'");} - catch(e) {} // Seems to throw 'Not Implemented' on some IE8 versions - } - nums.style.top = "0px"; - nums.style.overflow = "hidden"; - container.appendChild(nums); - scroller.className = "CodeMirror-line-numbers"; - nums.appendChild(scroller); - return nums; - } - - function CodeMirror(place, options) { - // Backward compatibility for deprecated options. - if (options.dumbTabs) options.tabMode = "spaces"; - else if (options.normalTab) options.tabMode = "default"; - - // Use passed options, if any, to override defaults. - this.options = options = options || {}; - setDefaults(options, CodeMirrorConfig); - - var frame = this.frame = document.createElement("IFRAME"); - if (options.iframeClass) frame.className = options.iframeClass; - frame.frameBorder = 0; - frame.src = "javascript:false;"; - frame.style.border = "0"; - frame.style.width = '100%'; - frame.style.height = '100%'; - // display: block occasionally suppresses some Firefox bugs, so we - // always add it, redundant as it sounds. - frame.style.display = "block"; - - var div = this.wrapping = document.createElement("DIV"); - div.style.position = "relative"; - div.className = "CodeMirror-wrapping"; - div.style.width = options.width; - div.style.height = options.height; - - if (place.appendChild) place.appendChild(div); - else place(div); - div.appendChild(frame); - if (options.lineNumbers) this.lineNumbers = addLineNumberDiv(div); - - // Link back to this object, so that the editor can fetch options - // and add a reference to itself. - frame.CodeMirror = this; - this.win = frame.contentWindow; - - if (typeof options.parserfile == "string") - options.parserfile = [options.parserfile]; - if (typeof options.stylesheet == "string") - options.stylesheet = [options.stylesheet]; - - var html = [""]; - // Hack to work around a bunch of IE8-specific problems. - html.push(""); - forEach(options.stylesheet, function(file) { - html.push(""); - }); - forEach(options.basefiles.concat(options.parserfile), function(file) { - html.push(" - - - - - - - - -
- 52northlogo_small -

WPS Web Admin Console

-
-
-
-
- -
-
- - - - - - - - - - - - -
-
-
-
Server Settings
- -
-
-
-

- - -
-

-

- - -
-

-

- - -
-

-

- - -

-

- - -

-

- - -

-

- - -
-

-

-

- -
-

-

-

- -
-

-

-

- -
-

-

-

- -
-

-

-

- -
-

-

-
-
-
-
-
Algorithm Repositories
-
- -
-

- -

-
-
-
-
Parsers
-
-
-

- -

-
-
-
-
Generators
-
-
-

- -

-
-
-
-
Remote Repositories
-
-
-

- -

-
-
-
-
-
-
- - - -
-
- -
- -

- Please enter the fuly qualified name of the java class implementing IAlgorithm:
- -

-

- Please specify the .java file for the process:
- -

-

- Please specify the associated ProcessDescription .xml file - (optional):
- -

-

- - -

-
-
- -
- -
- -

- Please enter the process name:
- (only if process name should be unlike filename)

- -

-

- Please enter the location of an annotated R script
-
- -

- - - - -

- - -
-
- Process id will be org.n52.wps.server.r.[filename] - or org.n52.wps.server.r.[process name] -

-
-
- - -
- - \ No newline at end of file diff --git a/src/main/webapp/webAdmin/resources/jquery-ui.js b/src/main/webapp/webAdmin/resources/jquery-ui.js deleted file mode 100755 index fa98459..0000000 --- a/src/main/webapp/webAdmin/resources/jquery-ui.js +++ /dev/null @@ -1,5923 +0,0 @@ -/* - * jQuery UI 1.6rc5 - * - * Copyright (c) 2009 AUTHORS.txt (http://ui.jquery.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI - */ -;(function($) { - -var _remove = $.fn.remove, - isFF2 = $.browser.mozilla && (parseFloat($.browser.version) < 1.9); - -//Helper functions and ui object -$.ui = { - version: "1.6rc5", - - // $.ui.plugin is deprecated. Use the proxy pattern instead. - plugin: { - add: function(module, option, set) { - var proto = $.ui[module].prototype; - for(var i in set) { - proto.plugins[i] = proto.plugins[i] || []; - proto.plugins[i].push([option, set[i]]); - } - }, - call: function(instance, name, args) { - var set = instance.plugins[name]; - if(!set) { return; } - - for (var i = 0; i < set.length; i++) { - if (instance.options[set[i][0]]) { - set[i][1].apply(instance.element, args); - } - } - } - }, - - contains: function(a, b) { - return document.compareDocumentPosition - ? a.compareDocumentPosition(b) & 16 - : a !== b && a.contains(b); - }, - - cssCache: {}, - css: function(name) { - if ($.ui.cssCache[name]) { return $.ui.cssCache[name]; } - var tmp = $('
').addClass(name).css({position:'absolute', top:'-5000px', left:'-5000px', display:'block'}).appendTo('body'); - - //if (!$.browser.safari) - //tmp.appendTo('body'); - - //Opera and Safari set width and height to 0px instead of auto - //Safari returns rgba(0,0,0,0) when bgcolor is not set - $.ui.cssCache[name] = !!( - (!(/auto|default/).test(tmp.css('cursor')) || (/^[1-9]/).test(tmp.css('height')) || (/^[1-9]/).test(tmp.css('width')) || - !(/none/).test(tmp.css('backgroundImage')) || !(/transparent|rgba\(0, 0, 0, 0\)/).test(tmp.css('backgroundColor'))) - ); - try { $('body').get(0).removeChild(tmp.get(0)); } catch(e){} - return $.ui.cssCache[name]; - }, - - hasScroll: function(el, a) { - - //If overflow is hidden, the element might have extra content, but the user wants to hide it - if ($(el).css('overflow') == 'hidden') { return false; } - - var scroll = (a && a == 'left') ? 'scrollLeft' : 'scrollTop', - has = false; - - if (el[scroll] > 0) { return true; } - - // TODO: determine which cases actually cause this to happen - // if the element doesn't have the scroll set, see if it's possible to - // set the scroll - el[scroll] = 1; - has = (el[scroll] > 0); - el[scroll] = 0; - return has; - }, - - isOverAxis: function(x, reference, size) { - //Determines when x coordinate is over "b" element axis - return (x > reference) && (x < (reference + size)); - }, - - isOver: function(y, x, top, left, height, width) { - //Determines when x, y coordinates is over "b" element - return $.ui.isOverAxis(y, top, height) && $.ui.isOverAxis(x, left, width); - }, - - keyCode: { - BACKSPACE: 8, - CAPS_LOCK: 20, - COMMA: 188, - CONTROL: 17, - DELETE: 46, - DOWN: 40, - END: 35, - ENTER: 13, - ESCAPE: 27, - HOME: 36, - INSERT: 45, - LEFT: 37, - NUMPAD_ADD: 107, - NUMPAD_DECIMAL: 110, - NUMPAD_DIVIDE: 111, - NUMPAD_ENTER: 108, - NUMPAD_MULTIPLY: 106, - NUMPAD_SUBTRACT: 109, - PAGE_DOWN: 34, - PAGE_UP: 33, - PERIOD: 190, - RIGHT: 39, - SHIFT: 16, - SPACE: 32, - TAB: 9, - UP: 38 - } -}; - -// WAI-ARIA normalization -if (isFF2) { - var attr = $.attr, - removeAttr = $.fn.removeAttr, - ariaNS = "http://www.w3.org/2005/07/aaa", - ariaState = /^aria-/, - ariaRole = /^wairole:/; - - $.attr = function(elem, name, value) { - var set = value !== undefined; - - return (name == 'role' - ? (set - ? attr.call(this, elem, name, "wairole:" + value) - : (attr.apply(this, arguments) || "").replace(ariaRole, "")) - : (ariaState.test(name) - ? (set - ? elem.setAttributeNS(ariaNS, - name.replace(ariaState, "aaa:"), value) - : attr.call(this, elem, name.replace(ariaState, "aaa:"))) - : attr.apply(this, arguments))); - }; - - $.fn.removeAttr = function(name) { - return (ariaState.test(name) - ? this.each(function() { - this.removeAttributeNS(ariaNS, name.replace(ariaState, "")); - }) : removeAttr.call(this, name)); - }; -} - -//jQuery plugins -$.fn.extend({ - remove: function() { - // Safari has a native remove event which actually removes DOM elements, - // so we have to use triggerHandler instead of trigger (#3037). - $("*", this).add(this).each(function() { - $(this).triggerHandler("remove"); - }); - return _remove.apply(this, arguments ); - }, - - enableSelection: function() { - return this - .attr('unselectable', 'off') - .css('MozUserSelect', '') - .unbind('selectstart.ui'); - }, - - disableSelection: function() { - return this - .attr('unselectable', 'on') - .css('MozUserSelect', 'none') - .bind('selectstart.ui', function() { return false; }); - }, - - scrollParent: function() { - var scrollParent; - if(($.browser.msie && (/(static|relative)/).test(this.css('position'))) || (/absolute/).test(this.css('position'))) { - scrollParent = this.parents().filter(function() { - return (/(relative|absolute|fixed)/).test($.curCSS(this,'position',1)) && (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1)); - }).eq(0); - } else { - scrollParent = this.parents().filter(function() { - return (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1)); - }).eq(0); - } - - return (/fixed/).test(this.css('position')) || !scrollParent.length ? $(document) : scrollParent; - } -}); - - -//Additional selectors -$.extend($.expr[':'], { - data: function(elem, i, match) { - return !!$.data(elem, match[3]); - }, - - // TODO: add support for object, area - tabbable: function(elem) { - var nodeName = elem.nodeName.toLowerCase(); - function isVisible(element) { - return !($(element).is(':hidden') || $(element).parents(':hidden').length); - } - - return ( - // in tab order - elem.tabIndex >= 0 && - - ( // filter node types that participate in the tab order - - // anchor tag - ('a' == nodeName && elem.href) || - - // enabled form element - (/input|select|textarea|button/.test(nodeName) && - 'hidden' != elem.type && !elem.disabled) - ) && - - // visible on page - isVisible(elem) - ); - } -}); - - -// $.widget is a factory to create jQuery plugins -// taking some boilerplate code out of the plugin code -function getter(namespace, plugin, method, args) { - function getMethods(type) { - var methods = $[namespace][plugin][type] || []; - return (typeof methods == 'string' ? methods.split(/,?\s+/) : methods); - } - - var methods = getMethods('getter'); - if (args.length == 1 && typeof args[0] == 'string') { - methods = methods.concat(getMethods('getterSetter')); - } - return ($.inArray(method, methods) != -1); -} - -$.widget = function(name, prototype) { - var namespace = name.split(".")[0]; - name = name.split(".")[1]; - - // create plugin method - $.fn[name] = function(options) { - var isMethodCall = (typeof options == 'string'), - args = Array.prototype.slice.call(arguments, 1); - - // prevent calls to internal methods - if (isMethodCall && options.substring(0, 1) == '_') { - return this; - } - - // handle getter methods - if (isMethodCall && getter(namespace, name, options, args)) { - var instance = $.data(this[0], name); - return (instance ? instance[options].apply(instance, args) - : undefined); - } - - // handle initialization and non-getter methods - return this.each(function() { - var instance = $.data(this, name); - - // constructor - (!instance && !isMethodCall && - $.data(this, name, new $[namespace][name](this, options))); - - // method call - (instance && isMethodCall && $.isFunction(instance[options]) && - instance[options].apply(instance, args)); - }); - }; - - // create widget constructor - $[namespace] = $[namespace] || {}; - $[namespace][name] = function(element, options) { - var self = this; - - this.namespace = namespace; - this.widgetName = name; - this.widgetEventPrefix = $[namespace][name].eventPrefix || name; - this.widgetBaseClass = namespace + '-' + name; - - this.options = $.extend({}, - $.widget.defaults, - $[namespace][name].defaults, - $.metadata && $.metadata.get(element)[name], - options); - - this.element = $(element) - .bind('setData.' + name, function(event, key, value) { - if (event.target == element) { - return self._setData(key, value); - } - }) - .bind('getData.' + name, function(event, key) { - if (event.target == element) { - return self._getData(key); - } - }) - .bind('remove', function() { - return self.destroy(); - }); - - this._init(); - }; - - // add widget prototype - $[namespace][name].prototype = $.extend({}, $.widget.prototype, prototype); - - // TODO: merge getter and getterSetter properties from widget prototype - // and plugin prototype - $[namespace][name].getterSetter = 'option'; -}; - -$.widget.prototype = { - _init: function() {}, - destroy: function() { - this.element.removeData(this.widgetName) - .removeClass(this.widgetBaseClass + '-disabled' + ' ' + this.namespace + '-state-disabled') - .removeAttr('aria-disabled'); - }, - - option: function(key, value) { - var options = key, - self = this; - - if (typeof key == "string") { - if (value === undefined) { - return this._getData(key); - } - options = {}; - options[key] = value; - } - - $.each(options, function(key, value) { - self._setData(key, value); - }); - }, - _getData: function(key) { - return this.options[key]; - }, - _setData: function(key, value) { - this.options[key] = value; - - if (key == 'disabled') { - this.element - [value ? 'addClass' : 'removeClass']( - this.widgetBaseClass + '-disabled' + ' ' + - this.namespace + '-state-disabled') - .attr("aria-disabled", value); - } - }, - - enable: function() { - this._setData('disabled', false); - }, - disable: function() { - this._setData('disabled', true); - }, - - _trigger: function(type, event, data) { - var callback = this.options[type], - eventName = (type == this.widgetEventPrefix - ? type : this.widgetEventPrefix + type); - - event = $.Event(event); - event.type = eventName; - - this.element.trigger(event, data); - - return !($.isFunction(callback) && callback.call(this.element[0], event, data) === false - || event.isDefaultPrevented()); - } -}; - -$.widget.defaults = { - disabled: false -}; - - -/** Mouse Interaction Plugin **/ - -$.ui.mouse = { - _mouseInit: function() { - var self = this; - - this.element - .bind('mousedown.'+this.widgetName, function(event) { - return self._mouseDown(event); - }) - .bind('click.'+this.widgetName, function(event) { - if(self._preventClickEvent) { - self._preventClickEvent = false; - return false; - } - }); - - // Prevent text selection in IE - if ($.browser.msie) { - this._mouseUnselectable = this.element.attr('unselectable'); - this.element.attr('unselectable', 'on'); - } - - this.started = false; - }, - - // TODO: make sure destroying one instance of mouse doesn't mess with - // other instances of mouse - _mouseDestroy: function() { - this.element.unbind('.'+this.widgetName); - - // Restore text selection in IE - ($.browser.msie - && this.element.attr('unselectable', this._mouseUnselectable)); - }, - - _mouseDown: function(event) { - // we may have missed mouseup (out of window) - (this._mouseStarted && this._mouseUp(event)); - - this._mouseDownEvent = event; - - var self = this, - btnIsLeft = (event.which == 1), - elIsCancel = (typeof this.options.cancel == "string" ? $(event.target).parents().add(event.target).filter(this.options.cancel).length : false); - if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) { - return true; - } - - this.mouseDelayMet = !this.options.delay; - if (!this.mouseDelayMet) { - this._mouseDelayTimer = setTimeout(function() { - self.mouseDelayMet = true; - }, this.options.delay); - } - - if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { - this._mouseStarted = (this._mouseStart(event) !== false); - if (!this._mouseStarted) { - event.preventDefault(); - return true; - } - } - - // these delegates are required to keep context - this._mouseMoveDelegate = function(event) { - return self._mouseMove(event); - }; - this._mouseUpDelegate = function(event) { - return self._mouseUp(event); - }; - $(document) - .bind('mousemove.'+this.widgetName, this._mouseMoveDelegate) - .bind('mouseup.'+this.widgetName, this._mouseUpDelegate); - - // preventDefault() is used to prevent the selection of text here - - // however, in Safari, this causes select boxes not to be selectable - // anymore, so this fix is needed - ($.browser.safari || event.preventDefault()); - - return true; - }, - - _mouseMove: function(event) { - // IE mouseup check - mouseup happened when mouse was out of window - if ($.browser.msie && !event.button) { - return this._mouseUp(event); - } - - if (this._mouseStarted) { - this._mouseDrag(event); - return event.preventDefault(); - } - - if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { - this._mouseStarted = - (this._mouseStart(this._mouseDownEvent, event) !== false); - (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event)); - } - - return !this._mouseStarted; - }, - - _mouseUp: function(event) { - $(document) - .unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate) - .unbind('mouseup.'+this.widgetName, this._mouseUpDelegate); - - if (this._mouseStarted) { - this._mouseStarted = false; - this._preventClickEvent = true; - this._mouseStop(event); - } - - return false; - }, - - _mouseDistanceMet: function(event) { - return (Math.max( - Math.abs(this._mouseDownEvent.pageX - event.pageX), - Math.abs(this._mouseDownEvent.pageY - event.pageY) - ) >= this.options.distance - ); - }, - - _mouseDelayMet: function(event) { - return this.mouseDelayMet; - }, - - // These are placeholder methods, to be overriden by extending plugin - _mouseStart: function(event) {}, - _mouseDrag: function(event) {}, - _mouseStop: function(event) {}, - _mouseCapture: function(event) { return true; } -}; - -$.ui.mouse.defaults = { - cancel: null, - distance: 1, - delay: 0 -}; - -})(jQuery); -/* - * jQuery UI Draggable 1.6rc5 - * - * Copyright (c) 2009 AUTHORS.txt (http://ui.jquery.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Draggables - * - * Depends: - * ui.core.js - */ -(function($) { - -$.widget("ui.draggable", $.extend({}, $.ui.mouse, { - - _init: function() { - - if (this.options.helper == 'original' && !(/^(?:r|a|f)/).test(this.element.css("position"))) - this.element[0].style.position = 'relative'; - - (this.options.cssNamespace && this.element.addClass(this.options.cssNamespace+"-draggable")); - (this.options.disabled && this.element.addClass(this.options.cssNamespace+'-draggable-disabled')); - - this._mouseInit(); - - }, - - destroy: function() { - if(!this.element.data('draggable')) return; - this.element.removeData("draggable").unbind(".draggable").removeClass(this.options.cssNamespace+'-draggable '+this.options.cssNamespace+'-draggable-dragging '+this.options.cssNamespace+'-draggable-disabled'); - this._mouseDestroy(); - }, - - _mouseCapture: function(event) { - - var o = this.options; - - if (this.helper || o.disabled || $(event.target).is('.'+this.options.cssNamespace+'-resizable-handle')) - return false; - - //Quit if we're not on a valid handle - this.handle = this._getHandle(event); - if (!this.handle) - return false; - - return true; - - }, - - _mouseStart: function(event) { - - var o = this.options; - - //Create and append the visible helper - this.helper = this._createHelper(event); - - //Cache the helper size - this._cacheHelperProportions(); - - //If ddmanager is used for droppables, set the global draggable - if($.ui.ddmanager) - $.ui.ddmanager.current = this; - - /* - * - Position generation - - * This block generates everything position related - it's the core of draggables. - */ - - //Cache the margins of the original element - this._cacheMargins(); - - //Store the helper's css position - this.cssPosition = this.helper.css("position"); - this.scrollParent = this.helper.scrollParent(); - - //The element's absolute position on the page minus margins - this.offset = this.element.offset(); - this.offset = { - top: this.offset.top - this.margins.top, - left: this.offset.left - this.margins.left - }; - - $.extend(this.offset, { - click: { //Where the click happened, relative to the element - left: event.pageX - this.offset.left, - top: event.pageY - this.offset.top - }, - parent: this._getParentOffset(), - relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper - }); - - //Generate the original position - this.originalPosition = this._generatePosition(event); - this.originalPageX = event.pageX; - this.originalPageY = event.pageY; - - //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied - if(o.cursorAt) - this._adjustOffsetFromHelper(o.cursorAt); - - //Set a containment if given in the options - if(o.containment) - this._setContainment(); - - //Call plugins and callbacks - this._trigger("start", event); - - //Recache the helper size - this._cacheHelperProportions(); - - //Prepare the droppable offsets - if ($.ui.ddmanager && !o.dropBehaviour) - $.ui.ddmanager.prepareOffsets(this, event); - - this.helper.addClass(o.cssNamespace+"-draggable-dragging"); - this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position - return true; - }, - - _mouseDrag: function(event, noPropagation) { - - //Compute the helpers position - this.position = this._generatePosition(event); - this.positionAbs = this._convertPositionTo("absolute"); - - //Call plugins and callbacks and use the resulting position if something is returned - if (!noPropagation) { - var ui = this._uiHash(); - this._trigger('drag', event, ui); - this.position = ui.position; - } - - if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px'; - if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px'; - if($.ui.ddmanager) $.ui.ddmanager.drag(this, event); - - return false; - }, - - _mouseStop: function(event) { - - //If we are using droppables, inform the manager about the drop - var dropped = false; - if ($.ui.ddmanager && !this.options.dropBehaviour) - dropped = $.ui.ddmanager.drop(this, event); - - //if a drop comes from outside (a sortable) - if(this.dropped) { - dropped = this.dropped; - this.dropped = false; - } - - if((this.options.revert == "invalid" && !dropped) || (this.options.revert == "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) { - var self = this; - $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() { - self._trigger("stop", event); - self._clear(); - }); - } else { - this._trigger("stop", event); - this._clear(); - } - - return false; - }, - - _getHandle: function(event) { - - var handle = !this.options.handle || !$(this.options.handle, this.element).length ? true : false; - $(this.options.handle, this.element) - .find("*") - .andSelf() - .each(function() { - if(this == event.target) handle = true; - }); - - return handle; - - }, - - _createHelper: function(event) { - - var o = this.options; - var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper == 'clone' ? this.element.clone() : this.element); - - if(!helper.parents('body').length) - helper.appendTo((o.appendTo == 'parent' ? this.element[0].parentNode : o.appendTo)); - - if(helper[0] != this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) - helper.css("position", "absolute"); - - return helper; - - }, - - _adjustOffsetFromHelper: function(obj) { - if(obj.left != undefined) this.offset.click.left = obj.left + this.margins.left; - if(obj.right != undefined) this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; - if(obj.top != undefined) this.offset.click.top = obj.top + this.margins.top; - if(obj.bottom != undefined) this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; - }, - - _getParentOffset: function() { - - //Get the offsetParent and cache its position - this.offsetParent = this.helper.offsetParent(); - var po = this.offsetParent.offset(); - - // This is a special case where we need to modify a offset calculated on start, since the following happened: - // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent - // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that - // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag - if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) { - po.left += this.scrollParent.scrollLeft(); - po.top += this.scrollParent.scrollTop(); - } - - if((this.offsetParent[0] == document.body && $.browser.mozilla) //Ugly FF3 fix - || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.browser.msie)) //Ugly IE fix - po = { top: 0, left: 0 }; - - return { - top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), - left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) - }; - - }, - - _getRelativeOffset: function() { - - if(this.cssPosition == "relative") { - var p = this.element.position(); - return { - top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), - left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() - }; - } else { - return { top: 0, left: 0 }; - } - - }, - - _cacheMargins: function() { - this.margins = { - left: (parseInt(this.element.css("marginLeft"),10) || 0), - top: (parseInt(this.element.css("marginTop"),10) || 0) - }; - }, - - _cacheHelperProportions: function() { - this.helperProportions = { - width: this.helper.outerWidth(), - height: this.helper.outerHeight() - }; - }, - - _setContainment: function() { - - var o = this.options; - if(o.containment == 'parent') o.containment = this.helper[0].parentNode; - if(o.containment == 'document' || o.containment == 'window') this.containment = [ - 0 - this.offset.relative.left - this.offset.parent.left, - 0 - this.offset.relative.top - this.offset.parent.top, - $(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left, - ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top - ]; - - if(!(/^(document|window|parent)$/).test(o.containment)) { - var ce = $(o.containment)[0]; - var co = $(o.containment).offset(); - var over = ($(ce).css("overflow") != 'hidden'); - - this.containment = [ - co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) - this.margins.left, - co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) - this.margins.top, - co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - this.helperProportions.width - this.margins.left, - co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - this.helperProportions.height - this.margins.top - ]; - } - - }, - - _convertPositionTo: function(d, pos) { - - if(!pos) pos = this.position; - var mod = d == "absolute" ? 1 : -1; - var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); - - return { - top: ( - pos.top // The absolute mouse position - + this.offset.relative.top * mod // Only for relative positioned nodes: Relative offset from element to offset parent - + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border) - - ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod - ), - left: ( - pos.left // The absolute mouse position - + this.offset.relative.left * mod // Only for relative positioned nodes: Relative offset from element to offset parent - + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border) - - ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod - ) - }; - - }, - - _generatePosition: function(event) { - - var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); - - // This is another very weird special case that only happens for relative elements: - // 1. If the css position is relative - // 2. and the scroll parent is the document or similar to the offset parent - // we have to refresh the relative offset during the scroll so there are no jumps - if(this.cssPosition == 'relative' && !(this.scrollParent[0] != document && this.scrollParent[0] != this.offsetParent[0])) { - this.offset.relative = this._getRelativeOffset(); - } - - var pageX = event.pageX; - var pageY = event.pageY; - - /* - * - Position constraining - - * Constrain the position to a mix of grid, containment. - */ - - if(this.originalPosition) { //If we are not dragging yet, we won't check for options - - if(this.containment) { - if(event.pageX - this.offset.click.left < this.containment[0]) pageX = this.containment[0] + this.offset.click.left; - if(event.pageY - this.offset.click.top < this.containment[1]) pageY = this.containment[1] + this.offset.click.top; - if(event.pageX - this.offset.click.left > this.containment[2]) pageX = this.containment[2] + this.offset.click.left; - if(event.pageY - this.offset.click.top > this.containment[3]) pageY = this.containment[3] + this.offset.click.top; - } - - if(o.grid) { - var top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1]; - pageY = this.containment ? (!(top - this.offset.click.top < this.containment[1] || top - this.offset.click.top > this.containment[3]) ? top : (!(top - this.offset.click.top < this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; - - var left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0]; - pageX = this.containment ? (!(left - this.offset.click.left < this.containment[0] || left - this.offset.click.left > this.containment[2]) ? left : (!(left - this.offset.click.left < this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; - } - - } - - return { - top: ( - pageY // The absolute mouse position - - this.offset.click.top // Click offset (relative to the element) - - this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent - - this.offset.parent.top // The offsetParent's offset without borders (offset + border) - + ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) - ), - left: ( - pageX // The absolute mouse position - - this.offset.click.left // Click offset (relative to the element) - - this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent - - this.offset.parent.left // The offsetParent's offset without borders (offset + border) - + ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) - ) - }; - - }, - - _clear: function() { - this.helper.removeClass(this.options.cssNamespace+"-draggable-dragging"); - if(this.helper[0] != this.element[0] && !this.cancelHelperRemoval) this.helper.remove(); - //if($.ui.ddmanager) $.ui.ddmanager.current = null; - this.helper = null; - this.cancelHelperRemoval = false; - }, - - // From now on bulk stuff - mainly helpers - - _trigger: function(type, event, ui) { - ui = ui || this._uiHash(); - $.ui.plugin.call(this, type, [event, ui]); - if(type == "drag") this.positionAbs = this._convertPositionTo("absolute"); //The absolute position has to be recalculated after plugins - return $.widget.prototype._trigger.call(this, type, event, ui); - }, - - plugins: {}, - - _uiHash: function(event) { - return { - helper: this.helper, - position: this.position, - absolutePosition: this.positionAbs, - options: this.options - }; - } - -})); - -$.extend($.ui.draggable, { - version: "1.6rc5", - eventPrefix: "drag", - defaults: { - appendTo: "parent", - axis: false, - cancel: ":input,option", - connectToSortable: false, - containment: false, - cssNamespace: "ui", - cursor: "default", - cursorAt: null, - delay: 0, - distance: 1, - grid: false, - handle: false, - helper: "original", - iframeFix: false, - opacity: null, - refreshPositions: false, - revert: false, - revertDuration: 500, - scope: "default", - scroll: true, - scrollSensitivity: 20, - scrollSpeed: 20, - snap: false, - snapMode: "both", - snapTolerance: 20, - stack: false, - zIndex: null - } -}); - -$.ui.plugin.add("draggable", "connectToSortable", { - start: function(event, ui) { - - var inst = $(this).data("draggable"); - inst.sortables = []; - $(ui.options.connectToSortable).each(function() { - // 'this' points to a string, and should therefore resolved as query, but instead, if the string is assigned to a variable, it loops through the strings properties, - // so we have to append '' to make it anonymous again - $(this+'').each(function() { - if($.data(this, 'sortable')) { - var sortable = $.data(this, 'sortable'); - inst.sortables.push({ - instance: sortable, - shouldRevert: sortable.options.revert - }); - sortable._refreshItems(); //Do a one-time refresh at start to refresh the containerCache - sortable._trigger("activate", event, inst); - } - }); - }); - - }, - stop: function(event, ui) { - - //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper - var inst = $(this).data("draggable"); - - $.each(inst.sortables, function() { - if(this.instance.isOver) { - - this.instance.isOver = 0; - - inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance - this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work) - - //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: 'valid/invalid' - if(this.shouldRevert) this.instance.options.revert = true; - - //Trigger the stop of the sortable - this.instance._mouseStop(event); - - //Also propagate receive event, since the sortable is actually receiving a element - this.instance.element.triggerHandler("sortreceive", [event, $.extend(this.instance._uiHash(), { sender: inst.element })], this.instance.options["receive"]); - - this.instance.options.helper = this.instance.options._helper; - - //If the helper has been the original item, restore properties in the sortable - if(inst.options.helper == 'original') - this.instance.currentItem.css({ top: 'auto', left: 'auto' }); - - } else { - this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance - this.instance._trigger("deactivate", event, inst); - } - - }); - - }, - drag: function(event, ui) { - - var inst = $(this).data("draggable"), self = this; - - var checkPos = function(o) { - var dyClick = this.offset.click.top, dxClick = this.offset.click.left; - var helperTop = this.positionAbs.top, helperLeft = this.positionAbs.left; - var itemHeight = o.height, itemWidth = o.width; - var itemTop = o.top, itemLeft = o.left; - - return $.ui.isOver(helperTop + dyClick, helperLeft + dxClick, itemTop, itemLeft, itemHeight, itemWidth); - }; - - $.each(inst.sortables, function(i) { - - if(checkPos.call(inst, this.instance.containerCache)) { - - //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once - if(!this.instance.isOver) { - this.instance.isOver = 1; - //Now we fake the start of dragging for the sortable instance, - //by cloning the list group item, appending it to the sortable and using it as inst.currentItem - //We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one) - this.instance.currentItem = $(self).clone().appendTo(this.instance.element).data("sortable-item", true); - this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it - this.instance.options.helper = function() { return ui.helper[0]; }; - - event.target = this.instance.currentItem[0]; - this.instance._mouseCapture(event, true); - this.instance._mouseStart(event, true, true); - - //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes - this.instance.offset.click.top = inst.offset.click.top; - this.instance.offset.click.left = inst.offset.click.left; - this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left; - this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top; - - inst._trigger("toSortable", event); - inst.dropped = this.instance.element; //draggable revert needs that - this.instance.fromOutside = true; //Little hack so receive/update callbacks work - - } - - //Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable - if(this.instance.currentItem) this.instance._mouseDrag(event); - - } else { - - //If it doesn't intersect with the sortable, and it intersected before, - //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval - if(this.instance.isOver) { - this.instance.isOver = 0; - this.instance.cancelHelperRemoval = true; - this.instance.options.revert = false; //No revert here - this.instance._mouseStop(event, true); - this.instance.options.helper = this.instance.options._helper; - - //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size - this.instance.currentItem.remove(); - if(this.instance.placeholder) this.instance.placeholder.remove(); - - inst._trigger("fromSortable", event); - inst.dropped = false; //draggable revert needs that - } - - }; - - }); - - } -}); - -$.ui.plugin.add("draggable", "cursor", { - start: function(event, ui) { - var t = $('body'); - if (t.css("cursor")) ui.options._cursor = t.css("cursor"); - t.css("cursor", ui.options.cursor); - }, - stop: function(event, ui) { - if (ui.options._cursor) $('body').css("cursor", ui.options._cursor); - } -}); - -$.ui.plugin.add("draggable", "iframeFix", { - start: function(event, ui) { - $(ui.options.iframeFix === true ? "iframe" : ui.options.iframeFix).each(function() { - $('
') - .css({ - width: this.offsetWidth+"px", height: this.offsetHeight+"px", - position: "absolute", opacity: "0.001", zIndex: 1000 - }) - .css($(this).offset()) - .appendTo("body"); - }); - }, - stop: function(event, ui) { - $("div.ui-draggable-iframeFix").each(function() { this.parentNode.removeChild(this); }); //Remove frame helpers - } -}); - -$.ui.plugin.add("draggable", "opacity", { - start: function(event, ui) { - var t = $(ui.helper); - if(t.css("opacity")) ui.options._opacity = t.css("opacity"); - t.css('opacity', ui.options.opacity); - }, - stop: function(event, ui) { - if(ui.options._opacity) $(ui.helper).css('opacity', ui.options._opacity); - } -}); - -$.ui.plugin.add("draggable", "scroll", { - start: function(event, ui) { - var o = ui.options; - var i = $(this).data("draggable"); - - if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') i.overflowOffset = i.scrollParent.offset(); - - }, - drag: function(event, ui) { - - var o = ui.options, scrolled = false; - var i = $(this).data("draggable"); - - if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') { - - if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) - i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed; - else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity) - i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed; - - if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) - i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed; - else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity) - i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed; - - } else { - - if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) - scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); - else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) - scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); - - if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) - scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); - else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) - scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); - - } - - if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) - $.ui.ddmanager.prepareOffsets(i, event); - - } -}); - -$.ui.plugin.add("draggable", "snap", { - start: function(event, ui) { - - var inst = $(this).data("draggable"); - inst.snapElements = []; - - $(ui.options.snap.constructor != String ? ( ui.options.snap.items || ':data(draggable)' ) : ui.options.snap).each(function() { - var $t = $(this); var $o = $t.offset(); - if(this != inst.element[0]) inst.snapElements.push({ - item: this, - width: $t.outerWidth(), height: $t.outerHeight(), - top: $o.top, left: $o.left - }); - }); - - }, - drag: function(event, ui) { - - var inst = $(this).data("draggable"); - var d = ui.options.snapTolerance; - - var x1 = ui.absolutePosition.left, x2 = x1 + inst.helperProportions.width, - y1 = ui.absolutePosition.top, y2 = y1 + inst.helperProportions.height; - - for (var i = inst.snapElements.length - 1; i >= 0; i--){ - - var l = inst.snapElements[i].left, r = l + inst.snapElements[i].width, - t = inst.snapElements[i].top, b = t + inst.snapElements[i].height; - - //Yes, I know, this is insane ;) - if(!((l-d < x1 && x1 < r+d && t-d < y1 && y1 < b+d) || (l-d < x1 && x1 < r+d && t-d < y2 && y2 < b+d) || (l-d < x2 && x2 < r+d && t-d < y1 && y1 < b+d) || (l-d < x2 && x2 < r+d && t-d < y2 && y2 < b+d))) { - if(inst.snapElements[i].snapping) (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); - inst.snapElements[i].snapping = false; - continue; - } - - if(ui.options.snapMode != 'inner') { - var ts = Math.abs(t - y2) <= d; - var bs = Math.abs(b - y1) <= d; - var ls = Math.abs(l - x2) <= d; - var rs = Math.abs(r - x1) <= d; - if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top; - if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top; - if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left; - if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left; - } - - var first = (ts || bs || ls || rs); - - if(ui.options.snapMode != 'outer') { - var ts = Math.abs(t - y1) <= d; - var bs = Math.abs(b - y2) <= d; - var ls = Math.abs(l - x1) <= d; - var rs = Math.abs(r - x2) <= d; - if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top; - if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top; - if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left; - if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left; - } - - if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) - (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); - inst.snapElements[i].snapping = (ts || bs || ls || rs || first); - - }; - - } -}); - -$.ui.plugin.add("draggable", "stack", { - start: function(event, ui) { - var group = $.makeArray($(ui.options.stack.group)).sort(function(a,b) { - return (parseInt($(a).css("zIndex"),10) || ui.options.stack.min) - (parseInt($(b).css("zIndex"),10) || ui.options.stack.min); - }); - - $(group).each(function(i) { - this.style.zIndex = ui.options.stack.min + i; - }); - - this[0].style.zIndex = ui.options.stack.min + group.length; - } -}); - -$.ui.plugin.add("draggable", "zIndex", { - start: function(event, ui) { - var t = $(ui.helper); - if(t.css("zIndex")) ui.options._zIndex = t.css("zIndex"); - t.css('zIndex', ui.options.zIndex); - }, - stop: function(event, ui) { - if(ui.options._zIndex) $(ui.helper).css('zIndex', ui.options._zIndex); - } -}); - -})(jQuery); -/* - * jQuery UI Droppable 1.6rc5 - * - * Copyright (c) 2009 AUTHORS.txt (http://ui.jquery.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Droppables - * - * Depends: - * ui.core.js - * ui.draggable.js - */ -(function($) { - -$.widget("ui.droppable", { - - _init: function() { - - var o = this.options, accept = o.accept; - this.isover = 0; this.isout = 1; - - this.options.accept = this.options.accept && $.isFunction(this.options.accept) ? this.options.accept : function(d) { - return d.is(accept); - }; - - //Store the droppable's proportions - this.proportions = { width: this.element[0].offsetWidth, height: this.element[0].offsetHeight }; - - // Add the reference and positions to the manager - $.ui.ddmanager.droppables[this.options.scope] = $.ui.ddmanager.droppables[this.options.scope] || []; - $.ui.ddmanager.droppables[this.options.scope].push(this); - - (this.options.cssNamespace && this.element.addClass(this.options.cssNamespace+"-droppable")); - - }, - - destroy: function() { - var drop = $.ui.ddmanager.droppables[this.options.scope]; - for ( var i = 0; i < drop.length; i++ ) - if ( drop[i] == this ) - drop.splice(i, 1); - - this.element - .removeClass(this.options.cssNamespace+"-droppable "+this.options.cssNamespace+"-droppable-disabled") - .removeData("droppable") - .unbind(".droppable"); - }, - - _setData: function(key, value) { - - if(key == 'accept') { - this.options.accept = value && $.isFunction(value) ? value : function(d) { - return d.is(accept); - }; - } else { - $.widget.prototype._setData.apply(this, arguments); - } - - }, - - _activate: function(event) { - - var draggable = $.ui.ddmanager.current; - $.ui.plugin.call(this, 'activate', [event, this.ui(draggable)]); - (draggable && this._trigger('activate', event, this.ui(draggable))); - - }, - - _deactivate: function(event) { - - var draggable = $.ui.ddmanager.current; - $.ui.plugin.call(this, 'deactivate', [event, this.ui(draggable)]); - (draggable && this._trigger('deactivate', event, this.ui(draggable))); - - }, - - _over: function(event) { - - var draggable = $.ui.ddmanager.current; - if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element - - if (this.options.accept.call(this.element,(draggable.currentItem || draggable.element))) { - $.ui.plugin.call(this, 'over', [event, this.ui(draggable)]); - this._trigger('over', event, this.ui(draggable)); - } - - }, - - _out: function(event) { - - var draggable = $.ui.ddmanager.current; - if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element - - if (this.options.accept.call(this.element,(draggable.currentItem || draggable.element))) { - $.ui.plugin.call(this, 'out', [event, this.ui(draggable)]); - this._trigger('out', event, this.ui(draggable)); - } - - }, - - _drop: function(event,custom) { - - var draggable = custom || $.ui.ddmanager.current; - if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return false; // Bail if draggable and droppable are same element - - var childrenIntersection = false; - this.element.find(":data(droppable)").not("."+draggable.options.cssNamespace+"-draggable-dragging").each(function() { - var inst = $.data(this, 'droppable'); - if(inst.options.greedy && $.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance)) { - childrenIntersection = true; return false; - } - }); - if(childrenIntersection) return false; - - if(this.options.accept.call(this.element,(draggable.currentItem || draggable.element))) { - $.ui.plugin.call(this, 'drop', [event, this.ui(draggable)]); - this._trigger('drop', event, this.ui(draggable)); - return this.element; - } - - return false; - - }, - - plugins: {}, - - ui: function(c) { - return { - draggable: (c.currentItem || c.element), - helper: c.helper, - position: c.position, - absolutePosition: c.positionAbs, - options: this.options, - element: this.element - }; - } - -}); - -$.extend($.ui.droppable, { - version: "1.6rc5", - eventPrefix: 'drop', - defaults: { - accept: '*', - activeClass: null, - cssNamespace: 'ui', - greedy: false, - hoverClass: null, - scope: 'default', - tolerance: 'intersect' - } -}); - -$.ui.intersect = function(draggable, droppable, toleranceMode) { - - if (!droppable.offset) return false; - - var x1 = (draggable.positionAbs || draggable.position.absolute).left, x2 = x1 + draggable.helperProportions.width, - y1 = (draggable.positionAbs || draggable.position.absolute).top, y2 = y1 + draggable.helperProportions.height; - var l = droppable.offset.left, r = l + droppable.proportions.width, - t = droppable.offset.top, b = t + droppable.proportions.height; - - switch (toleranceMode) { - case 'fit': - return (l < x1 && x2 < r - && t < y1 && y2 < b); - break; - case 'intersect': - return (l < x1 + (draggable.helperProportions.width / 2) // Right Half - && x2 - (draggable.helperProportions.width / 2) < r // Left Half - && t < y1 + (draggable.helperProportions.height / 2) // Bottom Half - && y2 - (draggable.helperProportions.height / 2) < b ); // Top Half - break; - case 'pointer': - var draggableLeft = ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left), - draggableTop = ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top), - isOver = $.ui.isOver(draggableTop, draggableLeft, t, l, droppable.proportions.height, droppable.proportions.width); - return isOver; - break; - case 'touch': - return ( - (y1 >= t && y1 <= b) || // Top edge touching - (y2 >= t && y2 <= b) || // Bottom edge touching - (y1 < t && y2 > b) // Surrounded vertically - ) && ( - (x1 >= l && x1 <= r) || // Left edge touching - (x2 >= l && x2 <= r) || // Right edge touching - (x1 < l && x2 > r) // Surrounded horizontally - ); - break; - default: - return false; - break; - } - -}; - -/* - This manager tracks offsets of draggables and droppables -*/ -$.ui.ddmanager = { - current: null, - droppables: { 'default': [] }, - prepareOffsets: function(t, event) { - - var m = $.ui.ddmanager.droppables[t.options.scope]; - var type = event ? event.type : null; // workaround for #2317 - var list = (t.currentItem || t.element).find(":data(droppable)").andSelf(); - - droppablesLoop: for (var i = 0; i < m.length; i++) { - - if(m[i].options.disabled || (t && !m[i].options.accept.call(m[i].element,(t.currentItem || t.element)))) continue; //No disabled and non-accepted - for (var j=0; j < list.length; j++) { if(list[j] == m[i].element[0]) { m[i].proportions.height = 0; continue droppablesLoop; } }; //Filter out elements in the current dragged item - m[i].visible = m[i].element.css("display") != "none"; if(!m[i].visible) continue; //If the element is not visible, continue - - m[i].offset = m[i].element.offset(); - m[i].proportions = { width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight }; - - if(type == "dragstart" || type == "sortactivate") m[i]._activate.call(m[i], event); //Activate the droppable if used directly from draggables - - } - - }, - drop: function(draggable, event) { - - var dropped = false; - $.each($.ui.ddmanager.droppables[draggable.options.scope], function() { - - if(!this.options) return; - if (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance)) - dropped = this._drop.call(this, event); - - if (!this.options.disabled && this.visible && this.options.accept.call(this.element,(draggable.currentItem || draggable.element))) { - this.isout = 1; this.isover = 0; - this._deactivate.call(this, event); - } - - }); - return dropped; - - }, - drag: function(draggable, event) { - - //If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse. - if(draggable.options.refreshPositions) $.ui.ddmanager.prepareOffsets(draggable, event); - - //Run through all droppables and check their positions based on specific tolerance options - - $.each($.ui.ddmanager.droppables[draggable.options.scope], function() { - - if(this.options.disabled || this.greedyChild || !this.visible) return; - var intersects = $.ui.intersect(draggable, this, this.options.tolerance); - - var c = !intersects && this.isover == 1 ? 'isout' : (intersects && this.isover == 0 ? 'isover' : null); - if(!c) return; - - var parentInstance; - if (this.options.greedy) { - var parent = this.element.parents(':data(droppable):eq(0)'); - if (parent.length) { - parentInstance = $.data(parent[0], 'droppable'); - parentInstance.greedyChild = (c == 'isover' ? 1 : 0); - } - } - - // we just moved into a greedy child - if (parentInstance && c == 'isover') { - parentInstance['isover'] = 0; - parentInstance['isout'] = 1; - parentInstance._out.call(parentInstance, event); - } - - this[c] = 1; this[c == 'isout' ? 'isover' : 'isout'] = 0; - this[c == "isover" ? "_over" : "_out"].call(this, event); - - // we just moved out of a greedy child - if (parentInstance && c == 'isout') { - parentInstance['isout'] = 0; - parentInstance['isover'] = 1; - parentInstance._over.call(parentInstance, event); - } - }); - - } -}; - -/* - * Droppable Extensions - */ - -$.ui.plugin.add("droppable", "activeClass", { - activate: function(event, ui) { - $(this).addClass(ui.options.activeClass); - }, - deactivate: function(event, ui) { - $(this).removeClass(ui.options.activeClass); - }, - drop: function(event, ui) { - $(this).removeClass(ui.options.activeClass); - } -}); - -$.ui.plugin.add("droppable", "hoverClass", { - over: function(event, ui) { - $(this).addClass(ui.options.hoverClass); - }, - out: function(event, ui) { - $(this).removeClass(ui.options.hoverClass); - }, - drop: function(event, ui) { - $(this).removeClass(ui.options.hoverClass); - } -}); - -})(jQuery); -/* - * jQuery UI Resizable 1.6rc5 - * - * Copyright (c) 2009 AUTHORS.txt (http://ui.jquery.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Resizables - * - * Depends: - * ui.core.js - */ -(function($) { - -$.widget("ui.resizable", $.extend({}, $.ui.mouse, { - - _init: function() { - - var self = this, o = this.options; - - var elpos = this.element.css('position'); - - this.originalElement = this.element; - - // simulate .ui-resizable { position: relative; } - this.element.addClass("ui-resizable").css({ position: /static/.test(elpos) ? 'relative' : elpos }); - - $.extend(o, { - _aspectRatio: !!(o.aspectRatio), - helper: o.helper || o.ghost || o.animate ? o.helper || 'ui-resizable-helper' : null, - knobHandles: o.knobHandles === true ? 'ui-resizable-knob-handle' : o.knobHandles - }); - - //Default Theme - var aBorder = '1px solid #DEDEDE'; - - o.defaultTheme = { - 'ui-resizable': { display: 'block' }, - 'ui-resizable-handle': { position: 'absolute', background: '#F2F2F2', fontSize: '0.1px' }, - 'ui-resizable-n': { cursor: 'n-resize', height: '4px', left: '0px', right: '0px', borderTop: aBorder }, - 'ui-resizable-s': { cursor: 's-resize', height: '4px', left: '0px', right: '0px', borderBottom: aBorder }, - 'ui-resizable-e': { cursor: 'e-resize', width: '4px', top: '0px', bottom: '0px', borderRight: aBorder }, - 'ui-resizable-w': { cursor: 'w-resize', width: '4px', top: '0px', bottom: '0px', borderLeft: aBorder }, - 'ui-resizable-se': { cursor: 'se-resize', width: '4px', height: '4px', borderRight: aBorder, borderBottom: aBorder }, - 'ui-resizable-sw': { cursor: 'sw-resize', width: '4px', height: '4px', borderBottom: aBorder, borderLeft: aBorder }, - 'ui-resizable-ne': { cursor: 'ne-resize', width: '4px', height: '4px', borderRight: aBorder, borderTop: aBorder }, - 'ui-resizable-nw': { cursor: 'nw-resize', width: '4px', height: '4px', borderLeft: aBorder, borderTop: aBorder } - }; - - o.knobTheme = { - 'ui-resizable-handle': { background: '#F2F2F2', border: '1px solid #808080', height: '8px', width: '8px' }, - 'ui-resizable-n': { cursor: 'n-resize', top: '0px', left: '45%' }, - 'ui-resizable-s': { cursor: 's-resize', bottom: '0px', left: '45%' }, - 'ui-resizable-e': { cursor: 'e-resize', right: '0px', top: '45%' }, - 'ui-resizable-w': { cursor: 'w-resize', left: '0px', top: '45%' }, - 'ui-resizable-se': { cursor: 'se-resize', right: '0px', bottom: '0px' }, - 'ui-resizable-sw': { cursor: 'sw-resize', left: '0px', bottom: '0px' }, - 'ui-resizable-nw': { cursor: 'nw-resize', left: '0px', top: '0px' }, - 'ui-resizable-ne': { cursor: 'ne-resize', right: '0px', top: '0px' } - }; - - o._nodeName = this.element[0].nodeName; - - //Wrap the element if it cannot hold child nodes - if(o._nodeName.match(/canvas|textarea|input|select|button|img/i)) { - var el = this.element; - - //Opera fixing relative position - if (/relative/.test(el.css('position')) && $.browser.opera) - el.css({ position: 'relative', top: 'auto', left: 'auto' }); - - //Create a wrapper element and set the wrapper to the new current internal element - el.wrap( - $('
').css( { - position: el.css('position'), - width: el.outerWidth(), - height: el.outerHeight(), - top: el.css('top'), - left: el.css('left') - }) - ); - - var oel = this.element; this.element = this.element.parent(); - - // store instance on wrapper - this.element.data('resizable', this); - - //Move margins to the wrapper - this.element.css({ marginLeft: oel.css("marginLeft"), marginTop: oel.css("marginTop"), - marginRight: oel.css("marginRight"), marginBottom: oel.css("marginBottom") - }); - - oel.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0}); - - //Prevent Safari textarea resize - if ($.browser.safari && o.preventDefault) oel.css('resize', 'none'); - - o.proportionallyResize = oel.css({ position: 'static', zoom: 1, display: 'block' }); - - // avoid IE jump - this.element.css({ margin: oel.css('margin') }); - - // fix handlers offset - this._proportionallyResize(); - } - - if(!o.handles) o.handles = !$('.ui-resizable-handle', this.element).length ? "e,s,se" : { n: '.ui-resizable-n', e: '.ui-resizable-e', s: '.ui-resizable-s', w: '.ui-resizable-w', se: '.ui-resizable-se', sw: '.ui-resizable-sw', ne: '.ui-resizable-ne', nw: '.ui-resizable-nw' }; - if(o.handles.constructor == String) { - - o.zIndex = o.zIndex || 1000; - - if(o.handles == 'all') o.handles = 'n,e,s,w,se,sw,ne,nw'; - - var n = o.handles.split(","); o.handles = {}; - - // insertions are applied when don't have theme loaded - var insertionsDefault = { - handle: 'position: absolute; display: none; overflow:hidden;', - n: 'top: 0pt; width:100%;', - e: 'right: 0pt; height:100%;', - s: 'bottom: 0pt; width:100%;', - w: 'left: 0pt; height:100%;', - se: 'bottom: 0pt; right: 0px;', - sw: 'bottom: 0pt; left: 0px;', - ne: 'top: 0pt; right: 0px;', - nw: 'top: 0pt; left: 0px;' - }; - - for(var i = 0; i < n.length; i++) { - var handle = $.trim(n[i]), dt = o.defaultTheme, hname = 'ui-resizable-'+handle, loadDefault = !$.ui.css(hname) && !o.knobHandles, userKnobClass = $.ui.css('ui-resizable-knob-handle'), - allDefTheme = $.extend(dt[hname], dt['ui-resizable-handle']), allKnobTheme = $.extend(o.knobTheme[hname], !userKnobClass ? o.knobTheme['ui-resizable-handle'] : {}); - - // increase zIndex of sw, se, ne, nw axis - var applyZIndex = /sw|se|ne|nw/.test(handle) ? { zIndex: ++o.zIndex } : {}; - - var defCss = (loadDefault ? insertionsDefault[handle] : ''), - axis = $(['
'].join('')).css( applyZIndex ); - - if ('se' == handle) { - axis.addClass('ui-icon ui-icon-gripsmall-diagonal-se'); - }; - - o.handles[handle] = '.ui-resizable-'+handle; - - this.element.append( - //Theme detection, if not loaded, load o.defaultTheme - axis.css( loadDefault ? allDefTheme : {} ) - // Load the knobHandle css, fix width, height, top, left... - .css( o.knobHandles ? allKnobTheme : {} ).addClass(o.knobHandles ? 'ui-resizable-knob-handle' : '').addClass(o.knobHandles) - ); - } - - if (o.knobHandles) this.element.addClass('ui-resizable-knob').css( !$.ui.css('ui-resizable-knob') ? { /*border: '1px #fff dashed'*/ } : {} ); - } - - this._renderAxis = function(target) { - target = target || this.element; - - for(var i in o.handles) { - if(o.handles[i].constructor == String) - o.handles[i] = $(o.handles[i], this.element).show(); - - if (o.transparent) - o.handles[i].css({opacity:0}); - - //Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls) - if (this.element.is('.ui-wrapper') && - o._nodeName.match(/textarea|input|select|button/i)) { - - var axis = $(o.handles[i], this.element), padWrapper = 0; - - //Checking the correct pad and border - padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth(); - - //The padding type i have to apply... - var padPos = [ 'padding', - /ne|nw|n/.test(i) ? 'Top' : - /se|sw|s/.test(i) ? 'Bottom' : - /^e$/.test(i) ? 'Right' : 'Left' ].join(""); - - if (!o.transparent) - target.css(padPos, padWrapper); - - this._proportionallyResize(); - } - if(!$(o.handles[i]).length) continue; - } - }; - - this._renderAxis(this.element); - o._handles = $('.ui-resizable-handle', self.element); - - if (o.disableSelection) - o._handles.disableSelection(); - - //Matching axis name - o._handles.mouseover(function() { - if (!o.resizing) { - if (this.className) - var axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i); - //Axis, default = se - self.axis = o.axis = axis && axis[1] ? axis[1] : 'se'; - } - }); - - //If we want to auto hide the elements - if (o.autoHide) { - o._handles.hide(); - $(self.element).addClass("ui-resizable-autohide").hover(function() { - $(this).removeClass("ui-resizable-autohide"); - o._handles.show(); - }, - function(){ - if (!o.resizing) { - $(this).addClass("ui-resizable-autohide"); - o._handles.hide(); - } - }); - } - - this._mouseInit(); - }, - - destroy: function() { - var el = this.element, wrapped = el.children(".ui-resizable").get(0); - - this._mouseDestroy(); - - var _destroy = function(exp) { - $(exp).removeClass("ui-resizable ui-resizable-disabled") - .removeData("resizable").unbind(".resizable").find('.ui-resizable-handle').remove(); - }; - - _destroy(el); - - if (el.is('.ui-wrapper') && wrapped) { - el.parent().append( - $(wrapped).css({ - position: el.css('position'), - width: el.outerWidth(), - height: el.outerHeight(), - top: el.css('top'), - left: el.css('left') - }) - ).end().remove(); - - _destroy(wrapped); - } - }, - - _mouseCapture: function(event) { - - if(this.options.disabled) return false; - - var handle = false; - for(var i in this.options.handles) { - if($(this.options.handles[i])[0] == event.target) handle = true; - } - if (!handle) return false; - - return true; - - }, - - _mouseStart: function(event) { - - var o = this.options, iniPos = this.element.position(), el = this.element, - num = function(v) { return parseInt(v, 10) || 0; }, ie6 = $.browser.msie && $.browser.version < 7; - o.resizing = true; - o.documentScroll = { top: $(document).scrollTop(), left: $(document).scrollLeft() }; - - // bugfix #1749 - if (el.is('.ui-draggable') || (/absolute/).test(el.css('position'))) { - - // sOffset decides if document scrollOffset will be added to the top/left of the resizable element - var sOffset = $.browser.msie && !o.containment && (/absolute/).test(el.css('position')) && !(/relative/).test(el.parent().css('position')); - var dscrollt = sOffset ? o.documentScroll.top : 0, dscrolll = sOffset ? o.documentScroll.left : 0; - - el.css({ position: 'absolute', top: (iniPos.top + dscrollt), left: (iniPos.left + dscrolll) }); - } - - //Opera fixing relative position - if ($.browser.opera && (/relative/).test(el.css('position'))) - el.css({ position: 'relative', top: 'auto', left: 'auto' }); - - this._renderProxy(); - - var curleft = num(this.helper.css('left')), curtop = num(this.helper.css('top')); - - if (o.containment) { - curleft += $(o.containment).scrollLeft()||0; - curtop += $(o.containment).scrollTop()||0; - } - - //Store needed variables - this.offset = this.helper.offset(); - this.position = { left: curleft, top: curtop }; - this.size = o.helper || ie6 ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() }; - this.originalSize = o.helper || ie6 ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() }; - this.originalPosition = { left: curleft, top: curtop }; - this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() }; - this.originalMousePosition = { left: event.pageX, top: event.pageY }; - - //Aspect Ratio - o.aspectRatio = (typeof o.aspectRatio == 'number') ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height)||1); - - if (o.preserveCursor) { - var cursor = $('.ui-resizable-' + this.axis).css('cursor'); - $('body').css('cursor', cursor == 'auto' ? this.axis + '-resize' : cursor); - } - - this._propagate("start", event); - return true; - }, - - _mouseDrag: function(event) { - - //Increase performance, avoid regex - var el = this.helper, o = this.options, props = {}, - self = this, smp = this.originalMousePosition, a = this.axis; - - var dx = (event.pageX-smp.left)||0, dy = (event.pageY-smp.top)||0; - var trigger = this._change[a]; - if (!trigger) return false; - - // Calculate the attrs that will be change - var data = trigger.apply(this, [event, dx, dy]), ie6 = $.browser.msie && $.browser.version < 7, csdif = this.sizeDiff; - - if (o._aspectRatio || event.shiftKey) - data = this._updateRatio(data, event); - - data = this._respectSize(data, event); - - // plugins callbacks need to be called first - this._propagate("resize", event); - - el.css({ - top: this.position.top + "px", left: this.position.left + "px", - width: this.size.width + "px", height: this.size.height + "px" - }); - - if (!o.helper && o.proportionallyResize) - this._proportionallyResize(); - - this._updateCache(data); - - // calling the user callback at the end - this._trigger('resize', event, this.ui()); - - return false; - }, - - _mouseStop: function(event) { - - this.options.resizing = false; - var o = this.options, num = function(v) { return parseInt(v, 10) || 0; }, self = this; - - if(o.helper) { - var pr = o.proportionallyResize, ista = pr && (/textarea/i).test(pr.get(0).nodeName), - soffseth = ista && $.ui.hasScroll(pr.get(0), 'left') /* TODO - jump height */ ? 0 : self.sizeDiff.height, - soffsetw = ista ? 0 : self.sizeDiff.width; - - var s = { width: (self.size.width - soffsetw), height: (self.size.height - soffseth) }, - left = (parseInt(self.element.css('left'), 10) + (self.position.left - self.originalPosition.left)) || null, - top = (parseInt(self.element.css('top'), 10) + (self.position.top - self.originalPosition.top)) || null; - - if (!o.animate) - this.element.css($.extend(s, { top: top, left: left })); - - if (o.helper && !o.animate) this._proportionallyResize(); - } - - if (o.preserveCursor) - $('body').css('cursor', 'auto'); - - this._propagate("stop", event); - - if (o.helper) this.helper.remove(); - - return false; - }, - - _updateCache: function(data) { - var o = this.options; - this.offset = this.helper.offset(); - if (data.left) this.position.left = data.left; - if (data.top) this.position.top = data.top; - if (data.height) this.size.height = data.height; - if (data.width) this.size.width = data.width; - }, - - _updateRatio: function(data, event) { - - var o = this.options, cpos = this.position, csize = this.size, a = this.axis; - - if (data.height) data.width = (csize.height * o.aspectRatio); - else if (data.width) data.height = (csize.width / o.aspectRatio); - - if (a == 'sw') { - data.left = cpos.left + (csize.width - data.width); - data.top = null; - } - if (a == 'nw') { - data.top = cpos.top + (csize.height - data.height); - data.left = cpos.left + (csize.width - data.width); - } - - return data; - }, - - _respectSize: function(data, event) { - - var el = this.helper, o = this.options, pRatio = o._aspectRatio || event.shiftKey, a = this.axis, - ismaxw = data.width && o.maxWidth && o.maxWidth < data.width, ismaxh = data.height && o.maxHeight && o.maxHeight < data.height, - isminw = data.width && o.minWidth && o.minWidth > data.width, isminh = data.height && o.minHeight && o.minHeight > data.height; - - if (isminw) data.width = o.minWidth; - if (isminh) data.height = o.minHeight; - if (ismaxw) data.width = o.maxWidth; - if (ismaxh) data.height = o.maxHeight; - - var dw = this.originalPosition.left + this.originalSize.width, dh = this.position.top + this.size.height; - var cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a); - - if (isminw && cw) data.left = dw - o.minWidth; - if (ismaxw && cw) data.left = dw - o.maxWidth; - if (isminh && ch) data.top = dh - o.minHeight; - if (ismaxh && ch) data.top = dh - o.maxHeight; - - // fixing jump error on top/left - bug #2330 - var isNotwh = !data.width && !data.height; - if (isNotwh && !data.left && data.top) data.top = null; - else if (isNotwh && !data.top && data.left) data.left = null; - - return data; - }, - - _proportionallyResize: function() { - var o = this.options; - if (!o.proportionallyResize) return; - var prel = o.proportionallyResize, el = this.helper || this.element; - - if (!o.borderDif) { - var b = [prel.css('borderTopWidth'), prel.css('borderRightWidth'), prel.css('borderBottomWidth'), prel.css('borderLeftWidth')], - p = [prel.css('paddingTop'), prel.css('paddingRight'), prel.css('paddingBottom'), prel.css('paddingLeft')]; - - o.borderDif = $.map(b, function(v, i) { - var border = parseInt(v,10)||0, padding = parseInt(p[i],10)||0; - return border + padding; - }); - } - - if ($.browser.msie && !isVisible(el)) - return; - - prel.css({ - height: (el.height() - o.borderDif[0] - o.borderDif[2]) || 0, - width: (el.width() - o.borderDif[1] - o.borderDif[3]) || 0 - }); - }, - - _renderProxy: function() { - var el = this.element, o = this.options; - this.elementOffset = el.offset(); - - if(o.helper) { - this.helper = this.helper || $('
'); - - // fix ie6 offset - var ie6 = $.browser.msie && $.browser.version < 7, ie6offset = (ie6 ? 1 : 0), - pxyoffset = ( ie6 ? 2 : -1 ); - - this.helper.addClass(o.helper).css({ - width: el.outerWidth() + pxyoffset, - height: el.outerHeight() + pxyoffset, - position: 'absolute', - left: this.elementOffset.left - ie6offset +'px', - top: this.elementOffset.top - ie6offset +'px', - zIndex: ++o.zIndex - }); - - this.helper.appendTo("body"); - - if (o.disableSelection) - this.helper.disableSelection(); - - } else { - this.helper = el; - } - }, - - _change: { - e: function(event, dx, dy) { - return { width: this.originalSize.width + dx }; - }, - w: function(event, dx, dy) { - var o = this.options, cs = this.originalSize, sp = this.originalPosition; - return { left: sp.left + dx, width: cs.width - dx }; - }, - n: function(event, dx, dy) { - var o = this.options, cs = this.originalSize, sp = this.originalPosition; - return { top: sp.top + dy, height: cs.height - dy }; - }, - s: function(event, dx, dy) { - return { height: this.originalSize.height + dy }; - }, - se: function(event, dx, dy) { - return $.extend(this._change.s.apply(this, arguments), this._change.e.apply(this, [event, dx, dy])); - }, - sw: function(event, dx, dy) { - return $.extend(this._change.s.apply(this, arguments), this._change.w.apply(this, [event, dx, dy])); - }, - ne: function(event, dx, dy) { - return $.extend(this._change.n.apply(this, arguments), this._change.e.apply(this, [event, dx, dy])); - }, - nw: function(event, dx, dy) { - return $.extend(this._change.n.apply(this, arguments), this._change.w.apply(this, [event, dx, dy])); - } - }, - - _propagate: function(n, event) { - $.ui.plugin.call(this, n, [event, this.ui()]); - - (n != "resize" && this._trigger(n, event, this.ui())); - }, - - plugins: {}, - - ui: function() { - return { - originalElement: this.originalElement, - element: this.element, - helper: this.helper, - position: this.position, - size: this.size, - options: this.options, - originalSize: this.originalSize, - originalPosition: this.originalPosition - }; - } - -})); - -$.extend($.ui.resizable, { - version: "1.6rc5", - eventPrefix: "resize", - defaults: { - alsoResize: false, - animate: false, - animateDuration: "slow", - animateEasing: "swing", - aspectRatio: false, - autoHide: false, - cancel: ":input,option", - containment: false, - delay: 0, - disableSelection: true, - distance: 1, - ghost: false, - grid: false, - knobHandles: false, - maxHeight: null, - maxWidth: null, - minHeight: 10, - minWidth: 10, - preserveCursor: true, - preventDefault: true, - proportionallyResize: false, - transparent: false - } -}); - -/* - * Resizable Extensions - */ - -$.ui.plugin.add("resizable", "alsoResize", { - - start: function(event, ui) { - var o = ui.options, self = $(this).data("resizable"), - - _store = function(exp) { - $(exp).each(function() { - $(this).data("resizable-alsoresize", { - width: parseInt($(this).width(), 10), height: parseInt($(this).height(), 10), - left: parseInt($(this).css('left'), 10), top: parseInt($(this).css('top'), 10) - }); - }); - }; - - if (typeof(o.alsoResize) == 'object' && !o.alsoResize.parentNode) { - if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); } - else { $.each(o.alsoResize, function(exp, c) { _store(exp); }); } - }else{ - _store(o.alsoResize); - } - }, - - resize: function(event, ui){ - var o = ui.options, self = $(this).data("resizable"), os = self.originalSize, op = self.originalPosition; - - var delta = { - height: (self.size.height - os.height) || 0, width: (self.size.width - os.width) || 0, - top: (self.position.top - op.top) || 0, left: (self.position.left - op.left) || 0 - }, - - _alsoResize = function(exp, c) { - $(exp).each(function() { - var el = $(this), start = $(this).data("resizable-alsoresize"), style = {}, css = c && c.length ? c : ['width', 'height', 'top', 'left']; - - $.each(css || ['width', 'height', 'top', 'left'], function(i, prop) { - var sum = (start[prop]||0) + (delta[prop]||0); - if (sum && sum >= 0) - style[prop] = sum || null; - }); - - //Opera fixing relative position - if (/relative/.test(el.css('position')) && $.browser.opera) { - self._revertToRelativePosition = true; - el.css({ position: 'absolute', top: 'auto', left: 'auto' }); - } - - el.css(style); - }); - }; - - if (typeof(o.alsoResize) == 'object' && !o.alsoResize.nodeType) { - $.each(o.alsoResize, function(exp, c) { _alsoResize(exp, c); }); - }else{ - _alsoResize(o.alsoResize); - } - }, - - stop: function(event, ui){ - var self = $(this).data("resizable"); - - //Opera fixing relative position - if (self._revertToRelativePosition && $.browser.opera) { - self._revertToRelativePosition = false; - el.css({ position: 'relative' }); - } - - $(this).removeData("resizable-alsoresize-start"); - } -}); - -$.ui.plugin.add("resizable", "animate", { - - stop: function(event, ui) { - var o = ui.options, self = $(this).data("resizable"); - - var pr = o.proportionallyResize, ista = pr && (/textarea/i).test(pr.get(0).nodeName), - soffseth = ista && $.ui.hasScroll(pr.get(0), 'left') /* TODO - jump height */ ? 0 : self.sizeDiff.height, - soffsetw = ista ? 0 : self.sizeDiff.width; - - var style = { width: (self.size.width - soffsetw), height: (self.size.height - soffseth) }, - left = (parseInt(self.element.css('left'), 10) + (self.position.left - self.originalPosition.left)) || null, - top = (parseInt(self.element.css('top'), 10) + (self.position.top - self.originalPosition.top)) || null; - - self.element.animate( - $.extend(style, top && left ? { top: top, left: left } : {}), { - duration: o.animateDuration, - easing: o.animateEasing, - step: function() { - - var data = { - width: parseInt(self.element.css('width'), 10), - height: parseInt(self.element.css('height'), 10), - top: parseInt(self.element.css('top'), 10), - left: parseInt(self.element.css('left'), 10) - }; - - if (pr) pr.css({ width: data.width, height: data.height }); - - // propagating resize, and updating values for each animation step - self._updateCache(data); - self._propagate("resize", event); - - } - } - ); - } - -}); - -$.ui.plugin.add("resizable", "containment", { - - start: function(event, ui) { - var o = ui.options, self = $(this).data("resizable"), el = self.element; - var oc = o.containment, ce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc; - if (!ce) return; - - self.containerElement = $(ce); - - if (/document/.test(oc) || oc == document) { - self.containerOffset = { left: 0, top: 0 }; - self.containerPosition = { left: 0, top: 0 }; - - self.parentData = { - element: $(document), left: 0, top: 0, - width: $(document).width(), height: $(document).height() || document.body.parentNode.scrollHeight - }; - } - - // i'm a node, so compute top, left, right, bottom - else{ - self.containerOffset = $(ce).offset(); - self.containerPosition = $(ce).position(); - self.containerSize = { height: $(ce).innerHeight(), width: $(ce).innerWidth() }; - - var co = self.containerOffset, ch = self.containerSize.height, cw = self.containerSize.width, - width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw ), height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch); - - self.parentData = { - element: ce, left: co.left, top: co.top, width: width, height: height - }; - } - }, - - resize: function(event, ui) { - var o = ui.options, self = $(this).data("resizable"), - ps = self.containerSize, co = self.containerOffset, cs = self.size, cp = self.position, - pRatio = o._aspectRatio || event.shiftKey, cop = { top:0, left:0 }, ce = self.containerElement; - - if (ce[0] != document && (/static/).test(ce.css('position'))) - cop = self.containerPosition; - - if (cp.left < (o.helper ? co.left : 0)) { - self.size.width = self.size.width + (o.helper ? (self.position.left - co.left) : (self.position.left - cop.left)); - if (pRatio) self.size.height = self.size.width / o.aspectRatio; - self.position.left = o.helper ? co.left : 0; - } - - if (cp.top < (o.helper ? co.top : 0)) { - self.size.height = self.size.height + (o.helper ? (self.position.top - co.top) : self.position.top); - if (pRatio) self.size.width = self.size.height * o.aspectRatio; - self.position.top = o.helper ? co.top : 0; - } - - var woset = Math.abs( (o.helper ? self.offset.left - cop.left : (self.offset.left - cop.left)) + self.sizeDiff.width ), - hoset = Math.abs( (o.helper ? self.offset.top - cop.top : (self.offset.top - co.top)) + self.sizeDiff.height ); - - if (woset + self.size.width >= self.parentData.width) { - self.size.width = self.parentData.width - woset; - if (pRatio) self.size.height = self.size.width / o.aspectRatio; - } - - if (hoset + self.size.height >= self.parentData.height) { - self.size.height = self.parentData.height - hoset; - if (pRatio) self.size.width = self.size.height * o.aspectRatio; - } - }, - - stop: function(event, ui){ - var o = ui.options, self = $(this).data("resizable"), cp = self.position, - co = self.containerOffset, cop = self.containerPosition, ce = self.containerElement; - - var helper = $(self.helper), ho = helper.offset(), w = helper.outerWidth() - self.sizeDiff.width, h = helper.outerHeight() - self.sizeDiff.height; - - if (o.helper && !o.animate && (/relative/).test(ce.css('position'))) - $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h }); - - if (o.helper && !o.animate && (/static/).test(ce.css('position'))) - $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h }); - - } -}); - -$.ui.plugin.add("resizable", "ghost", { - - start: function(event, ui) { - var o = ui.options, self = $(this).data("resizable"), pr = o.proportionallyResize, cs = self.size; - - if (!pr) self.ghost = self.element.clone(); - else self.ghost = pr.clone(); - - self.ghost.css( - { opacity: .25, display: 'block', position: 'relative', height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 } - ) - .addClass('ui-resizable-ghost').addClass(typeof o.ghost == 'string' ? o.ghost : ''); - - self.ghost.appendTo(self.helper); - - }, - - resize: function(event, ui){ - var o = ui.options, self = $(this).data("resizable"), pr = o.proportionallyResize; - - if (self.ghost) self.ghost.css({ position: 'relative', height: self.size.height, width: self.size.width }); - - }, - - stop: function(event, ui){ - var o = ui.options, self = $(this).data("resizable"), pr = o.proportionallyResize; - if (self.ghost && self.helper) self.helper.get(0).removeChild(self.ghost.get(0)); - } - -}); - -$.ui.plugin.add("resizable", "grid", { - - resize: function(event, ui) { - var o = ui.options, self = $(this).data("resizable"), cs = self.size, os = self.originalSize, op = self.originalPosition, a = self.axis, ratio = o._aspectRatio || event.shiftKey; - o.grid = typeof o.grid == "number" ? [o.grid, o.grid] : o.grid; - var ox = Math.round((cs.width - os.width) / (o.grid[0]||1)) * (o.grid[0]||1), oy = Math.round((cs.height - os.height) / (o.grid[1]||1)) * (o.grid[1]||1); - - if (/^(se|s|e)$/.test(a)) { - self.size.width = os.width + ox; - self.size.height = os.height + oy; - } - else if (/^(ne)$/.test(a)) { - self.size.width = os.width + ox; - self.size.height = os.height + oy; - self.position.top = op.top - oy; - } - else if (/^(sw)$/.test(a)) { - self.size.width = os.width + ox; - self.size.height = os.height + oy; - self.position.left = op.left - ox; - } - else { - self.size.width = os.width + ox; - self.size.height = os.height + oy; - self.position.top = op.top - oy; - self.position.left = op.left - ox; - } - } - -}); - -function isVisible(element) { - return !($(element).is(':hidden') || $(element).parents(':hidden').length); -} - -})(jQuery); -/* - * jQuery UI Selectable 1.6rc5 - * - * Copyright (c) 2009 AUTHORS.txt (http://ui.jquery.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Selectables - * - * Depends: - * ui.core.js - */ -(function($) { - -$.widget("ui.selectable", $.extend({}, $.ui.mouse, { - - _init: function() { - var self = this; - - this.element.addClass("ui-selectable"); - - this.dragged = false; - - // cache selectee children based on filter - var selectees; - this.refresh = function() { - selectees = $(self.options.filter, self.element[0]); - selectees.each(function() { - var $this = $(this); - var pos = $this.offset(); - $.data(this, "selectable-item", { - element: this, - $element: $this, - left: pos.left, - top: pos.top, - right: pos.left + $this.outerWidth(), - bottom: pos.top + $this.outerHeight(), - startselected: false, - selected: $this.hasClass('ui-selected'), - selecting: $this.hasClass('ui-selecting'), - unselecting: $this.hasClass('ui-unselecting') - }); - }); - }; - this.refresh(); - - this.selectees = selectees.addClass("ui-selectee"); - - this._mouseInit(); - - this.helper = $(document.createElement('div')) - .css({border:'1px dotted black'}) - .addClass("ui-selectable-helper"); - }, - - destroy: function() { - this.element - .removeClass("ui-selectable ui-selectable-disabled") - .removeData("selectable") - .unbind(".selectable"); - this._mouseDestroy(); - }, - - _mouseStart: function(event) { - var self = this; - - this.opos = [event.pageX, event.pageY]; - - if (this.options.disabled) - return; - - var options = this.options; - - this.selectees = $(options.filter, this.element[0]); - - this._trigger("start", event); - - $('body').append(this.helper); - // position helper (lasso) - this.helper.css({ - "z-index": 100, - "position": "absolute", - "left": event.clientX, - "top": event.clientY, - "width": 0, - "height": 0 - }); - - if (options.autoRefresh) { - this.refresh(); - } - - this.selectees.filter('.ui-selected').each(function() { - var selectee = $.data(this, "selectable-item"); - selectee.startselected = true; - if (!event.metaKey) { - selectee.$element.removeClass('ui-selected'); - selectee.selected = false; - selectee.$element.addClass('ui-unselecting'); - selectee.unselecting = true; - // selectable UNSELECTING callback - self._trigger("unselecting", event, { - unselecting: selectee.element - }); - } - }); - - $(event.target).parents().andSelf().each(function() { - var selectee = $.data(this, "selectable-item"); - if (selectee) { - selectee.$element.removeClass("ui-unselecting").addClass('ui-selecting'); - selectee.unselecting = false; - selectee.selecting = true; - selectee.selected = true; - // selectable SELECTING callback - self._trigger("selecting", event, { - selecting: selectee.element - }); - return false; - } - }); - - }, - - _mouseDrag: function(event) { - var self = this; - this.dragged = true; - - if (this.options.disabled) - return; - - var options = this.options; - - var x1 = this.opos[0], y1 = this.opos[1], x2 = event.pageX, y2 = event.pageY; - if (x1 > x2) { var tmp = x2; x2 = x1; x1 = tmp; } - if (y1 > y2) { var tmp = y2; y2 = y1; y1 = tmp; } - this.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1}); - - this.selectees.each(function() { - var selectee = $.data(this, "selectable-item"); - //prevent helper from being selected if appendTo: selectable - if (!selectee || selectee.element == self.element[0]) - return; - var hit = false; - if (options.tolerance == 'touch') { - hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) ); - } else if (options.tolerance == 'fit') { - hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2); - } - - if (hit) { - // SELECT - if (selectee.selected) { - selectee.$element.removeClass('ui-selected'); - selectee.selected = false; - } - if (selectee.unselecting) { - selectee.$element.removeClass('ui-unselecting'); - selectee.unselecting = false; - } - if (!selectee.selecting) { - selectee.$element.addClass('ui-selecting'); - selectee.selecting = true; - // selectable SELECTING callback - self._trigger("selecting", event, { - selecting: selectee.element - }); - } - } else { - // UNSELECT - if (selectee.selecting) { - if (event.metaKey && selectee.startselected) { - selectee.$element.removeClass('ui-selecting'); - selectee.selecting = false; - selectee.$element.addClass('ui-selected'); - selectee.selected = true; - } else { - selectee.$element.removeClass('ui-selecting'); - selectee.selecting = false; - if (selectee.startselected) { - selectee.$element.addClass('ui-unselecting'); - selectee.unselecting = true; - } - // selectable UNSELECTING callback - self._trigger("unselecting", event, { - unselecting: selectee.element - }); - } - } - if (selectee.selected) { - if (!event.metaKey && !selectee.startselected) { - selectee.$element.removeClass('ui-selected'); - selectee.selected = false; - - selectee.$element.addClass('ui-unselecting'); - selectee.unselecting = true; - // selectable UNSELECTING callback - self._trigger("unselecting", event, { - unselecting: selectee.element - }); - } - } - } - }); - - return false; - }, - - _mouseStop: function(event) { - var self = this; - - this.dragged = false; - - var options = this.options; - - $('.ui-unselecting', this.element[0]).each(function() { - var selectee = $.data(this, "selectable-item"); - selectee.$element.removeClass('ui-unselecting'); - selectee.unselecting = false; - selectee.startselected = false; - self._trigger("unselected", event, { - unselected: selectee.element - }); - }); - $('.ui-selecting', this.element[0]).each(function() { - var selectee = $.data(this, "selectable-item"); - selectee.$element.removeClass('ui-selecting').addClass('ui-selected'); - selectee.selecting = false; - selectee.selected = true; - selectee.startselected = true; - self._trigger("selected", event, { - selected: selectee.element - }); - }); - this._trigger("stop", event); - - this.helper.remove(); - - return false; - } - -})); - -$.extend($.ui.selectable, { - version: "1.6rc5", - defaults: { - appendTo: 'body', - autoRefresh: true, - cancel: ":input,option", - delay: 0, - distance: 0, - filter: '*', - tolerance: 'touch' - } -}); - -})(jQuery); -/* - * jQuery UI Sortable 1.6rc5 - * - * Copyright (c) 2009 AUTHORS.txt (http://ui.jquery.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Sortables - * - * Depends: - * ui.core.js - */ -(function($) { - -$.widget("ui.sortable", $.extend({}, $.ui.mouse, { - _init: function() { - - var o = this.options; - this.containerCache = {}; - (this.options.cssNamespace && this.element.addClass(this.options.cssNamespace+"-sortable")); - - //Get the items - this.refresh(); - - //Let's determine if the items are floating - this.floating = this.items.length ? (/left|right/).test(this.items[0].item.css('float')) : false; - - //Let's determine the parent's offset - this.offset = this.element.offset(); - - //Initialize mouse events for interaction - this._mouseInit(); - - }, - - destroy: function() { - this.element - .removeClass(this.options.cssNamespace+"-sortable "+this.options.cssNamespace+"-sortable-disabled") - .removeData("sortable") - .unbind(".sortable"); - this._mouseDestroy(); - - for ( var i = this.items.length - 1; i >= 0; i-- ) - this.items[i].item.removeData("sortable-item"); - }, - - _mouseCapture: function(event, overrideHandle) { - - if (this.reverting) { - return false; - } - - if(this.options.disabled || this.options.type == 'static') return false; - - //We have to refresh the items data once first - this._refreshItems(event); - - //Find out if the clicked node (or one of its parents) is a actual item in this.items - var currentItem = null, self = this, nodes = $(event.target).parents().each(function() { - if($.data(this, 'sortable-item') == self) { - currentItem = $(this); - return false; - } - }); - if($.data(event.target, 'sortable-item') == self) currentItem = $(event.target); - - if(!currentItem) return false; - if(this.options.handle && !overrideHandle) { - var validHandle = false; - - $(this.options.handle, currentItem).find("*").andSelf().each(function() { if(this == event.target) validHandle = true; }); - if(!validHandle) return false; - } - - this.currentItem = currentItem; - this._removeCurrentsFromItems(); - return true; - - }, - - _mouseStart: function(event, overrideHandle, noActivation) { - - var o = this.options; - this.currentContainer = this; - - //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture - this.refreshPositions(); - - //Create and append the visible helper - this.helper = this._createHelper(event); - - //Cache the helper size - this._cacheHelperProportions(); - - /* - * - Position generation - - * This block generates everything position related - it's the core of draggables. - */ - - //Cache the margins of the original element - this._cacheMargins(); - - //Get the next scrolling parent - this.scrollParent = this.helper.scrollParent(); - - //The element's absolute position on the page minus margins - this.offset = this.currentItem.offset(); - this.offset = { - top: this.offset.top - this.margins.top, - left: this.offset.left - this.margins.left - }; - - // Only after we got the offset, we can change the helper's position to absolute - // TODO: Still need to figure out a way to make relative sorting possible - this.helper.css("position", "absolute"); - this.cssPosition = this.helper.css("position"); - - $.extend(this.offset, { - click: { //Where the click happened, relative to the element - left: event.pageX - this.offset.left, - top: event.pageY - this.offset.top - }, - parent: this._getParentOffset(), - relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper - }); - - //Generate the original position - this.originalPosition = this._generatePosition(event); - this.originalPageX = event.pageX; - this.originalPageY = event.pageY; - - //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied - if(o.cursorAt) - this._adjustOffsetFromHelper(o.cursorAt); - - //Cache the former DOM position - this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] }; - - //If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way - if(this.helper[0] != this.currentItem[0]) { - this.currentItem.hide(); - } - - //Create the placeholder - this._createPlaceholder(); - - //Set a containment if given in the options - if(o.containment) - this._setContainment(); - - //Call plugins and callbacks - this._trigger("start", event); - - //Recache the helper size - if(!this._preserveHelperProportions) - this._cacheHelperProportions(); - - - //Post 'activate' events to possible containers - if(!noActivation) { - for (var i = this.containers.length - 1; i >= 0; i--) { this.containers[i]._trigger("activate", event, this); } - } - - //Prepare possible droppables - if($.ui.ddmanager) - $.ui.ddmanager.current = this; - - if ($.ui.ddmanager && !o.dropBehaviour) - $.ui.ddmanager.prepareOffsets(this, event); - - this.dragging = true; - - this.helper.addClass(o.cssNamespace+'-sortable-helper'); - this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position - return true; - - }, - - _mouseDrag: function(event) { - - //Compute the helpers position - this.position = this._generatePosition(event); - this.positionAbs = this._convertPositionTo("absolute"); - - if (!this.lastPositionAbs) { - this.lastPositionAbs = this.positionAbs; - } - - //Call the internal plugins - $.ui.plugin.call(this, "sort", [event, this._uiHash()]); - - //Regenerate the absolute position used for position checks - this.positionAbs = this._convertPositionTo("absolute"); - - //Set the helper position - if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px'; - if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px'; - - //Rearrange - for (var i = this.items.length - 1; i >= 0; i--) { - - //Cache variables and intersection, continue if no intersection - var item = this.items[i], itemElement = item.item[0], intersection = this._intersectsWithPointer(item); - if (!intersection) continue; - - if(itemElement != this.currentItem[0] //cannot intersect with itself - && this.placeholder[intersection == 1 ? "next" : "prev"]()[0] != itemElement //no useless actions that have been done before - && !$.ui.contains(this.placeholder[0], itemElement) //no action if the item moved is the parent of the item checked - && (this.options.type == 'semi-dynamic' ? !$.ui.contains(this.element[0], itemElement) : true) - ) { - - this.direction = intersection == 1 ? "down" : "up"; - - if (this.options.tolerance == "pointer" || this._intersectsWithSides(item)) { - this.options.sortIndicator.call(this, event, item); - } else { - break; - } - - this._trigger("change", event); //Call plugins and callbacks - break; - } - } - - //Post events to containers - this._contactContainers(event); - - //Interconnect with droppables - if($.ui.ddmanager) $.ui.ddmanager.drag(this, event); - - //Call callbacks - this._trigger('sort', event); - - this.lastPositionAbs = this.positionAbs; - return false; - - }, - - _mouseStop: function(event, noPropagation) { - - if(!event) return; - - //If we are using droppables, inform the manager about the drop - if ($.ui.ddmanager && !this.options.dropBehaviour) - $.ui.ddmanager.drop(this, event); - - if(this.options.revert) { - var self = this; - var cur = self.placeholder.offset(); - - self.reverting = true; - - $(this.helper).animate({ - left: cur.left - this.offset.parent.left - self.margins.left + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollLeft), - top: cur.top - this.offset.parent.top - self.margins.top + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollTop) - }, parseInt(this.options.revert, 10) || 500, function() { - self._clear(event); - }); - } else { - this._clear(event, noPropagation); - } - - return false; - - }, - - cancel: function() { - - if(this.dragging) { - - this._mouseUp(); - - if(this.options.helper == "original") - this.currentItem.css(this._storedCSS).removeClass(this.options.cssNamespace+"-sortable-helper"); - else - this.currentItem.show(); - - //Post deactivating events to containers - for (var i = this.containers.length - 1; i >= 0; i--){ - this.containers[i]._trigger("deactivate", null, this); - if(this.containers[i].containerCache.over) { - this.containers[i]._trigger("out", null, this); - this.containers[i].containerCache.over = 0; - } - } - - } - - //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! - if(this.placeholder[0].parentNode) this.placeholder[0].parentNode.removeChild(this.placeholder[0]); - if(this.options.helper != "original" && this.helper && this.helper[0].parentNode) this.helper.remove(); - - $.extend(this, { - helper: null, - dragging: false, - reverting: false, - _noFinalSort: null - }); - - if(this.domPosition.prev) { - $(this.domPosition.prev).after(this.currentItem); - } else { - $(this.domPosition.parent).prepend(this.currentItem); - } - - return true; - - }, - - serialize: function(o) { - - var items = this._getItemsAsjQuery(o && o.connected); - var str = []; o = o || {}; - - $(items).each(function() { - var res = ($(o.item || this).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/)); - if(res) str.push((o.key || res[1]+'[]')+'='+(o.key && o.expression ? res[1] : res[2])); - }); - - return str.join('&'); - - }, - - toArray: function(o) { - - var items = this._getItemsAsjQuery(o && o.connected); - var ret = []; o = o || {}; - - items.each(function() { ret.push($(o.item || this).attr(o.attribute || 'id') || ''); }); - return ret; - - }, - - /* Be careful with the following core functions */ - _intersectsWith: function(item) { - - var x1 = this.positionAbs.left, - x2 = x1 + this.helperProportions.width, - y1 = this.positionAbs.top, - y2 = y1 + this.helperProportions.height; - - var l = item.left, - r = l + item.width, - t = item.top, - b = t + item.height; - - var dyClick = this.offset.click.top, - dxClick = this.offset.click.left; - - var isOverElement = (y1 + dyClick) > t && (y1 + dyClick) < b && (x1 + dxClick) > l && (x1 + dxClick) < r; - - if( this.options.tolerance == "pointer" - || this.options.forcePointerForContainers - || (this.options.tolerance != "pointer" && this.helperProportions[this.floating ? 'width' : 'height'] > item[this.floating ? 'width' : 'height']) - ) { - return isOverElement; - } else { - - return (l < x1 + (this.helperProportions.width / 2) // Right Half - && x2 - (this.helperProportions.width / 2) < r // Left Half - && t < y1 + (this.helperProportions.height / 2) // Bottom Half - && y2 - (this.helperProportions.height / 2) < b ); // Top Half - - } - }, - - _intersectsWithPointer: function(item) { - - var isOverElementHeight = $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height), - isOverElementWidth = $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width), - isOverElement = isOverElementHeight && isOverElementWidth, - verticalDirection = this._getDragVerticalDirection(), - horizontalDirection = this._getDragHorizontalDirection(); - - if (!isOverElement) - return false; - - return this.floating ? - ( ((horizontalDirection && horizontalDirection == "right") || verticalDirection == "down") ? 2 : 1 ) - : ( verticalDirection && (verticalDirection == "down" ? 2 : 1) ); - - }, - - _intersectsWithSides: function(item) { - - var isOverBottomHalf = $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height), - isOverRightHalf = $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width), - verticalDirection = this._getDragVerticalDirection(), - horizontalDirection = this._getDragHorizontalDirection(); - - if (this.floating && horizontalDirection) { - return ((horizontalDirection == "right" && isOverRightHalf) || (horizontalDirection == "left" && !isOverRightHalf)); - } else { - return verticalDirection && ((verticalDirection == "down" && isOverBottomHalf) || (verticalDirection == "up" && !isOverBottomHalf)); - } - - }, - - _getDragVerticalDirection: function() { - var delta = this.positionAbs.top - this.lastPositionAbs.top; - return delta != 0 && (delta > 0 ? "down" : "up"); - }, - - _getDragHorizontalDirection: function() { - var delta = this.positionAbs.left - this.lastPositionAbs.left; - return delta != 0 && (delta > 0 ? "right" : "left"); - }, - - refresh: function(event) { - this._refreshItems(event); - this.refreshPositions(); - }, - - _getItemsAsjQuery: function(connected) { - - var self = this; - var items = []; - var queries = []; - - if(this.options.connectWith && connected) { - for (var i = this.options.connectWith.length - 1; i >= 0; i--){ - var cur = $(this.options.connectWith[i]); - for (var j = cur.length - 1; j >= 0; j--){ - var inst = $.data(cur[j], 'sortable'); - if(inst && inst != this && !inst.options.disabled) { - queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not("."+inst.options.cssNamespace+"-sortable-helper"), inst]); - } - }; - }; - } - - queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not("."+this.options.cssNamespace+"-sortable-helper"), this]); - - for (var i = queries.length - 1; i >= 0; i--){ - queries[i][0].each(function() { - items.push(this); - }); - }; - - return $(items); - - }, - - _removeCurrentsFromItems: function() { - - var list = this.currentItem.find(":data(sortable-item)"); - - for (var i=0; i < this.items.length; i++) { - - for (var j=0; j < list.length; j++) { - if(list[j] == this.items[i].item[0]) - this.items.splice(i,1); - }; - - }; - - }, - - _refreshItems: function(event) { - - this.items = []; - this.containers = [this]; - var items = this.items; - var self = this; - var queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]]; - - if(this.options.connectWith) { - for (var i = this.options.connectWith.length - 1; i >= 0; i--){ - var cur = $(this.options.connectWith[i]); - for (var j = cur.length - 1; j >= 0; j--){ - var inst = $.data(cur[j], 'sortable'); - if(inst && inst != this && !inst.options.disabled) { - queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]); - this.containers.push(inst); - } - }; - }; - } - - for (var i = queries.length - 1; i >= 0; i--) { - var targetData = queries[i][1]; - var _queries = queries[i][0]; - - for (var j=0, queriesLength = _queries.length; j < queriesLength; j++) { - var item = $(_queries[j]); - - item.data('sortable-item', targetData); // Data for target checking (mouse manager) - - items.push({ - item: item, - instance: targetData, - width: 0, height: 0, - left: 0, top: 0 - }); - }; - }; - - }, - - refreshPositions: function(fast) { - - //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change - if(this.offsetParent && this.helper) { - this.offset.parent = this._getParentOffset(); - } - - for (var i = this.items.length - 1; i >= 0; i--){ - var item = this.items[i]; - - //We ignore calculating positions of all connected containers when we're not over them - if(item.instance != this.currentContainer && this.currentContainer && item.item[0] != this.currentItem[0]) - continue; - - var t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item; - - if (!fast) { - if (this.options.accurateIntersection) { - item.width = t.outerWidth(); - item.height = t.outerHeight(); - } - else { - item.width = t[0].offsetWidth; - item.height = t[0].offsetHeight; - } - } - - var p = t.offset(); - item.left = p.left; - item.top = p.top; - }; - - if(this.options.custom && this.options.custom.refreshContainers) { - this.options.custom.refreshContainers.call(this); - } else { - for (var i = this.containers.length - 1; i >= 0; i--){ - var p = this.containers[i].element.offset(); - this.containers[i].containerCache.left = p.left; - this.containers[i].containerCache.top = p.top; - this.containers[i].containerCache.width = this.containers[i].element.outerWidth(); - this.containers[i].containerCache.height = this.containers[i].element.outerHeight(); - }; - } - - }, - - _createPlaceholder: function(that) { - - var self = that || this, o = self.options; - - if(!o.placeholder || o.placeholder.constructor == String) { - var className = o.placeholder; - o.placeholder = { - element: function() { - - var el = $(document.createElement(self.currentItem[0].nodeName)) - .addClass(className || self.currentItem[0].className+" "+self.options.cssNamespace+"-sortable-placeholder") - .removeClass(self.options.cssNamespace+'-sortable-helper')[0]; - - if(!className) - el.style.visibility = "hidden"; - - return el; - }, - update: function(container, p) { - - // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that - // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified - if(className && !o.forcePlaceholderSize) return; - - //If the element doesn't have a actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item - if(!p.height()) { p.height(self.currentItem.innerHeight() - parseInt(self.currentItem.css('paddingTop')||0, 10) - parseInt(self.currentItem.css('paddingBottom')||0, 10)); }; - if(!p.width()) { p.width(self.currentItem.innerWidth() - parseInt(self.currentItem.css('paddingLeft')||0, 10) - parseInt(self.currentItem.css('paddingRight')||0, 10)); }; - } - }; - } - - //Create the placeholder - self.placeholder = $(o.placeholder.element.call(self.element, self.currentItem)); - - //Append it after the actual current item - self.currentItem.after(self.placeholder); - - //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317) - o.placeholder.update(self, self.placeholder); - - }, - - _contactContainers: function(event) { - for (var i = this.containers.length - 1; i >= 0; i--){ - - if(this._intersectsWith(this.containers[i].containerCache)) { - if(!this.containers[i].containerCache.over) { - - if(this.currentContainer != this.containers[i]) { - - //When entering a new container, we will find the item with the least distance and append our item near it - var dist = 10000; var itemWithLeastDistance = null; var base = this.positionAbs[this.containers[i].floating ? 'left' : 'top']; - for (var j = this.items.length - 1; j >= 0; j--) { - if(!$.ui.contains(this.containers[i].element[0], this.items[j].item[0])) continue; - var cur = this.items[j][this.containers[i].floating ? 'left' : 'top']; - if(Math.abs(cur - base) < dist) { - dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j]; - } - } - - if(!itemWithLeastDistance && !this.options.dropOnEmpty) //Check if dropOnEmpty is enabled - continue; - - this.currentContainer = this.containers[i]; - itemWithLeastDistance ? this.options.sortIndicator.call(this, event, itemWithLeastDistance, null, true) : this.options.sortIndicator.call(this, event, null, this.containers[i].element, true); - this._trigger("change", event); //Call plugins and callbacks - this.containers[i]._trigger("change", event, this); //Call plugins and callbacks - - //Update the placeholder - this.options.placeholder.update(this.currentContainer, this.placeholder); - - } - - this.containers[i]._trigger("over", event, this); - this.containers[i].containerCache.over = 1; - } - } else { - if(this.containers[i].containerCache.over) { - this.containers[i]._trigger("out", event, this); - this.containers[i].containerCache.over = 0; - } - } - - }; - }, - - _createHelper: function(event) { - - var o = this.options; - var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper == 'clone' ? this.currentItem.clone() : this.currentItem); - - if(!helper.parents('body').length) //Add the helper to the DOM if that didn't happen already - $(o.appendTo != 'parent' ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]); - - if(helper[0] == this.currentItem[0]) - this._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css("position"), top: this.currentItem.css("top"), left: this.currentItem.css("left") }; - - if(helper[0].style.width == '' || o.forceHelperSize) helper.width(this.currentItem.width()); - if(helper[0].style.height == '' || o.forceHelperSize) helper.height(this.currentItem.height()); - - return helper; - - }, - - _adjustOffsetFromHelper: function(obj) { - if(obj.left != undefined) this.offset.click.left = obj.left + this.margins.left; - if(obj.right != undefined) this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; - if(obj.top != undefined) this.offset.click.top = obj.top + this.margins.top; - if(obj.bottom != undefined) this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; - }, - - _getParentOffset: function() { - - - //Get the offsetParent and cache its position - this.offsetParent = this.helper.offsetParent(); - var po = this.offsetParent.offset(); - - // This is a special case where we need to modify a offset calculated on start, since the following happened: - // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent - // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that - // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag - if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) { - po.left += this.scrollParent.scrollLeft(); - po.top += this.scrollParent.scrollTop(); - } - - if((this.offsetParent[0] == document.body && $.browser.mozilla) //Ugly FF3 fix - || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.browser.msie)) //Ugly IE fix - po = { top: 0, left: 0 }; - - return { - top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), - left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) - }; - - }, - - _getRelativeOffset: function() { - - if(this.cssPosition == "relative") { - var p = this.currentItem.position(); - return { - top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), - left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() - }; - } else { - return { top: 0, left: 0 }; - } - - }, - - _cacheMargins: function() { - this.margins = { - left: (parseInt(this.currentItem.css("marginLeft"),10) || 0), - top: (parseInt(this.currentItem.css("marginTop"),10) || 0) - }; - }, - - _cacheHelperProportions: function() { - this.helperProportions = { - width: this.helper.outerWidth(), - height: this.helper.outerHeight() - }; - }, - - _setContainment: function() { - - var o = this.options; - if(o.containment == 'parent') o.containment = this.helper[0].parentNode; - if(o.containment == 'document' || o.containment == 'window') this.containment = [ - 0 - this.offset.relative.left - this.offset.parent.left, - 0 - this.offset.relative.top - this.offset.parent.top, - $(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left, - ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top - ]; - - if(!(/^(document|window|parent)$/).test(o.containment)) { - var ce = $(o.containment)[0]; - var co = $(o.containment).offset(); - var over = ($(ce).css("overflow") != 'hidden'); - - this.containment = [ - co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) - this.margins.left, - co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) - this.margins.top, - co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - this.helperProportions.width - this.margins.left, - co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - this.helperProportions.height - this.margins.top - ]; - } - - }, - - _convertPositionTo: function(d, pos) { - - if(!pos) pos = this.position; - var mod = d == "absolute" ? 1 : -1; - var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); - - return { - top: ( - pos.top // The absolute mouse position - + this.offset.relative.top * mod // Only for relative positioned nodes: Relative offset from element to offset parent - + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border) - - ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod - ), - left: ( - pos.left // The absolute mouse position - + this.offset.relative.left * mod // Only for relative positioned nodes: Relative offset from element to offset parent - + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border) - - ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod - ) - }; - - }, - - _generatePosition: function(event) { - - var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); - - // This is another very weird special case that only happens for relative elements: - // 1. If the css position is relative - // 2. and the scroll parent is the document or similar to the offset parent - // we have to refresh the relative offset during the scroll so there are no jumps - if(this.cssPosition == 'relative' && !(this.scrollParent[0] != document && this.scrollParent[0] != this.offsetParent[0])) { - this.offset.relative = this._getRelativeOffset(); - } - - var pageX = event.pageX; - var pageY = event.pageY; - - /* - * - Position constraining - - * Constrain the position to a mix of grid, containment. - */ - - if(this.originalPosition) { //If we are not dragging yet, we won't check for options - - if(this.containment) { - if(event.pageX - this.offset.click.left < this.containment[0]) pageX = this.containment[0] + this.offset.click.left; - if(event.pageY - this.offset.click.top < this.containment[1]) pageY = this.containment[1] + this.offset.click.top; - if(event.pageX - this.offset.click.left > this.containment[2]) pageX = this.containment[2] + this.offset.click.left; - if(event.pageY - this.offset.click.top > this.containment[3]) pageY = this.containment[3] + this.offset.click.top; - } - - if(o.grid) { - var top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1]; - pageY = this.containment ? (!(top - this.offset.click.top < this.containment[1] || top - this.offset.click.top > this.containment[3]) ? top : (!(top - this.offset.click.top < this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; - - var left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0]; - pageX = this.containment ? (!(left - this.offset.click.left < this.containment[0] || left - this.offset.click.left > this.containment[2]) ? left : (!(left - this.offset.click.left < this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; - } - - } - - return { - top: ( - pageY // The absolute mouse position - - this.offset.click.top // Click offset (relative to the element) - - this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent - - this.offset.parent.top // The offsetParent's offset without borders (offset + border) - + ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) - ), - left: ( - pageX // The absolute mouse position - - this.offset.click.left // Click offset (relative to the element) - - this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent - - this.offset.parent.left // The offsetParent's offset without borders (offset + border) - + ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) - ) - }; - - }, - - _rearrange: function(event, i, a, hardRefresh) { - - a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction == 'down' ? i.item[0] : i.item[0].nextSibling)); - - //Various things done here to improve the performance: - // 1. we create a setTimeout, that calls refreshPositions - // 2. on the instance, we have a counter variable, that get's higher after every append - // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same - // 4. this lets only the last addition to the timeout stack through - this.counter = this.counter ? ++this.counter : 1; - var self = this, counter = this.counter; - - window.setTimeout(function() { - if(counter == self.counter) self.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove - },0); - - }, - - _clear: function(event, noPropagation) { - - this.reverting = false; - - //We first have to update the dom position of the actual currentItem - if(!this._noFinalSort) this.placeholder.before(this.currentItem); - this._noFinalSort = null; - - if(this.helper[0] == this.currentItem[0]) { - for(var i in this._storedCSS) { - if(this._storedCSS[i] == 'auto' || this._storedCSS[i] == 'static') this._storedCSS[i] = ''; - } - this.currentItem.css(this._storedCSS).removeClass(this.options.cssNamespace+"-sortable-helper"); - } else { - this.currentItem.show(); - } - - if(this.fromOutside) this._trigger("receive", event, this, noPropagation); - if(this.fromOutside || this.domPosition.prev != this.currentItem.prev().not("."+this.options.cssNamespace+"-sortable-helper")[0] || this.domPosition.parent != this.currentItem.parent()[0]) this._trigger("update", event, null, noPropagation); //Trigger update callback if the DOM position has changed - if(!$.ui.contains(this.element[0], this.currentItem[0])) { //Node was moved out of the current element - this._trigger("remove", event, null, noPropagation); - for (var i = this.containers.length - 1; i >= 0; i--){ - if($.ui.contains(this.containers[i].element[0], this.currentItem[0])) { - this.containers[i]._trigger("receive", event, this, noPropagation); - this.containers[i]._trigger("update", event, this, noPropagation); - } - }; - }; - - //Post events to containers - for (var i = this.containers.length - 1; i >= 0; i--){ - this.containers[i]._trigger("deactivate", event, this, noPropagation); - if(this.containers[i].containerCache.over) { - this.containers[i]._trigger("out", event, this); - this.containers[i].containerCache.over = 0; - } - } - - this.dragging = false; - if(this.cancelHelperRemoval) { - this._trigger("beforeStop", event, null, noPropagation); - this._trigger("stop", event, null, noPropagation); - return false; - } - - this._trigger("beforeStop", event, null, noPropagation); - - //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! - this.placeholder[0].parentNode.removeChild(this.placeholder[0]); - - if(this.helper[0] != this.currentItem[0]) this.helper.remove(); this.helper = null; - this._trigger("stop", event, null, noPropagation); - - this.fromOutside = false; - return true; - - }, - - _trigger: function(type, event, inst, noPropagation) { - $.ui.plugin.call(this, type, [event, this._uiHash(inst)]); - if(!noPropagation) { - if ($.widget.prototype._trigger.call(this, type, event, this._uiHash(inst)) === false) { - this.cancel(); - } - } - }, - - plugins: {}, - - _uiHash: function(inst) { - var self = inst || this; - return { - helper: self.helper, - placeholder: self.placeholder || $([]), - position: self.position, - absolutePosition: self.positionAbs, - item: self.currentItem, - sender: inst ? inst.element : null - }; - } - -})); - -$.extend($.ui.sortable, { - getter: "serialize toArray", - version: "1.6rc5", - defaults: { - accurateIntersection: true, - appendTo: "parent", - cancel: ":input,option", - cssNamespace: 'ui', - delay: 0, - distance: 1, - dropOnEmpty: true, - forcePlaceholderSize: false, - forceHelperSize: false, - helper: "original", - items: '> *', - scope: "default", - scroll: true, - scrollSensitivity: 20, - scrollSpeed: 20, - sortIndicator: $.ui.sortable.prototype._rearrange, - tolerance: "default", - zIndex: 1000 - } -}); - -/* - * Sortable Extensions - */ - -$.ui.plugin.add("sortable", "cursor", { - start: function(event, ui) { - var t = $('body'), i = $(this).data('sortable'); - if (t.css("cursor")) i.options._cursor = t.css("cursor"); - t.css("cursor", i.options.cursor); - }, - beforeStop: function(event, ui) { - var i = $(this).data('sortable'); - if (i.options._cursor) $('body').css("cursor", i.options._cursor); - } -}); - -$.ui.plugin.add("sortable", "opacity", { - start: function(event, ui) { - var t = ui.helper, i = $(this).data('sortable'); - if(t.css("opacity")) i.options._opacity = t.css("opacity"); - t.css('opacity', i.options.opacity); - }, - beforeStop: function(event, ui) { - var i = $(this).data('sortable'); - if(i.options._opacity) $(ui.helper).css('opacity', i.options._opacity); - } -}); - -$.ui.plugin.add("sortable", "scroll", { - start: function(event, ui) { - var i = $(this).data("sortable"), o = i.options; - if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') i.overflowOffset = i.scrollParent.offset(); - }, - sort: function(event, ui) { - - var i = $(this).data("sortable"), o = i.options, scrolled = false; - - if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') { - - if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) - i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed; - else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity) - i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed; - - if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) - i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed; - else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity) - i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed; - - } else { - - if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) - scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); - else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) - scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); - - if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) - scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); - else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) - scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); - - } - - if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) - $.ui.ddmanager.prepareOffsets(i, event); - - } -}); - -$.ui.plugin.add("sortable", "zIndex", { - start: function(event, ui) { - var t = ui.helper, i = $(this).data('sortable'); - if(t.css("zIndex")) i.options._zIndex = t.css("zIndex"); - t.css('zIndex', i.options.zIndex); - }, - beforeStop: function(event, ui) { - var i = $(this).data('sortable'); - if(i.options._zIndex) $(ui.helper).css('zIndex', i.options._zIndex == 'auto' ? '' : i.options._zIndex); - } -}); - -})(jQuery); -/* - * jQuery UI Accordion 1.6rc5 - * - * Copyright (c) 2009 AUTHORS.txt (http://ui.jquery.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Accordion - * - * Depends: - * ui.core.js - */ -(function($) { - -$.widget("ui.accordion", { - - _init: function() { - var options = this.options; - - if ( options.navigation ) { - var current = this.element.find("a").filter(options.navigationFilter); - if ( current.length ) { - if ( current.filter(options.header).length ) { - options.active = current; - } else { - options.active = current.parent().parent().prev(); - current.addClass("ui-accordion-current"); - } - } - } - - this.element.addClass("ui-accordion ui-widget ui-helper-reset"); - var groups = this.element.children().addClass("ui-accordion-group"); - var headers = options.headers = groups.find("> :first-child").addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all") - .bind("mouseenter.accordion", function(){ $(this).addClass('ui-state-hover'); }) - .bind("mouseleave.accordion", function(){ $(this).removeClass('ui-state-hover'); }); - // wrap content elements in div against animation issues - headers.next().wrap("
").addClass("ui-accordion-content").parent().addClass("ui-accordion-content-wrap ui-helper-reset ui-widget-content ui-corner-bottom"); - - var active = options.active = findActive(headers, options.active).toggleClass("ui-state-default").toggleClass("ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top"); - active.parent().addClass(options.selectedClass); - $("").addClass("ui-icon " + this.options.icons.header).prependTo(headers); - active.find(".ui-icon").toggleClass(this.options.icons.header).toggleClass(this.options.icons.headerSelected); - - // IE7-/Win - Extra vertical space in Lists fixed - if ($.browser.msie) { - this.element.find('a').css('zoom', '1'); - } - - this.resize(); - - this.element.attr('role','tablist'); - - var self=this; - options.headers - .attr('role','tab') - .bind('keydown', function(event) { return self._keydown(event); }) - .next() - .attr('role','tabpanel'); - - options.headers - .not(options.active || "") - .attr('aria-expanded','false') - .attr("tabIndex", "-1") - .next() - .hide(); - - // make sure at least one header is in the tab order - if (!options.active.length) { - options.headers.eq(0).attr('tabIndex','0'); - } else { - options.active - .attr('aria-expanded','true') - .attr("tabIndex", "0"); - } - - // only need links in taborder for Safari - if (!$.browser.safari) - options.headers.find('a').attr('tabIndex','-1'); - - if (options.event) { - this.element.bind((options.event) + ".accordion", clickHandler); - } - }, - - destroy: function() { - this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role").unbind(".accordion"); - $.removeData(this.element[0], "accordion"); - var groups = this.element.children().removeClass("ui-accordion-group "+this.options.selectedClass); - var headers = this.options.headers.unbind(".accordion").removeClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-corner-top") - .removeAttr("role").removeAttr("aria-expanded").removeAttr("tabindex"); - headers.find("a").removeAttr("tabindex"); - headers.children(".ui-icon").remove(); - headers.next().children().removeClass("ui-accordion-content").each(function(){ - $(this).parent().replaceWith(this); - }) - }, - - _keydown: function(event) { - if (this.options.disabled || event.altKey || event.ctrlKey) - return; - - var keyCode = $.ui.keyCode; - - var length = this.options.headers.length; - var currentIndex = this.options.headers.index(event.target); - var toFocus = false; - - switch(event.keyCode) { - case keyCode.RIGHT: - case keyCode.DOWN: - toFocus = this.options.headers[(currentIndex + 1) % length]; - break; - case keyCode.LEFT: - case keyCode.UP: - toFocus = this.options.headers[(currentIndex - 1 + length) % length]; - break; - case keyCode.SPACE: - case keyCode.ENTER: - return clickHandler.call(this.element[0], { target: event.target }); - } - - if (toFocus) { - $(event.target).attr('tabIndex','-1'); - $(toFocus).attr('tabIndex','0'); - toFocus.focus(); - return false; - } - - return true; - }, - - resize: function() { - var options = this.options, - maxHeight; - if ( options.fillSpace ) { - maxHeight = this.element.parent().height(); - options.headers.each(function() { - maxHeight -= $(this).outerHeight(); - }); - var maxPadding = 0; - options.headers.next().each(function() { - maxPadding = Math.max(maxPadding, $(this).innerHeight() - $(this).height()); - }).height(maxHeight - maxPadding) - .css('overflow', 'auto'); - } else if ( options.autoHeight ) { - maxHeight = 0; - options.headers.next().each(function() { - maxHeight = Math.max(maxHeight, $(this).outerHeight()); - }).height(maxHeight); - } - }, - - activate: function(index) { - // call clickHandler with custom event - clickHandler.call(this.element[0], { - target: findActive( this.options.headers, index )[0] - }); - } - -}); - -function scopeCallback(callback, scope) { - return function() { - return callback.apply(scope, arguments); - }; -}; - -function completed(cancel) { - // if removed while animated data can be empty - if (!$.data(this, "accordion")) { - return; - } - - var instance = $.data(this, "accordion"); - var options = instance.options; - options.running = cancel ? 0 : --options.running; - if ( options.running ) { - return; - } - if ( options.clearStyle ) { - options.toShow.add(options.toHide).css({ - height: "", - overflow: "" - }); - } - instance._trigger('change', null, options.data); -} - -function toggle(toShow, toHide, data, clickedActive, down) { - var options = $.data(this, "accordion").options; - options.toShow = toShow; - options.toHide = toHide; - options.data = data; - var complete = scopeCallback(completed, this); - - $.data(this, "accordion")._trigger("changestart", null, options.data); - - // count elements to animate - options.running = toHide.size() === 0 ? toShow.size() : toHide.size(); - - if ( options.animated ) { - var animOptions = {}; - - if ( !options.alwaysOpen && clickedActive ) { - animOptions = { - toShow: $([]), - toHide: toHide, - complete: complete, - down: down, - autoHeight: options.autoHeight || options.fillSpace - }; - } else { - animOptions = { - toShow: toShow, - toHide: toHide, - complete: complete, - down: down, - autoHeight: options.autoHeight || options.fillSpace - }; - } - - if (!options.proxied) { - options.proxied = options.animated; - } - - if (!options.proxiedDuration) { - options.proxiedDuration = options.duration; - } - - options.animated = $.isFunction(options.proxied) ? - options.proxied(animOptions) : options.proxied; - - options.duration = $.isFunction(options.proxiedDuration) ? - options.proxiedDuration(animOptions) : options.proxiedDuration; - - var animations = $.ui.accordion.animations, - duration = options.duration, - easing = options.animated; - - if (!animations[easing]) { - animations[easing] = function(options) { - this.slide(options, { - easing: easing, - duration: duration || 700 - }); - }; - } - - animations[easing](animOptions); - - } else { - if ( !options.alwaysOpen && clickedActive ) { - toShow.toggle(); - } else { - toHide.hide(); - toShow.show(); - } - complete(true); - } - toHide.prev().attr('aria-expanded','false').attr("tabIndex", "-1"); - toShow.prev().attr('aria-expanded','true').attr("tabIndex", "0").focus();; -} - -function clickHandler(event) { - var options = $.data(this, "accordion").options; - if (options.disabled) { - return false; - } - // called only when using activate(false) to close all parts programmatically - if ( !event.target && !options.alwaysOpen ) { - options.active.parent().toggleClass(options.selectedClass); - var toHide = options.active.next(), - data = { - options: options, - newHeader: $([]), - oldHeader: options.active, - newContent: $([]), - oldContent: toHide - }, - toShow = (options.active = $([])); - toggle.call(this, toShow, toHide, data ); - return false; - } - // get the click target - var clicked = $(event.target); - - // due to the event delegation model, we have to check if one - // of the parent elements is our actual header, and find that - // otherwise stick with the initial target - clicked = $( clicked.parents(options.header)[0] || clicked ); - - var clickedActive = clicked[0] == options.active[0]; - - // if animations are still active, or the active header is the target, ignore click - if (options.running || (options.alwaysOpen && clickedActive)) { - return false; - } - if (!clicked.is(options.header)) { - return; - } - - // switch classes - options.active.parent().toggleClass(options.selectedClass); - options.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all") - .find(".ui-icon").removeClass(options.icons.headerSelected).addClass(options.icons.header); - if ( !clickedActive ) { - clicked.parent().addClass(options.selectedClass); - clicked.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top") - .find(".ui-icon").removeClass(options.icons.header).addClass(options.icons.headerSelected); - } - - // find elements to show and hide - var toShow = clicked.next(), - toHide = options.active.next(), - data = { - options: options, - newHeader: clickedActive && !options.alwaysOpen ? $([]) : clicked, - oldHeader: options.active, - newContent: clickedActive && !options.alwaysOpen ? $([]) : toShow, - oldContent: toHide - }, - down = options.headers.index( options.active[0] ) > options.headers.index( clicked[0] ); - - options.active = clickedActive ? $([]) : clicked; - toggle.call(this, toShow, toHide, data, clickedActive, down ); - - return false; -}; - -function findActive(headers, selector) { - return selector - ? typeof selector == "number" - ? headers.filter(":eq(" + selector + ")") - : headers.not(headers.not(selector)) - : selector === false - ? $([]) - : headers.filter(":eq(0)"); -} - -$.extend($.ui.accordion, { - version: "1.6rc5", - defaults: { - autoHeight: true, - alwaysOpen: true, - animated: 'slide', - event: "click", - header: "a", - icons: { - header: "ui-icon-triangle-1-e", - headerSelected: "ui-icon-triangle-1-s" - }, - navigationFilter: function() { - return this.href.toLowerCase() == location.href.toLowerCase(); - }, - running: 0, - selectedClass: "ui-accordion-selected" - }, - animations: { - slide: function(options, additions) { - options = $.extend({ - easing: "swing", - duration: 300 - }, options, additions); - if ( !options.toHide.size() ) { - options.toShow.animate({height: "show"}, options); - return; - } - var hideHeight = options.toHide.height(), - showHeight = options.toShow.height(), - difference = showHeight / hideHeight, - overflow = options.toShow.css('overflow'); - options.toShow.css({ height: 0, overflow: 'hidden' }).show(); - options.toHide.filter(":hidden").each(options.complete).end().filter(":visible").animate({height:"hide"},{ - step: function(now) { - var current = (hideHeight - now) * difference; - if ($.browser.msie || $.browser.opera) { - current = Math.ceil(current); - } - options.toShow.height( current ); - }, - duration: options.duration, - easing: options.easing, - complete: function() { - if ( !options.autoHeight ) { - options.toShow.css("height", "auto"); - } - options.toShow.css({overflow: overflow}); - options.complete(); - } - }); - }, - bounceslide: function(options) { - this.slide(options, { - easing: options.down ? "easeOutBounce" : "swing", - duration: options.down ? 1000 : 200 - }); - }, - easeslide: function(options) { - this.slide(options, { - easing: "easeinout", - duration: 700 - }); - } - } -}); - -})(jQuery); -/* - * jQuery UI Dialog 1.6rc5 - * - * Copyright (c) 2009 AUTHORS.txt (http://ui.jquery.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Dialog - * - * Depends: - * ui.core.js - * ui.draggable.js - * ui.resizable.js - */ -(function($) { - -var setDataSwitch = { - dragStart: "start.draggable", - drag: "drag.draggable", - dragStop: "stop.draggable", - maxHeight: "maxHeight.resizable", - minHeight: "minHeight.resizable", - maxWidth: "maxWidth.resizable", - minWidth: "minWidth.resizable", - resizeStart: "start.resizable", - resize: "drag.resizable", - resizeStop: "stop.resizable" -}; - -$.widget("ui.dialog", { - - _init: function() { - this.originalTitle = this.element.attr('title'); - this.options.title = this.options.title || this.originalTitle; - - var self = this, - options = this.options, - - title = options.title || ' ', - titleId = $.ui.dialog.getTitleId(this.element), - - uiDialog = (this.uiDialog = $('
')) - .appendTo(document.body) - .hide() - .addClass( - 'ui-dialog ' + - 'ui-widget ' + - 'ui-widget-content ' + - 'ui-corner-all ' + - options.dialogClass - ) - .css({ - position: 'absolute', - overflow: 'hidden', - zIndex: options.zIndex - }) - // setting tabIndex makes the div focusable - // setting outline to 0 prevents a border on focus in Mozilla - .attr('tabIndex', -1).css('outline', 0).keydown(function(ev) { - (options.closeOnEscape && ev.keyCode - && ev.keyCode == $.ui.keyCode.ESCAPE && self.close()); - }) - .attr({ - role: 'dialog', - 'aria-labelledby': titleId - }) - .mousedown(function() { - self.moveToTop(); - }), - - uiDialogContent = this.element - .show() - .removeAttr('title') - .addClass( - 'ui-dialog-content ' + - 'ui-widget-content') - .appendTo(uiDialog), - - uiDialogTitlebar = (this.uiDialogTitlebar = $('
')) - .addClass( - 'ui-dialog-titlebar ' + - 'ui-widget-header ' + - 'ui-corner-all ' + - 'ui-helper-clearfix' - ) - .prependTo(uiDialog), - - uiDialogTitlebarClose = $('') - .addClass( - 'ui-dialog-titlebar-close ' + - 'ui-corner-all' - ) - .attr('role', 'button') - .hover( - function() { - uiDialogTitlebarClose.addClass('ui-state-hover'); - }, - function() { - uiDialogTitlebarClose.removeClass('ui-state-hover'); - } - ) - .focus(function() { - uiDialogTitlebarClose.addClass('ui-state-focus'); - }) - .blur(function() { - uiDialogTitlebarClose.removeClass('ui-state-focus'); - }) - .mousedown(function(ev) { - ev.stopPropagation(); - }) - .click(function() { - self.close(); - return false; - }) - .appendTo(uiDialogTitlebar), - - uiDialogTitlebarCloseText = (this.uiDialogTitlebarCloseText = $('')) - .addClass( - 'ui-icon ' + - 'ui-icon-closethick' - ) - .text(options.closeText) - .appendTo(uiDialogTitlebarClose), - - uiDialogTitle = $('') - .addClass('ui-dialog-title') - .attr('id', titleId) - .html(title) - .prependTo(uiDialogTitlebar), - - uiDialogButtonPane = (this.uiDialogButtonPane = $('
')) - .addClass( - 'ui-dialog-buttonpane ' + - 'ui-widget-content ' + - 'ui-helper-clearfix' - ) - .appendTo(uiDialog); - - uiDialogTitlebar.find("*").add(uiDialogTitlebar).disableSelection(); - - (options.draggable && $.fn.draggable && this._makeDraggable()); - (options.resizable && $.fn.resizable && this._makeResizable()); - - this._createButtons(options.buttons); - this._isOpen = false; - - (options.bgiframe && $.fn.bgiframe && uiDialog.bgiframe()); - (options.autoOpen && this.open()); - }, - - destroy: function() { - (this.overlay && this.overlay.destroy()); - this.uiDialog.hide(); - this.element - .unbind('.dialog') - .removeData('dialog') - .removeClass('ui-dialog-content ui-widget-content') - .hide().appendTo('body'); - this.uiDialog.remove(); - - (this.originalTitle && this.element.attr('title', this.originalTitle)); - }, - - close: function() { - if (false === this._trigger('beforeclose')) { - return; - } - - (this.overlay && this.overlay.destroy()); - this.uiDialog - .hide(this.options.hide) - .unbind('keypress.ui-dialog'); - - this._trigger('close'); - $.ui.dialog.overlay.resize(); - - this._isOpen = false; - }, - - isOpen: function() { - return this._isOpen; - }, - - // the force parameter allows us to move modal dialogs to their correct - // position on open - moveToTop: function(force) { - - if ((this.options.modal && !force) - || (!this.options.stack && !this.options.modal)) { - return this._trigger('focus'); - } - - var maxZ = this.options.zIndex, options = this.options; - $('.ui-dialog:visible').each(function() { - maxZ = Math.max(maxZ, parseInt($(this).css('z-index'), 10) || options.zIndex); - }); - (this.overlay && this.overlay.$el.css('z-index', ++maxZ)); - - //Save and then restore scroll since Opera 9.5+ resets when parent z-Index is changed. - // http://ui.jquery.com/bugs/ticket/3193 - var saveScroll = { scrollTop: this.element.attr('scrollTop'), scrollLeft: this.element.attr('scrollLeft') }; - this.uiDialog.css('z-index', ++maxZ); - this.element.attr(saveScroll); - this._trigger('focus'); - }, - - open: function() { - if (this._isOpen) { return; } - - this.overlay = this.options.modal ? new $.ui.dialog.overlay(this) : null; - (this.uiDialog.next().length && this.uiDialog.appendTo('body')); - this._size(); - this._position(this.options.position); - this.uiDialog.show(this.options.show); - this.moveToTop(true); - - // prevent tabbing out of modal dialogs - (this.options.modal && this.uiDialog.bind('keypress.ui-dialog', function(event) { - if (event.keyCode != $.ui.keyCode.TAB) { - return; - } - - var tabbables = $(':tabbable', this), - first = tabbables.filter(':first')[0], - last = tabbables.filter(':last')[0]; - - if (event.target == last && !event.shiftKey) { - setTimeout(function() { - first.focus(); - }, 1); - } else if (event.target == first && event.shiftKey) { - setTimeout(function() { - last.focus(); - }, 1); - } - })); - - this.uiDialog.find(':tabbable:first').focus(); - this._trigger('open'); - this._isOpen = true; - }, - - _createButtons: function(buttons) { - var self = this, - hasButtons = false, - uiDialogButtonPane = this.uiDialogButtonPane; - - // remove any existing buttons - uiDialogButtonPane.empty().hide(); - - $.each(buttons, function() { return !(hasButtons = true); }); - if (hasButtons) { - uiDialogButtonPane.show(); - $.each(buttons, function(name, fn) { - $('') - .addClass( - 'ui-state-default ' + - 'ui-corner-all' - ) - .text(name) - .click(function() { fn.apply(self.element[0], arguments); }) - .hover( - function() { - $(this).addClass('ui-state-hover'); - }, - function() { - $(this).removeClass('ui-state-hover'); - } - ) - .focus(function() { - $(this).addClass('ui-state-focus'); - }) - .blur(function() { - $(this).removeClass('ui-state-focus'); - }) - .appendTo(uiDialogButtonPane); - }); - } - }, - - _makeDraggable: function() { - var self = this, - options = this.options; - - this.uiDialog.draggable({ - cancel: '.ui-dialog-content', - helper: options.dragHelper, - handle: '.ui-dialog-titlebar', - containment: 'document', - start: function() { - (options.dragStart && options.dragStart.apply(self.element[0], arguments)); - }, - drag: function() { - (options.drag && options.drag.apply(self.element[0], arguments)); - }, - stop: function() { - (options.dragStop && options.dragStop.apply(self.element[0], arguments)); - $.ui.dialog.overlay.resize(); - } - }); - }, - - _makeResizable: function(handles) { - handles = (handles === undefined ? this.options.resizable : handles); - var self = this, - options = this.options, - resizeHandles = typeof handles == 'string' - ? handles - : 'n,e,s,w,se,sw,ne,nw'; - - this.uiDialog.resizable({ - cancel: '.ui-dialog-content', - alsoResize: this.element, - helper: options.resizeHelper, - maxWidth: options.maxWidth, - maxHeight: options.maxHeight, - minWidth: options.minWidth, - minHeight: options.minHeight, - start: function() { - (options.resizeStart && options.resizeStart.apply(self.element[0], arguments)); - }, - resize: function() { - (options.resize && options.resize.apply(self.element[0], arguments)); - }, - handles: resizeHandles, - stop: function() { - (options.resizeStop && options.resizeStop.apply(self.element[0], arguments)); - $.ui.dialog.overlay.resize(); - } - }) - .find('.ui-resizable-se').addClass('ui-icon ui-icon-grip-diagonal-se'); - }, - - _position: function(pos) { - var wnd = $(window), doc = $(document), - pTop = doc.scrollTop(), pLeft = doc.scrollLeft(), - minTop = pTop; - - if ($.inArray(pos, ['center','top','right','bottom','left']) >= 0) { - pos = [ - pos == 'right' || pos == 'left' ? pos : 'center', - pos == 'top' || pos == 'bottom' ? pos : 'middle' - ]; - } - if (pos.constructor != Array) { - pos = ['center', 'middle']; - } - if (pos[0].constructor == Number) { - pLeft += pos[0]; - } else { - switch (pos[0]) { - case 'left': - pLeft += 0; - break; - case 'right': - pLeft += wnd.width() - this.uiDialog.outerWidth(); - break; - default: - case 'center': - pLeft += (wnd.width() - this.uiDialog.outerWidth()) / 2; - } - } - if (pos[1].constructor == Number) { - pTop += pos[1]; - } else { - switch (pos[1]) { - case 'top': - pTop += 0; - break; - case 'bottom': - pTop += wnd.height() - this.uiDialog.outerHeight(); - break; - default: - case 'middle': - pTop += (wnd.height() - this.uiDialog.outerHeight()) / 2; - } - } - - // prevent the dialog from being too high (make sure the titlebar - // is accessible) - pTop = Math.max(pTop, minTop); - this.uiDialog.css({top: pTop, left: pLeft}); - }, - - _setData: function(key, value){ - (setDataSwitch[key] && this.uiDialog.data(setDataSwitch[key], value)); - switch (key) { - case "buttons": - this._createButtons(value); - break; - case "closeText": - this.uiDialogTitlebarCloseText.text(value); - break; - case "draggable": - (value - ? this._makeDraggable() - : this.uiDialog.draggable('destroy')); - break; - case "height": - this.uiDialog.height(value); - break; - case "position": - this._position(value); - break; - case "resizable": - var uiDialog = this.uiDialog, - isResizable = this.uiDialog.is(':data(resizable)'); - - // currently resizable, becoming non-resizable - (isResizable && !value && uiDialog.resizable('destroy')); - - // currently resizable, changing handles - (isResizable && typeof value == 'string' && - uiDialog.resizable('option', 'handles', value)); - - // currently non-resizable, becoming resizable - (isResizable || this._makeResizable(value)); - - break; - case "title": - $(".ui-dialog-title", this.uiDialogTitlebar).html(value || ' '); - break; - case "width": - this.uiDialog.width(value); - break; - } - - $.widget.prototype._setData.apply(this, arguments); - }, - - _size: function() { - /* If the user has resized the dialog, the .ui-dialog and .ui-dialog-content - * divs will both have width and height set, so we need to reset them - */ - var options = this.options; - - // reset content sizing - this.element.css({ - height: 0, - minHeight: 0, - width: 'auto' - }); - - // reset wrapper sizing - // determine the height of all the non-content elements - var nonContentHeight = this.uiDialog.css({ - height: 'auto', - width: options.width - }) - .height(); - - this.element - .css({ - minHeight: options.minHeight - nonContentHeight, - height: options.height == 'auto' - ? 'auto' - : options.height - nonContentHeight - }); - } -}); - -$.extend($.ui.dialog, { - version: "1.6rc5", - defaults: { - autoOpen: true, - bgiframe: false, - buttons: {}, - closeOnEscape: true, - closeText: 'close', - draggable: true, - height: 'auto', - minHeight: 150, - minWidth: 150, - modal: false, - overlay: {}, - position: 'center', - resizable: true, - stack: true, - width: 300, - zIndex: 1000 - }, - - getter: 'isOpen', - - uuid: 0, - - getTitleId: function($el) { - return 'ui-dialog-title-' + ($el.attr('id') || ++this.uuid); - }, - - overlay: function(dialog) { - this.$el = $.ui.dialog.overlay.create(dialog); - } -}); - -$.extend($.ui.dialog.overlay, { - instances: [], - events: $.map('focus,mousedown,mouseup,keydown,keypress,click'.split(','), - function(event) { return event + '.dialog-overlay'; }).join(' '), - create: function(dialog) { - if (this.instances.length === 0) { - // prevent use of anchors and inputs - // we use a setTimeout in case the overlay is created from an - // event that we're going to be cancelling (see #2804) - setTimeout(function() { - $('a, :input').bind($.ui.dialog.overlay.events, function() { - // allow use of the element if inside a dialog and - // - there are no modal dialogs - // - there are modal dialogs, but we are in front of the topmost modal - var allow = false; - var $dialog = $(this).parents('.ui-dialog'); - if ($dialog.length) { - var $overlays = $('.ui-dialog-overlay'); - if ($overlays.length) { - var maxZ = parseInt($overlays.css('z-index'), 10); - $overlays.each(function() { - maxZ = Math.max(maxZ, parseInt($(this).css('z-index'), 10)); - }); - allow = parseInt($dialog.css('z-index'), 10) > maxZ; - } else { - allow = true; - } - } - return allow; - }); - }, 1); - - // allow closing by pressing the escape key - $(document).bind('keydown.dialog-overlay', function(event) { - (dialog.options.closeOnEscape && event.keyCode - && event.keyCode == $.ui.keyCode.ESCAPE && dialog.close()); - }); - - // handle window resize - $(window).bind('resize.dialog-overlay', $.ui.dialog.overlay.resize); - } - - var $el = $('
').appendTo(document.body) - .addClass('ui-dialog-overlay').css($.extend({ - borderWidth: 0, margin: 0, padding: 0, - position: 'absolute', top: 0, left: 0, - width: this.width(), - height: this.height() - }, dialog.options.overlay)); - - (dialog.options.bgiframe && $.fn.bgiframe && $el.bgiframe()); - - this.instances.push($el); - return $el; - }, - - destroy: function($el) { - this.instances.splice($.inArray(this.instances, $el), 1); - - if (this.instances.length === 0) { - $('a, :input').add([document, window]).unbind('.dialog-overlay'); - } - - $el.remove(); - }, - - height: function() { - // handle IE 6 - if ($.browser.msie && $.browser.version < 7) { - var scrollHeight = Math.max( - document.documentElement.scrollHeight, - document.body.scrollHeight - ); - var offsetHeight = Math.max( - document.documentElement.offsetHeight, - document.body.offsetHeight - ); - - if (scrollHeight < offsetHeight) { - return $(window).height() + 'px'; - } else { - return scrollHeight + 'px'; - } - // handle "good" browsers - } else { - return $(document).height() + 'px'; - } - }, - - width: function() { - // handle IE 6 - if ($.browser.msie && $.browser.version < 7) { - var scrollWidth = Math.max( - document.documentElement.scrollWidth, - document.body.scrollWidth - ); - var offsetWidth = Math.max( - document.documentElement.offsetWidth, - document.body.offsetWidth - ); - - if (scrollWidth < offsetWidth) { - return $(window).width() + 'px'; - } else { - return scrollWidth + 'px'; - } - // handle "good" browsers - } else { - return $(document).width() + 'px'; - } - }, - - resize: function() { - /* If the dialog is draggable and the user drags it past the - * right edge of the window, the document becomes wider so we - * need to stretch the overlay. If the user then drags the - * dialog back to the left, the document will become narrower, - * so we need to shrink the overlay to the appropriate size. - * This is handled by shrinking the overlay before setting it - * to the full document size. - */ - var $overlays = $([]); - $.each($.ui.dialog.overlay.instances, function() { - $overlays = $overlays.add(this); - }); - - $overlays.css({ - width: 0, - height: 0 - }).css({ - width: $.ui.dialog.overlay.width(), - height: $.ui.dialog.overlay.height() - }); - } -}); - -$.extend($.ui.dialog.overlay.prototype, { - destroy: function() { - $.ui.dialog.overlay.destroy(this.$el); - } -}); - -})(jQuery); -/* - * jQuery UI Slider 1.6rc5 - * - * Copyright (c) 2009 AUTHORS.txt (http://ui.jquery.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Slider - * - * Depends: - * ui.core.js - */ - -(function($) { - -$.widget("ui.slider", $.extend({}, $.ui.mouse, { - - _init: function() { - - var self = this, o = this.options; - this._keySliding = false; - this._handleIndex = null; - this.orientation = o.orientation == 'auto' ? (this.element[0].offsetWidth/this.element[0].offsetHeight > 1 ? 'horizontal' : 'vertical') : o.orientation; - - this._mouseInit(); - - this.element - .addClass("ui-slider" - + " ui-slider-" + this.orientation - + " ui-widget" - + " ui-widget-content" - + " ui-corner-all"); - - this.range = $([]); - - if (o.range) { - - if (o.range === true) { - this.range = $('
'); - if (!o.values) o.values = [this._valueMin(), this._valueMin()]; - if (o.values.length && o.values.length != 2) { - o.values = [o.values[0], o.values[0]]; - } - } else { - this.range = $('
'); - } - - this.range - .appendTo(this.element) - .addClass("ui-slider-range" - + " ui-widget-header"); - - (o.range == "min") && (this.orientation == "horizontal") && this.range.css({ left : 0 }); - (o.range == "max") && (this.orientation == "horizontal") && this.range.css({ right : 0 }); - (o.range == "min") && (this.orientation == "vertical") && this.range.css({ bottom : 0 }); - (o.range == "max") && (this.orientation == "vertical") && this.range.css({ top : 0 }); - - } - - if ($(".ui-slider-handle", this.element).length == 0) - $('
') - .appendTo(this.element) - .addClass("ui-slider-handle"); - - if (o.values && o.values.length) { - while ($(".ui-slider-handle", this.element).length < o.values.length) - $('') - .appendTo(this.element) - .addClass("ui-slider-handle"); - } - - this.handles = $(".ui-slider-handle", this.element) - .addClass("ui-state-default" - + " ui-corner-all"); - - this.handle = this.handles.eq(0); - - this.handles.add(this.range).filter("a") - .click(function(event) { event.preventDefault(); }) - .hover(function() { $(this).addClass('ui-state-hover'); }, function() { $(this).removeClass('ui-state-hover'); }) - .focus(function() { self.handles.removeClass('ui-state-focus'); $(this).addClass('ui-state-focus'); }) - .blur(function() { $(this).removeClass('ui-state-focus'); }); - - this.handles.each(function(i) { - $(this).data("index.ui-slider-handle", i); - }); - - this.handles.keydown(function(event) { - - var index = $(this).data("index.ui-slider-handle"); - - if (self.options.disabled) - return; - - switch (event.keyCode) { - case $.ui.keyCode.HOME: - case $.ui.keyCode.END: - case $.ui.keyCode.UP: - case $.ui.keyCode.RIGHT: - case $.ui.keyCode.DOWN: - case $.ui.keyCode.LEFT: - if (!self._keySliding) { - self._keySliding = true; - $(this).addClass("ui-state-active"); - self._start(event); - } - break; - } - - var curVal, newVal, step = self._step(); - if (self.options.values && self.options.values.length) { - curVal = newVal = self.values(index); - } else { - curVal = newVal = self.value(); - } - - switch (event.keyCode) { - case $.ui.keyCode.HOME: - newVal = self._valueMin(); - break; - case $.ui.keyCode.END: - newVal = self._valueMax(); - break; - case $.ui.keyCode.UP: - case $.ui.keyCode.RIGHT: - newVal = curVal + step; - break; - case $.ui.keyCode.DOWN: - case $.ui.keyCode.LEFT: - newVal = curVal - step; - break; - } - - self._slide(event, index, newVal); - - }).keyup(function(event) { - - if (self._keySliding) { - self._stop(event); - self._change(event); - self._keySliding = false; - $(this).removeClass("ui-state-active"); - } - - }); - - this._refreshValue(); - - }, - - destroy: function() { - - this.handles.remove(); - - this.element - .removeClass("ui-slider" - + " ui-slider-horizontal" - + " ui-slider-vertical" - + " ui-slider-disabled" - + " ui-widget" - + " ui-widget-content" - + " ui-corner-all") - .removeData("slider") - .unbind(".slider"); - - this._mouseDestroy(); - - }, - - _mouseCapture: function(event) { - - var o = this.options; - - if (o.disabled) - return false; - - this._start(event); - - this.elementSize = { - width: this.element.outerWidth(), - height: this.element.outerHeight() - }; - this.elementOffset = this.element.offset(); - - var position = { x: event.pageX, y: event.pageY }; - var normValue = this._normValueFromMouse(position); - - var distance = this._valueMax(), closestHandle; - var self = this, index; - this.handles.each(function(i) { - var thisDistance = Math.abs(normValue - self.values(i)); - if (distance > thisDistance) { - distance = thisDistance; - closestHandle = $(this); - index = i; - } - }); - - self._handleIndex = index; - - closestHandle - .addClass("ui-state-active") - .focus(); - - this._slide(event, index, normValue); - - return true; - - }, - - _mouseStart: function(event) { - return true; - }, - - _mouseDrag: function(event) { - - var position = { x: event.pageX, y: event.pageY }; - var normValue = this._normValueFromMouse(position); - - this._slide(event, this._handleIndex, normValue); - - return false; - - }, - - _mouseStop: function(event) { - - this.handles.removeClass("ui-state-active"); - this._stop(event); - this._change(event); - this._handleIndex = null; - - return false; - - }, - - _normValueFromMouse: function(position) { - - var pixelTotal, pixelMouse; - if ('horizontal' == this.orientation) { - pixelTotal = this.elementSize.width; - pixelMouse = position.x - this.elementOffset.left; - } else { - pixelTotal = this.elementSize.height; - pixelMouse = position.y - this.elementOffset.top; - } - - var percentMouse = (pixelMouse / pixelTotal); - if (percentMouse > 1) percentMouse = 1; - if (percentMouse < 0) percentMouse = 0; - if ('vertical' == this.orientation) - percentMouse = 1 - percentMouse; - - var valueTotal = this._valueMax() - this._valueMin(), - valueMouse = percentMouse * valueTotal, - valueMouseModStep = valueMouse % this.options.step, - normValue = this._valueMin() + valueMouse - valueMouseModStep; - - if (valueMouseModStep > (this.options.step / 2)) - normValue += this.options.step; - - return normValue; - - }, - - _start: function(event) { - this._trigger("start", event, { - value: this.value() - }); - }, - - _slide: function(event, index, newVal) { - - if (this.options.values && this.options.values.length) { - - var handle = this.handles[index]; - var otherVal = this.values(index ? 0 : 1); - - if ((index == 0 && newVal >= otherVal) || (index == 1 && newVal <= otherVal)) - newVal = otherVal; - - if (newVal != this.values(index)) { - var newValues = this.values(); - newValues[index] = newVal; - // A slide can be canceled by returning false from the slide callback - var allowed = this._trigger("slide", event, { - handle: handle, - value: newVal, - values: newValues - }); - var otherVal = this.values(index ? 0 : 1); - if (allowed !== false) { - this.values(index, newVal); - } - } - - } else { - - if (newVal != this.value()) { - // A slide can be canceled by returning false from the slide callback - var allowed = this._trigger("slide", event, { - value: newVal - }); - if (allowed !== false) - this._setData('value', newVal); - } - - } - - }, - - _stop: function(event) { - this._trigger("stop", event, { - value: this.value() - }); - }, - - _change: function(event) { - this._trigger("change", event, { - value: this.value() - }); - }, - - value: function(newValue) { - - if (arguments.length) { - this._setData("value", newValue); - this._change(); - } - - return this._value(); - - }, - - values: function(index, newValue) { - - if (arguments.length > 1) { - this.options.values[index] = newValue; - this._refreshValue(); - this._change(); - } - - if (arguments.length) { - if (this.options.values && this.options.values.length) { - return this._values(index); - } else { - return this.value(); - } - } else { - return this._values(); - } - - }, - - _setData: function(key, value) { - - $.widget.prototype._setData.apply(this, arguments); - - switch (key) { - case 'orientation': - - this.orientation = this.options.orientation == 'auto' ? (this.element[0].offsetWidth/this.element[0].offsetHeight > 1 ? 'horizontal' : 'vertical') : this.options.orientation; - - this.element - .removeClass("ui-slider-horizontal ui-slider-vertical") - .addClass("ui-slider-" + this._orientation()); - this._refreshValue(); - break; - case 'value': - this._refreshValue(); - break; - } - - }, - - _step: function() { - var step = this.options.step; - return step; - }, - - _value: function() { - - var val = this.options.value; - if (val < this._valueMin()) val = this._valueMin(); - if (val > this._valueMax()) val = this._valueMax(); - - return val; - - }, - - _values: function(index) { - - if (arguments.length) { - var val = this.options.values[index]; - if (val < this._valueMin()) val = this._valueMin(); - if (val > this._valueMax()) val = this._valueMax(); - - return val; - } else { - return this.options.values; - } - - }, - - _valueMin: function() { - var valueMin = this.options.min; - return valueMin; - }, - - _valueMax: function() { - var valueMax = this.options.max; - return valueMax; - }, - - _refreshValue: function() { - - var oRange = this.options.range; - - if (this.options.values && this.options.values.length) { - var self = this, vp0, vp1; - this.handles.each(function(i, j) { - var valPercent = (self.values(i) - self._valueMin()) / (self._valueMax() - self._valueMin()) * 100; - $(this).css(self.orientation == 'horizontal' ? 'left' : 'bottom', valPercent + '%'); - if (self.options.range === true) { - if (self.orientation == 'horizontal') { - (i == 0) && self.range.css('left', valPercent + '%'); - (i == 1) && self.range.css('width', (valPercent - lastValPercent) + '%'); - } else { - (i == 0) && self.range.css('bottom', (valPercent) + '%'); - (i == 1) && self.range.css('height', (valPercent - lastValPercent) + '%'); - } - } - lastValPercent = valPercent; - }); - } else { - var valPercent = (this.value() - this._valueMin()) / (this._valueMax() - this._valueMin()) * 100; - this.handle.css(this.orientation == 'horizontal' ? 'left' : 'bottom', valPercent + '%'); - - (oRange == "min") && (this.orientation == "horizontal") && this.range.css({ left: 0, width: valPercent + '%' }); - (oRange == "max") && (this.orientation == "horizontal") && this.range.css({ left: valPercent + '%', width: (100 - valPercent) + '%' }); - (oRange == "min") && (this.orientation == "vertical") && this.range.css({ top: (100 - valPercent) + '%', height: valPercent + '%' }); - (oRange == "max") && (this.orientation == "vertical") && this.range.css({ bottom: valPercent + '%', height: (100 - valPercent) + '%' }); - } - - } - -})); - -$.extend($.ui.slider, { - getter: "value values", - version: "1.6rc5", - eventPrefix: "slide", - defaults: { - delay: 0, - distance: 0, - max: 100, - min: 0, - orientation: 'auto', - range: false, - step: 1, - value: 0, - values: null - } -}); - -})(jQuery); -/* - * jQuery UI Tabs 1.6rc5 - * - * Copyright (c) 2009 AUTHORS.txt (http://ui.jquery.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Tabs - * - * Depends: - * ui.core.js - */ -(function($) { - -$.widget("ui.tabs", { - - _init: function() { - // create tabs - this._tabify(true); - }, - - destroy: function() { - var o = this.options; - this.list.unbind('.tabs') - .removeClass(o.navClass).removeData('tabs'); - this.$tabs.each(function() { - var href = $.data(this, 'href.tabs'); - if (href) - this.href = href; - var $this = $(this).unbind('.tabs'); - $.each(['href', 'load', 'cache'], function(i, prefix) { - $this.removeData(prefix + '.tabs'); - }); - }); - this.$lis.unbind('.tabs').add(this.$panels).each(function() { - if ($.data(this, 'destroy.tabs')) - $(this).remove(); - else - $(this).removeClass([o.tabClass, o.selectedClass, o.deselectableClass, - o.disabledClass, o.panelClass, o.hideClass].join(' ')); - }); - if (o.cookie) - this._cookie(null, o.cookie); - }, - - _setData: function(key, value) { - if ((/^selected/).test(key)) - this.select(value); - else { - this.options[key] = value; - this._tabify(); - } - }, - - length: function() { - return this.$tabs.length; - }, - - _tabId: function(a) { - return a.title && a.title.replace(/\s/g, '_').replace(/[^A-Za-z0-9\-_:\.]/g, '') - || this.options.idPrefix + $.data(a); - }, - - _sanitizeSelector: function(hash) { - return hash.replace(/:/g, '\\:'); // we need this because an id may contain a ":" - }, - - _cookie: function() { - var cookie = this.cookie || (this.cookie = 'ui-tabs-' + $.data(this.list[0])); - return $.cookie.apply(null, [cookie].concat($.makeArray(arguments))); - }, - - _tabify: function(init) { - - this.list = this.element.is('div') ? this.element.children('ul:first, ol:first').eq(0) : this.element; - this.$lis = $('li:has(a[href])', this.list); - this.$tabs = this.$lis.map(function() { return $('a', this)[0]; }); - this.$panels = $([]); - - var self = this, o = this.options; - - this.$tabs.each(function(i, a) { - // inline tab - if (a.hash && a.hash.replace('#', '')) // Safari 2 reports '#' for an empty hash - self.$panels = self.$panels.add(self._sanitizeSelector(a.hash)); - // remote tab - else if ($(a).attr('href') != '#') { // prevent loading the page itself if href is just "#" - $.data(a, 'href.tabs', a.href); // required for restore on destroy - $.data(a, 'load.tabs', a.href); // mutable - var id = self._tabId(a); - a.href = '#' + id; - var $panel = $('#' + id); - if (!$panel.length) { - $panel = $(o.panelTemplate).attr('id', id).addClass(o.panelClass) - .insertAfter(self.$panels[i - 1] || self.list); - $panel.data('destroy.tabs', true); - } - self.$panels = self.$panels.add($panel); - } - // invalid tab href - else - o.disabled.push(i + 1); - }); - - // initialization from scratch - if (init) { - - // attach necessary classes for styling - if (this.element.is('div')) { - // TODO replace hardcoded class names - this.element.addClass('ui-tabs ui-widget ui-widget-content ui-corner-all'); - } - this.list.addClass(o.navClass); - this.$lis.addClass(o.tabClass); - this.$panels.addClass(o.panelClass); - - // Selected tab - // use "selected" option or try to retrieve: - // 1. from fragment identifier in url - // 2. from cookie - // 3. from selected class attribute on
  • - if (o.selected === undefined) { - if (location.hash) { - this.$tabs.each(function(i, a) { - if (a.hash == location.hash) { - o.selected = i; - return false; // break - } - }); - } - else if (o.cookie) { - var index = parseInt(self._cookie(), 10); - if (index && self.$tabs[index]) o.selected = index; - } - else if (self.$lis.filter('.' + o.selectedClass).length) - o.selected = self.$lis.index( self.$lis.filter('.' + o.selectedClass)[0] ); - } - o.selected = o.selected === null || o.selected !== undefined ? o.selected : 0; // first tab selected by default - - // Take disabling tabs via class attribute from HTML - // into account and update option properly. - // A selected tab cannot become disabled. - o.disabled = $.unique(o.disabled.concat( - $.map(this.$lis.filter('.' + o.disabledClass), - function(n, i) { return self.$lis.index(n); } ) - )).sort(); - if ($.inArray(o.selected, o.disabled) != -1) - o.disabled.splice($.inArray(o.selected, o.disabled), 1); - - // highlight selected tab - this.$panels.addClass(o.hideClass); - this.$lis.removeClass(o.selectedClass); - if (o.selected !== null && this.$tabs.length) { // check for length avoids error when initializing empty list - this.$panels.eq(o.selected).removeClass(o.hideClass); - var classes = [o.selectedClass]; - if (o.deselectable) classes.push(o.deselectableClass); - this.$lis.eq(o.selected).addClass(classes.join(' ')); - - // seems to be expected behavior that the show callback is fired - var onShow = function() { - self._trigger('show', null, - self.ui(self.$tabs[o.selected], self.$panels[o.selected])); - }; - - // load if remote tab - if ($.data(this.$tabs[o.selected], 'load.tabs')) - this.load(o.selected, onShow); - // just trigger show event - else onShow(); - } - - // states - var handleState = function(state, el) { - if (el.is(':not(.' + o.disabledClass + ')')) el.toggleClass('ui-state-' + state); - }; - this.$lis.bind('mouseover.tabs mouseout.tabs', function() { - handleState('hover', $(this)); - }); - this.$tabs.bind('focus.tabs blur.tabs', function() { - handleState('focus', $(this).parents('li:first')); - }); - - // clean up to avoid memory leaks in certain versions of IE 6 - $(window).bind('unload', function() { - self.$lis.add(self.$tabs).unbind('.tabs'); - self.$lis = self.$tabs = self.$panels = null; - }); - - } - // update selected after add/remove - else - o.selected = this.$lis.index( this.$lis.filter('.' + o.selectedClass)[0] ); - - // set or update cookie after init and add/remove respectively - if (o.cookie) this._cookie(o.selected, o.cookie); - - // disable tabs - for (var i = 0, li; li = this.$lis[i]; i++) - $(li)[$.inArray(i, o.disabled) != -1 && !$(li).hasClass(o.selectedClass) ? 'addClass' : 'removeClass'](o.disabledClass); - - // reset cache if switching from cached to not cached - if (o.cache === false) this.$tabs.removeData('cache.tabs'); - - // set up animations - var hideFx, showFx; - if (o.fx) { - if (o.fx.constructor == Array) { - hideFx = o.fx[0]; - showFx = o.fx[1]; - } - else hideFx = showFx = o.fx; - } - - // Reset certain styles left over from animation - // and prevent IE's ClearType bug... - function resetStyle($el, fx) { - $el.css({ display: '' }); - if ($.browser.msie && fx.opacity) $el[0].style.removeAttribute('filter'); - } - - // Show a tab... - var showTab = showFx ? - function(clicked, $show) { - $show.animate(showFx, showFx.duration || 'normal', function() { - $show.removeClass(o.hideClass); - resetStyle($show, showFx); - self._trigger('show', null, self.ui(clicked, $show[0])); - }); - } : - function(clicked, $show) { - $show.removeClass(o.hideClass); - self._trigger('show', null, self.ui(clicked, $show[0])); - }; - - // Hide a tab, $show is optional... - var hideTab = hideFx ? - function(clicked, $hide, $show) { - $hide.animate(hideFx, hideFx.duration || 'normal', function() { - $hide.addClass(o.hideClass); - resetStyle($hide, hideFx); - if ($show) showTab(clicked, $show, $hide); - }); - } : - function(clicked, $hide, $show) { - $hide.addClass(o.hideClass); - if ($show) showTab(clicked, $show); - }; - - // Switch a tab... - function switchTab(clicked, $li, $hide, $show) { - var classes = [o.selectedClass]; - if (o.deselectable) classes.push(o.deselectableClass); - // TODO replace hardcoded class names - $li.removeClass('ui-state-default').addClass(classes.join(' ')) - .siblings().removeClass(classes.join(' ')).addClass('ui-state-default'); - hideTab(clicked, $hide, $show); - } - - // attach tab event handler, unbind to avoid duplicates from former tabifying... - this.$tabs.unbind('.tabs').bind(o.event + '.tabs', function() { - - //var trueClick = event.clientX; // add to history only if true click occured, not a triggered click - var $li = $(this).parents('li:eq(0)'), - $hide = self.$panels.filter(':visible'), - $show = $(self._sanitizeSelector(this.hash)); - - // If tab is already selected and not deselectable or tab disabled or - // or is already loading or click callback returns false stop here. - // Check if click handler returns false last so that it is not executed - // for a disabled or loading tab! - // TODO replace hardcoded class names - if (($li.hasClass('ui-state-active') && !o.deselectable) - || $li.hasClass(o.disabledClass) - || $(this).hasClass(o.loadingClass) - || self._trigger('select', null, self.ui(this, $show[0])) === false - ) { - this.blur(); - return false; - } - - o.selected = self.$tabs.index(this); - - // if tab may be closed - // TODO replace hardcoded class names - if (o.deselectable) { - if ($li.hasClass('ui-state-active')) { - self.options.selected = null; - $li.removeClass([o.selectedClass, o.deselectableClass].join(' ')). - addClass('ui-state-default'); - self.$panels.stop(); - hideTab(this, $hide); - this.blur(); - return false; - } else if (!$hide.length) { - self.$panels.stop(); - var a = this; - self.load(self.$tabs.index(this), function() { - $li.addClass([o.selectedClass, o.deselectableClass].join(' ')) - .removeClass('ui-state-default'); - showTab(a, $show); - }); - this.blur(); - return false; - } - } - - if (o.cookie) self._cookie(o.selected, o.cookie); - - // stop possibly running animations - self.$panels.stop(); - - // show new tab - if ($show.length) { - var a = this; - self.load(self.$tabs.index(this), $hide.length ? - function() { - switchTab(a, $li, $hide, $show); - } : - function() { - $li.addClass(o.selectedClass).removeClass('ui-state-default'); - showTab(a, $show); - } - ); - } else - throw 'jQuery UI Tabs: Mismatching fragment identifier.'; - - // Prevent IE from keeping other link focussed when using the back button - // and remove dotted border from clicked link. This is controlled via CSS - // in modern browsers; blur() removes focus from address bar in Firefox - // which can become a usability and annoying problem with tabs('rotate'). - if ($.browser.msie) this.blur(); - - return false; - - }); - - // disable click if event is configured to something else - if (o.event != 'click') this.$tabs.bind('click.tabs', function(){return false;}); - - }, - - add: function(url, label, index) { - if (index == undefined) - index = this.$tabs.length; // append by default - - var o = this.options; - var $li = $(o.tabTemplate.replace(/#\{href\}/g, url).replace(/#\{label\}/g, label)); - $li.addClass(o.tabClass).data('destroy.tabs', true); - - var id = url.indexOf('#') == 0 ? url.replace('#', '') : this._tabId( $('a:first-child', $li)[0] ); - - // try to find an existing element before creating a new one - var $panel = $('#' + id); - if (!$panel.length) { - $panel = $(o.panelTemplate).attr('id', id) - .addClass(o.hideClass) - .data('destroy.tabs', true); - } - $panel.addClass(o.panelClass); - if (index >= this.$lis.length) { - $li.appendTo(this.list); - $panel.appendTo(this.list[0].parentNode); - } - else { - $li.insertBefore(this.$lis[index]); - $panel.insertBefore(this.$panels[index]); - } - - o.disabled = $.map(o.disabled, - function(n, i) { return n >= index ? ++n : n }); - - this._tabify(); - - if (this.$tabs.length == 1) { - $li.addClass(o.selectedClass); - $panel.removeClass(o.hideClass); - var href = $.data(this.$tabs[0], 'load.tabs'); - if (href) this.load(index, href); - } - - // callback - this._trigger('add', null, this.ui(this.$tabs[index], this.$panels[index])); - }, - - remove: function(index) { - var o = this.options, $li = this.$lis.eq(index).remove(), - $panel = this.$panels.eq(index).remove(); - - // If selected tab was removed focus tab to the right or - // in case the last tab was removed the tab to the left. - if ($li.hasClass(o.selectedClass) && this.$tabs.length > 1) - this.select(index + (index + 1 < this.$tabs.length ? 1 : -1)); - - o.disabled = $.map($.grep(o.disabled, function(n, i) { return n != index; }), - function(n, i) { return n >= index ? --n : n }); - - this._tabify(); - - // callback - this._trigger('remove', null, this.ui($li.find('a')[0], $panel[0])); - }, - - enable: function(index) { - var o = this.options; - if ($.inArray(index, o.disabled) == -1) - return; - - var $li = this.$lis.eq(index).removeClass(o.disabledClass); - if ($.browser.safari) { // fix disappearing tab (that used opacity indicating disabling) after enabling in Safari 2... - $li.css('display', 'inline-block'); - setTimeout(function() { - $li.css('display', 'block'); - }, 0); - } - - o.disabled = $.grep(o.disabled, function(n, i) { return n != index; }); - - // callback - this._trigger('enable', null, this.ui(this.$tabs[index], this.$panels[index])); - }, - - disable: function(index) { - var self = this, o = this.options; - if (index != o.selected) { // cannot disable already selected tab - this.$lis.eq(index).addClass(o.disabledClass); - - o.disabled.push(index); - o.disabled.sort(); - - // callback - this._trigger('disable', null, this.ui(this.$tabs[index], this.$panels[index])); - } - }, - - select: function(index) { - // TODO make null as argument work - if (typeof index == 'string') - index = this.$tabs.index( this.$tabs.filter('[href$=' + index + ']')[0] ); - this.$tabs.eq(index).trigger(this.options.event + '.tabs'); - }, - - load: function(index, callback) { // callback is for internal usage only - - var self = this, o = this.options, $a = this.$tabs.eq(index), a = $a[0], - bypassCache = callback == undefined || callback === false, url = $a.data('load.tabs'); - - callback = callback || function() {}; - - // no remote or from cache - just finish with callback - if (!url || !bypassCache && $.data(a, 'cache.tabs')) { - callback(); - return; - } - - // load remote from here on - - var inner = function(parent) { - var $parent = $(parent), $inner = $parent.find('*:last'); - return $inner.length && $inner.is(':not(img)') && $inner || $parent; - }; - var cleanup = function() { - self.$tabs.filter('.' + o.loadingClass).removeClass(o.loadingClass) - .each(function() { - if (o.spinner) - inner(this).parent().html(inner(this).data('label.tabs')); - }); - self.xhr = null; - }; - - if (o.spinner) { - var label = inner(a).html(); - inner(a).wrapInner('') - .find('em').data('label.tabs', label).html(o.spinner); - } - - var ajaxOptions = $.extend({}, o.ajaxOptions, { - url: url, - success: function(r, s) { - $(self._sanitizeSelector(a.hash)).html(r); - cleanup(); - - if (o.cache) - $.data(a, 'cache.tabs', true); // if loaded once do not load them again - - // callbacks - self._trigger('load', null, self.ui(self.$tabs[index], self.$panels[index])); - try { - o.ajaxOptions.success(r, s); - } - catch (er) {} - - // This callback is required because the switch has to take - // place after loading has completed. Call last in order to - // fire load before show callback... - callback(); - } - }); - if (this.xhr) { - // terminate pending requests from other tabs and restore tab label - this.xhr.abort(); - cleanup(); - } - $a.addClass(o.loadingClass); - self.xhr = $.ajax(ajaxOptions); - }, - - url: function(index, url) { - this.$tabs.eq(index).removeData('cache.tabs').data('load.tabs', url); - }, - - ui: function(tab, panel) { - return { - options: this.options, - tab: tab, - panel: panel, - index: this.$tabs.index(tab) - }; - } - -}); - -$.extend($.ui.tabs, { - version: '1.6rc5', - getter: 'length', - defaults: { - ajaxOptions: null, - cache: false, - cookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true } - deselectable: false, - deselectableClass: 'ui-tabs-deselectable', - disabled: [], - disabledClass: 'ui-state-disabled', - event: 'click', - fx: null, // e.g. { height: 'toggle', opacity: 'toggle', duration: 200 } - hideClass: 'ui-tabs-hide', - idPrefix: 'ui-tabs-', - loadingClass: 'ui-tabs-loading', - navClass: 'ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all', - tabClass: 'ui-state-default ui-corner-top', - panelClass: 'ui-tabs-panel ui-widget-content ui-corner-bottom', - panelTemplate: '
    ', - selectedClass: 'ui-tabs-selected ui-state-active', - spinner: 'Loading…', - tabTemplate: '
  • #{label}
  • ' - } -}); - -/* - * Tabs Extensions - */ - -/* - * Rotate - */ -$.extend($.ui.tabs.prototype, { - rotation: null, - rotate: function(ms, continuing) { - - continuing = continuing || false; - - var self = this, t = this.options.selected; - - function start() { - self.rotation = setInterval(function() { - t = ++t < self.$tabs.length ? t : 0; - self.select(t); - }, ms); - } - - function stop(event) { - if (!event || event.clientX) { // only in case of a true click - clearInterval(self.rotation); - } - } - - // start interval - if (ms) { - start(); - if (!continuing) - this.$tabs.bind(this.options.event + '.tabs', stop); - else - this.$tabs.bind(this.options.event + '.tabs', function() { - stop(); - t = self.options.selected; - start(); - }); - } - // stop interval - else { - stop(); - this.$tabs.unbind(this.options.event + '.tabs', stop); - } - } -}); - -})(jQuery); -/* - * jQuery UI Progressbar 1.6rc5 - * - * Copyright (c) 2009 AUTHORS.txt (http://ui.jquery.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI/Progressbar - * - * Depends: - * ui.core.js - */ -(function($) { - -$.widget("ui.progressbar", { - - _init: function() { - - var self = this, - options = this.options; - - this.element - .addClass("ui-progressbar" - + " ui-widget" - + " ui-widget-content" - + " ui-corner-all") - .attr({ - role: "progressbar", - "aria-valuemin": this._valueMin(), - "aria-valuemax": this._valueMax(), - "aria-valuenow": this._value() - }); - - this.valueDiv = $('
    ').appendTo(this.element); - - this._refreshValue(); - - }, - - destroy: function() { - - this.element - .removeClass("ui-progressbar" - + " ui-widget" - + " ui-widget-content" - + " ui-corner-all") - .removeAttr("role") - .removeAttr("aria-valuemin") - .removeAttr("aria-valuemax") - .removeAttr("aria-valuenow") - .removeData("progressbar") - .unbind(".progressbar"); - - this.valueDiv.remove(); - - $.widget.prototype.destroy.apply(this, arguments); - - }, - - value: function(newValue) { - arguments.length && this._setData("value", newValue); - - return this._value(); - }, - - _setData: function(key, value){ - switch (key) { - case 'value': - this.options.value = value; - this._refreshValue(); - this._trigger('change', null, {}); - break; - } - - $.widget.prototype._setData.apply(this, arguments); - }, - - _value: function() { - var val = this.options.value; - if (val < this._valueMin()) val = this._valueMin(); - if (val > this._valueMax()) val = this._valueMax(); - - return val; - }, - - _valueMin: function() { - var valueMin = 0; - - return valueMin; - }, - - _valueMax: function() { - var valueMax = 100; - - return valueMax; - }, - - _refreshValue: function() { - var value = this.value(); - this.valueDiv[value == this._valueMax() ? 'addClass' : 'removeClass']("ui-corner-right"); - this.valueDiv.width(value + '%'); - this.element.attr("aria-valuenow", value); - } - -}); - -$.extend($.ui.progressbar, { - version: "1.6rc5", - defaults: { - value: 0 - } -}); - -})(jQuery); diff --git a/src/main/webapp/webAdmin/resources/jquery.ajax_upload.js b/src/main/webapp/webAdmin/resources/jquery.ajax_upload.js deleted file mode 100644 index 7853d43..0000000 --- a/src/main/webapp/webAdmin/resources/jquery.ajax_upload.js +++ /dev/null @@ -1,297 +0,0 @@ -/** - * Ajax upload plugin for jQuery - * Project page - http://valums.com/ajax-upload/ - * Copyright (c) 2008 Andris Valums, http://valums.com - * Licensed under the MIT license (http://valums.com/mit-license/) - * Version 1.0 (24.01.2009) - */ - -(function($){ - // we need jQuery to run - if ( ! $) return; - - /** - * Function generates unique id - */ - var get_uid = function(){ - var uid = 0; - return function(){ - return uid++; - } - }(); - - /** - * button - jQuery element - * option - hash of options : - * action - URL which iframe will use to post data - * name - file input name - * data - extra data hash to post within the file - * onSubmit - callback to fire on file submit - * onComplete - callback to fire when iframe has finished loading - */ - window.Ajax_upload = function(button, options){ - // make sure it is jquery object - button = $(button); - - if (button.size() != 1 ){ - //You should pass only 1 element to ajax upload ot once - return; - } - - this.button = button; - - this.wrapper = null; - this.form = null; - this.input = null; - this.iframe = null; - - this.disabled = false; - this.submitting = false; - - this.settings = { - // Location of the server-side upload script - action: 'upload.php', - // File upload name - name: 'userfile', - // Additional data to send - data: {}, - // Callback to fire when user selects file - // You can return false to cancel upload - onSubmit: function(file, extension) {}, - // Fired when file upload is completed - onComplete: function(file, response) {} - }; - - // Merge the users options with our defaults - $.extend(this.settings, options); - - this.create_wrapper(); - this.create_input(); - - if (jQuery.browser.msie){ - //fixes bug, which occur when you use div with transparent background as upload button - this.make_parent_opaque(); - } - - this.create_iframe(); - } - - // assigning methods to our class - Ajax_upload.prototype = { - set_data : function(data){ - this.settings.data = data; - }, - disable : function(){ - this.disabled = true; - if ( ! this.submitting){ - this.input.attr('disabled', true); - this.button.removeClass('hover'); - } - }, - enable : function(){ - this.disabled = false; - this.input.attr('disabled', false); - }, - /** - * Creates wrapper for button and invisible file input - */ - create_wrapper : function(){ - // Shorten names - var button = this.button, wrapper; - - wrapper = this.wrapper = $('
    ') - .insertAfter(button) - .append(button); - - // wait a bit because of FF bug - // it can't properly calculate the outerHeight - setTimeout(function(){ - wrapper.css({ - position: 'relative' - ,display: 'block' - ,overflow: 'hidden' - - // we need dimensions because of ie bug that allows to move - // input outside even if overflow set to hidden - ,height: button.outerHeight(true) - ,width: button.outerWidth(true) - }); - }, 1); - - var self = this; - wrapper.mousemove(function(e){ - // Move the input with the mouse, so the user can't misclick it - if (!self.input) { - return; - } - - self.input.css({ - top: e.pageY - wrapper.offset().top - 5 + 'px' - ,left: e.pageX - wrapper.offset().left - 170 + 'px' - }); - }); - - - }, - /** - * Creates invisible file input above the button - */ - create_input : function(){ - var self = this; - - this.input = - $('') - .attr('name', this.settings.name) - .css({ - 'position' : 'absolute' - ,'margin': 0 - ,'padding': 0 - ,'width': '220px' - ,'height': '10px' - ,'opacity': 0 - , cursor: 'pointer' - }) - .change(function(){ - if ($(this).val() == ''){ - // there is no file - return; - } - - // we need to lock "disable" method - self.submitting = true; - - // Submit form when value is changed - self.submit(); - - if (self.disabled){ - self.disable(); - } - - // unlock "disable" method - self.submitting = false; - - // clear input to allow user to select same file - // Thanks to boston for fix - $(this).val(''); - }) - .appendTo(this.wrapper) - - // Emulate button hover effect - .hover( - function(){self.button.addClass('hover');} - ,function(){self.button.removeClass('hover');} - ); - - if (this.disabled){ - this.input.attr('disabled', true); - } - - }, - /** - * Creates iframe with unique name - */ - create_iframe : function(){ - // unique name - // We cannot use getTime, because it sometimes return - // same value in safari :( - var id = 'valums97hhu' + get_uid(); - - // create iframe, so we dont need to refresh page - this.iframe = - $('') - .css('display', 'none') - .appendTo('body'); - }, - /** - * Upload file without refreshing the page - */ - submit : function(){ - var self = this, settings = this.settings; - - // get filename from input - var file = this.file_from_path(this.input.val()); - - // execute user event - if (settings.onSubmit.call(this, file, this.get_ext(file)) === false){ - // Do not continue if user function returns false - return; - } - - this.create_form(); - this.input.appendTo(this.form); - this.form.submit(); - - this.input.remove(); this.input = null; - this.form.remove(); this.form = null; - - this.submitting = false; - - // create new input - this.create_input(); - - var iframe = this.iframe; - iframe.load(function(){ - if (iframe[0].src == "about:blank"){ - return; - } - - var response = iframe.contents().find('body').html(); - - settings.onComplete.call(self, file, response); - // Workaround for FF2 bug, which causes cursor to be in busy state after post. - setTimeout(function(){ - // Workaround for ie6 bug, which causes progress bar to be in busy state after post. - // Thanks to Lei for the fix - iframe[0].src= "about:blank"; - iframe.remove(); - }, 1); - }); - - // Create new iframe, so we can have multiple uploads at once - this.create_iframe(); - }, - /** - * Creates form, that will be submitted to iframe - */ - create_form : function(){ - // method, enctype must be specified here - // because changing this attr on the fly is not allowed in IE 6/7 - this.form = - $('
    ') - .attr({ - "action" : this.settings.action - ,"target" : this.iframe.attr('name') - }) - .appendTo('body'); - - // Create hidden input element for each data key - for (var i in this.settings.data){ - $('') - .appendTo(this.form) - .attr({ - 'name': i - ,'value': this.settings.data[i] - }); - } - }, - file_from_path : function(file){ - return file.replace(/.*(\/|\\)/, ""); - }, - get_ext : function(file){ - return (/[.]/.exec(file)) ? /[^.]+$/.exec(file.toLowerCase()) : ''; - }, - make_parent_opaque : function(){ - // ie transparent background bug - this.button.add(this.button.parents()).each(function(){ - var color = $(this).css('backgroundColor'); - var image = $(this).css('backgroundImage'); - - if ( color != 'transparent' || image != 'none'){ - $(this).css('opacity', 1); - return false; - } - }); - } - - }; -})(jQuery); \ No newline at end of file diff --git a/src/main/webapp/webAdmin/resources/jquery.js b/src/main/webapp/webAdmin/resources/jquery.js deleted file mode 100644 index 81a7128..0000000 --- a/src/main/webapp/webAdmin/resources/jquery.js +++ /dev/null @@ -1,4241 +0,0 @@ -/*! - * jQuery JavaScript Library v1.3 - * http://jquery.com/ - * - * Copyright (c) 2009 John Resig - * Dual licensed under the MIT and GPL licenses. - * http://docs.jquery.com/License - * - * Date: 2009-01-13 12:50:31 -0500 (Tue, 13 Jan 2009) - * Revision: 6104 - */ -(function(){ - -var - // Will speed up references to window, and allows munging its name. - window = this, - // Will speed up references to undefined, and allows munging its name. - undefined, - // Map over jQuery in case of overwrite - _jQuery = window.jQuery, - // Map over the $ in case of overwrite - _$ = window.$, - - jQuery = window.jQuery = window.$ = function( selector, context ) { - // The jQuery object is actually just the init constructor 'enhanced' - return new jQuery.fn.init( selector, context ); - }, - - // A simple way to check for HTML strings or ID strings - // (both of which we optimize for) - quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/, - // Is it a simple selector - isSimple = /^.[^:#\[\.,]*$/; - -jQuery.fn = jQuery.prototype = { - init: function( selector, context ) { - // Make sure that a selection was provided - selector = selector || document; - - // Handle $(DOMElement) - if ( selector.nodeType ) { - this[0] = selector; - this.length = 1; - this.context = selector; - return this; - } - // Handle HTML strings - if ( typeof selector === "string" ) { - // Are we dealing with HTML string or an ID? - var match = quickExpr.exec( selector ); - - // Verify a match, and that no context was specified for #id - if ( match && (match[1] || !context) ) { - - // HANDLE: $(html) -> $(array) - if ( match[1] ) - selector = jQuery.clean( [ match[1] ], context ); - - // HANDLE: $("#id") - else { - var elem = document.getElementById( match[3] ); - - // Make sure an element was located - if ( elem ){ - // Handle the case where IE and Opera return items - // by name instead of ID - if ( elem.id != match[3] ) - return jQuery().find( selector ); - - // Otherwise, we inject the element directly into the jQuery object - var ret = jQuery( elem ); - ret.context = document; - ret.selector = selector; - return ret; - } - selector = []; - } - - // HANDLE: $(expr, [context]) - // (which is just equivalent to: $(content).find(expr) - } else - return jQuery( context ).find( selector ); - - // HANDLE: $(function) - // Shortcut for document ready - } else if ( jQuery.isFunction( selector ) ) - return jQuery( document ).ready( selector ); - - // Make sure that old selector state is passed along - if ( selector.selector && selector.context ) { - this.selector = selector.selector; - this.context = selector.context; - } - - return this.setArray(jQuery.makeArray(selector)); - }, - - // Start with an empty selector - selector: "", - - // The current version of jQuery being used - jquery: "1.3", - - // The number of elements contained in the matched element set - size: function() { - return this.length; - }, - - // Get the Nth element in the matched element set OR - // Get the whole matched element set as a clean array - get: function( num ) { - return num === undefined ? - - // Return a 'clean' array - jQuery.makeArray( this ) : - - // Return just the object - this[ num ]; - }, - - // Take an array of elements and push it onto the stack - // (returning the new matched element set) - pushStack: function( elems, name, selector ) { - // Build a new jQuery matched element set - var ret = jQuery( elems ); - - // Add the old object onto the stack (as a reference) - ret.prevObject = this; - - ret.context = this.context; - - if ( name === "find" ) - ret.selector = this.selector + (this.selector ? " " : "") + selector; - else if ( name ) - ret.selector = this.selector + "." + name + "(" + selector + ")"; - - // Return the newly-formed element set - return ret; - }, - - // Force the current matched set of elements to become - // the specified array of elements (destroying the stack in the process) - // You should use pushStack() in order to do this, but maintain the stack - setArray: function( elems ) { - // Resetting the length to 0, then using the native Array push - // is a super-fast way to populate an object with array-like properties - this.length = 0; - Array.prototype.push.apply( this, elems ); - - return this; - }, - - // Execute a callback for every element in the matched set. - // (You can seed the arguments with an array of args, but this is - // only used internally.) - each: function( callback, args ) { - return jQuery.each( this, callback, args ); - }, - - // Determine the position of an element within - // the matched set of elements - index: function( elem ) { - // Locate the position of the desired element - return jQuery.inArray( - // If it receives a jQuery object, the first element is used - elem && elem.jquery ? elem[0] : elem - , this ); - }, - - attr: function( name, value, type ) { - var options = name; - - // Look for the case where we're accessing a style value - if ( typeof name === "string" ) - if ( value === undefined ) - return this[0] && jQuery[ type || "attr" ]( this[0], name ); - - else { - options = {}; - options[ name ] = value; - } - - // Check to see if we're setting style values - return this.each(function(i){ - // Set all the styles - for ( name in options ) - jQuery.attr( - type ? - this.style : - this, - name, jQuery.prop( this, options[ name ], type, i, name ) - ); - }); - }, - - css: function( key, value ) { - // ignore negative width and height values - if ( (key == 'width' || key == 'height') && parseFloat(value) < 0 ) - value = undefined; - return this.attr( key, value, "curCSS" ); - }, - - text: function( text ) { - if ( typeof text !== "object" && text != null ) - return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) ); - - var ret = ""; - - jQuery.each( text || this, function(){ - jQuery.each( this.childNodes, function(){ - if ( this.nodeType != 8 ) - ret += this.nodeType != 1 ? - this.nodeValue : - jQuery.fn.text( [ this ] ); - }); - }); - - return ret; - }, - - wrapAll: function( html ) { - if ( this[0] ) { - // The elements to wrap the target around - var wrap = jQuery( html, this[0].ownerDocument ).clone(); - - if ( this[0].parentNode ) - wrap.insertBefore( this[0] ); - - wrap.map(function(){ - var elem = this; - - while ( elem.firstChild ) - elem = elem.firstChild; - - return elem; - }).append(this); - } - - return this; - }, - - wrapInner: function( html ) { - return this.each(function(){ - jQuery( this ).contents().wrapAll( html ); - }); - }, - - wrap: function( html ) { - return this.each(function(){ - jQuery( this ).wrapAll( html ); - }); - }, - - append: function() { - return this.domManip(arguments, true, function(elem){ - if (this.nodeType == 1) - this.appendChild( elem ); - }); - }, - - prepend: function() { - return this.domManip(arguments, true, function(elem){ - if (this.nodeType == 1) - this.insertBefore( elem, this.firstChild ); - }); - }, - - before: function() { - return this.domManip(arguments, false, function(elem){ - this.parentNode.insertBefore( elem, this ); - }); - }, - - after: function() { - return this.domManip(arguments, false, function(elem){ - this.parentNode.insertBefore( elem, this.nextSibling ); - }); - }, - - end: function() { - return this.prevObject || jQuery( [] ); - }, - - // For internal use only. - // Behaves like an Array's .push method, not like a jQuery method. - push: [].push, - - find: function( selector ) { - if ( this.length === 1 && !/,/.test(selector) ) { - var ret = this.pushStack( [], "find", selector ); - ret.length = 0; - jQuery.find( selector, this[0], ret ); - return ret; - } else { - var elems = jQuery.map(this, function(elem){ - return jQuery.find( selector, elem ); - }); - - return this.pushStack( /[^+>] [^+>]/.test( selector ) ? - jQuery.unique( elems ) : - elems, "find", selector ); - } - }, - - clone: function( events ) { - // Do the clone - var ret = this.map(function(){ - if ( !jQuery.support.noCloneEvent && !jQuery.isXMLDoc(this) ) { - // IE copies events bound via attachEvent when - // using cloneNode. Calling detachEvent on the - // clone will also remove the events from the orignal - // In order to get around this, we use innerHTML. - // Unfortunately, this means some modifications to - // attributes in IE that are actually only stored - // as properties will not be copied (such as the - // the name attribute on an input). - var clone = this.cloneNode(true), - container = document.createElement("div"); - container.appendChild(clone); - return jQuery.clean([container.innerHTML])[0]; - } else - return this.cloneNode(true); - }); - - // Need to set the expando to null on the cloned set if it exists - // removeData doesn't work here, IE removes it from the original as well - // this is primarily for IE but the data expando shouldn't be copied over in any browser - var clone = ret.find("*").andSelf().each(function(){ - if ( this[ expando ] !== undefined ) - this[ expando ] = null; - }); - - // Copy the events from the original to the clone - if ( events === true ) - this.find("*").andSelf().each(function(i){ - if (this.nodeType == 3) - return; - var events = jQuery.data( this, "events" ); - - for ( var type in events ) - for ( var handler in events[ type ] ) - jQuery.event.add( clone[ i ], type, events[ type ][ handler ], events[ type ][ handler ].data ); - }); - - // Return the cloned set - return ret; - }, - - filter: function( selector ) { - return this.pushStack( - jQuery.isFunction( selector ) && - jQuery.grep(this, function(elem, i){ - return selector.call( elem, i ); - }) || - - jQuery.multiFilter( selector, jQuery.grep(this, function(elem){ - return elem.nodeType === 1; - }) ), "filter", selector ); - }, - - closest: function( selector ) { - var pos = jQuery.expr.match.POS.test( selector ) ? jQuery(selector) : null; - - return this.map(function(){ - var cur = this; - while ( cur && cur.ownerDocument ) { - if ( pos ? pos.index(cur) > -1 : jQuery(cur).is(selector) ) - return cur; - cur = cur.parentNode; - } - }); - }, - - not: function( selector ) { - if ( typeof selector === "string" ) - // test special case where just one selector is passed in - if ( isSimple.test( selector ) ) - return this.pushStack( jQuery.multiFilter( selector, this, true ), "not", selector ); - else - selector = jQuery.multiFilter( selector, this ); - - var isArrayLike = selector.length && selector[selector.length - 1] !== undefined && !selector.nodeType; - return this.filter(function() { - return isArrayLike ? jQuery.inArray( this, selector ) < 0 : this != selector; - }); - }, - - add: function( selector ) { - return this.pushStack( jQuery.unique( jQuery.merge( - this.get(), - typeof selector === "string" ? - jQuery( selector ) : - jQuery.makeArray( selector ) - ))); - }, - - is: function( selector ) { - return !!selector && jQuery.multiFilter( selector, this ).length > 0; - }, - - hasClass: function( selector ) { - return !!selector && this.is( "." + selector ); - }, - - val: function( value ) { - if ( value === undefined ) { - var elem = this[0]; - - if ( elem ) { - if( jQuery.nodeName( elem, 'option' ) ) - return (elem.attributes.value || {}).specified ? elem.value : elem.text; - - // We need to handle select boxes special - if ( jQuery.nodeName( elem, "select" ) ) { - var index = elem.selectedIndex, - values = [], - options = elem.options, - one = elem.type == "select-one"; - - // Nothing was selected - if ( index < 0 ) - return null; - - // Loop through all the selected options - for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) { - var option = options[ i ]; - - if ( option.selected ) { - // Get the specifc value for the option - value = jQuery(option).val(); - - // We don't need an array for one selects - if ( one ) - return value; - - // Multi-Selects return an array - values.push( value ); - } - } - - return values; - } - - // Everything else, we just grab the value - return (elem.value || "").replace(/\r/g, ""); - - } - - return undefined; - } - - if ( typeof value === "number" ) - value += ''; - - return this.each(function(){ - if ( this.nodeType != 1 ) - return; - - if ( jQuery.isArray(value) && /radio|checkbox/.test( this.type ) ) - this.checked = (jQuery.inArray(this.value, value) >= 0 || - jQuery.inArray(this.name, value) >= 0); - - else if ( jQuery.nodeName( this, "select" ) ) { - var values = jQuery.makeArray(value); - - jQuery( "option", this ).each(function(){ - this.selected = (jQuery.inArray( this.value, values ) >= 0 || - jQuery.inArray( this.text, values ) >= 0); - }); - - if ( !values.length ) - this.selectedIndex = -1; - - } else - this.value = value; - }); - }, - - html: function( value ) { - return value === undefined ? - (this[0] ? - this[0].innerHTML : - null) : - this.empty().append( value ); - }, - - replaceWith: function( value ) { - return this.after( value ).remove(); - }, - - eq: function( i ) { - return this.slice( i, +i + 1 ); - }, - - slice: function() { - return this.pushStack( Array.prototype.slice.apply( this, arguments ), - "slice", Array.prototype.slice.call(arguments).join(",") ); - }, - - map: function( callback ) { - return this.pushStack( jQuery.map(this, function(elem, i){ - return callback.call( elem, i, elem ); - })); - }, - - andSelf: function() { - return this.add( this.prevObject ); - }, - - domManip: function( args, table, callback ) { - if ( this[0] ) { - var fragment = (this[0].ownerDocument || this[0]).createDocumentFragment(), - scripts = jQuery.clean( args, (this[0].ownerDocument || this[0]), fragment ), - first = fragment.firstChild, - extra = this.length > 1 ? fragment.cloneNode(true) : fragment; - - if ( first ) - for ( var i = 0, l = this.length; i < l; i++ ) - callback.call( root(this[i], first), i > 0 ? extra.cloneNode(true) : fragment ); - - if ( scripts ) - jQuery.each( scripts, evalScript ); - } - - return this; - - function root( elem, cur ) { - return table && jQuery.nodeName(elem, "table") && jQuery.nodeName(cur, "tr") ? - (elem.getElementsByTagName("tbody")[0] || - elem.appendChild(elem.ownerDocument.createElement("tbody"))) : - elem; - } - } -}; - -// Give the init function the jQuery prototype for later instantiation -jQuery.fn.init.prototype = jQuery.fn; - -function evalScript( i, elem ) { - if ( elem.src ) - jQuery.ajax({ - url: elem.src, - async: false, - dataType: "script" - }); - - else - jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" ); - - if ( elem.parentNode ) - elem.parentNode.removeChild( elem ); -} - -function now(){ - return +new Date; -} - -jQuery.extend = jQuery.fn.extend = function() { - // copy reference to target object - var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options; - - // Handle a deep copy situation - if ( typeof target === "boolean" ) { - deep = target; - target = arguments[1] || {}; - // skip the boolean and the target - i = 2; - } - - // Handle case when target is a string or something (possible in deep copy) - if ( typeof target !== "object" && !jQuery.isFunction(target) ) - target = {}; - - // extend jQuery itself if only one argument is passed - if ( length == i ) { - target = this; - --i; - } - - for ( ; i < length; i++ ) - // Only deal with non-null/undefined values - if ( (options = arguments[ i ]) != null ) - // Extend the base object - for ( var name in options ) { - var src = target[ name ], copy = options[ name ]; - - // Prevent never-ending loop - if ( target === copy ) - continue; - - // Recurse if we're merging object values - if ( deep && copy && typeof copy === "object" && !copy.nodeType ) - target[ name ] = jQuery.extend( deep, - // Never move original objects, clone them - src || ( copy.length != null ? [ ] : { } ) - , copy ); - - // Don't bring in undefined values - else if ( copy !== undefined ) - target[ name ] = copy; - - } - - // Return the modified object - return target; -}; - -// exclude the following css properties to add px -var exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i, - // cache defaultView - defaultView = document.defaultView || {}, - toString = Object.prototype.toString; - -jQuery.extend({ - noConflict: function( deep ) { - window.$ = _$; - - if ( deep ) - window.jQuery = _jQuery; - - return jQuery; - }, - - // See test/unit/core.js for details concerning isFunction. - // Since version 1.3, DOM methods and functions like alert - // aren't supported. They return false on IE (#2968). - isFunction: function( obj ) { - return toString.call(obj) === "[object Function]"; - }, - - isArray: function( obj ) { - return toString.call(obj) === "[object Array]"; - }, - - // check if an element is in a (or is an) XML document - isXMLDoc: function( elem ) { - return elem.documentElement && !elem.body || - elem.tagName && elem.ownerDocument && !elem.ownerDocument.body; - }, - - // Evalulates a script in a global context - globalEval: function( data ) { - data = jQuery.trim( data ); - - if ( data ) { - // Inspired by code by Andrea Giammarchi - // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html - var head = document.getElementsByTagName("head")[0] || document.documentElement, - script = document.createElement("script"); - - script.type = "text/javascript"; - if ( jQuery.support.scriptEval ) - script.appendChild( document.createTextNode( data ) ); - else - script.text = data; - - // Use insertBefore instead of appendChild to circumvent an IE6 bug. - // This arises when a base node is used (#2709). - head.insertBefore( script, head.firstChild ); - head.removeChild( script ); - } - }, - - nodeName: function( elem, name ) { - return elem.nodeName && elem.nodeName.toUpperCase() == name.toUpperCase(); - }, - - // args is for internal usage only - each: function( object, callback, args ) { - var name, i = 0, length = object.length; - - if ( args ) { - if ( length === undefined ) { - for ( name in object ) - if ( callback.apply( object[ name ], args ) === false ) - break; - } else - for ( ; i < length; ) - if ( callback.apply( object[ i++ ], args ) === false ) - break; - - // A special, fast, case for the most common use of each - } else { - if ( length === undefined ) { - for ( name in object ) - if ( callback.call( object[ name ], name, object[ name ] ) === false ) - break; - } else - for ( var value = object[0]; - i < length && callback.call( value, i, value ) !== false; value = object[++i] ){} - } - - return object; - }, - - prop: function( elem, value, type, i, name ) { - // Handle executable functions - if ( jQuery.isFunction( value ) ) - value = value.call( elem, i ); - - // Handle passing in a number to a CSS property - return typeof value === "number" && type == "curCSS" && !exclude.test( name ) ? - value + "px" : - value; - }, - - className: { - // internal only, use addClass("class") - add: function( elem, classNames ) { - jQuery.each((classNames || "").split(/\s+/), function(i, className){ - if ( elem.nodeType == 1 && !jQuery.className.has( elem.className, className ) ) - elem.className += (elem.className ? " " : "") + className; - }); - }, - - // internal only, use removeClass("class") - remove: function( elem, classNames ) { - if (elem.nodeType == 1) - elem.className = classNames !== undefined ? - jQuery.grep(elem.className.split(/\s+/), function(className){ - return !jQuery.className.has( classNames, className ); - }).join(" ") : - ""; - }, - - // internal only, use hasClass("class") - has: function( elem, className ) { - return jQuery.inArray( className, (elem.className || elem).toString().split(/\s+/) ) > -1; - } - }, - - // A method for quickly swapping in/out CSS properties to get correct calculations - swap: function( elem, options, callback ) { - var old = {}; - // Remember the old values, and insert the new ones - for ( var name in options ) { - old[ name ] = elem.style[ name ]; - elem.style[ name ] = options[ name ]; - } - - callback.call( elem ); - - // Revert the old values - for ( var name in options ) - elem.style[ name ] = old[ name ]; - }, - - css: function( elem, name, force ) { - if ( name == "width" || name == "height" ) { - var val, props = { position: "absolute", visibility: "hidden", display:"block" }, which = name == "width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ]; - - function getWH() { - val = name == "width" ? elem.offsetWidth : elem.offsetHeight; - var padding = 0, border = 0; - jQuery.each( which, function() { - padding += parseFloat(jQuery.curCSS( elem, "padding" + this, true)) || 0; - border += parseFloat(jQuery.curCSS( elem, "border" + this + "Width", true)) || 0; - }); - val -= Math.round(padding + border); - } - - if ( jQuery(elem).is(":visible") ) - getWH(); - else - jQuery.swap( elem, props, getWH ); - - return Math.max(0, val); - } - - return jQuery.curCSS( elem, name, force ); - }, - - curCSS: function( elem, name, force ) { - var ret, style = elem.style; - - // We need to handle opacity special in IE - if ( name == "opacity" && !jQuery.support.opacity ) { - ret = jQuery.attr( style, "opacity" ); - - return ret == "" ? - "1" : - ret; - } - - // Make sure we're using the right name for getting the float value - if ( name.match( /float/i ) ) - name = styleFloat; - - if ( !force && style && style[ name ] ) - ret = style[ name ]; - - else if ( defaultView.getComputedStyle ) { - - // Only "float" is needed here - if ( name.match( /float/i ) ) - name = "float"; - - name = name.replace( /([A-Z])/g, "-$1" ).toLowerCase(); - - var computedStyle = defaultView.getComputedStyle( elem, null ); - - if ( computedStyle ) - ret = computedStyle.getPropertyValue( name ); - - // We should always get a number back from opacity - if ( name == "opacity" && ret == "" ) - ret = "1"; - - } else if ( elem.currentStyle ) { - var camelCase = name.replace(/\-(\w)/g, function(all, letter){ - return letter.toUpperCase(); - }); - - ret = elem.currentStyle[ name ] || elem.currentStyle[ camelCase ]; - - // From the awesome hack by Dean Edwards - // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 - - // If we're not dealing with a regular pixel number - // but a number that has a weird ending, we need to convert it to pixels - if ( !/^\d+(px)?$/i.test( ret ) && /^\d/.test( ret ) ) { - // Remember the original values - var left = style.left, rsLeft = elem.runtimeStyle.left; - - // Put in the new values to get a computed value out - elem.runtimeStyle.left = elem.currentStyle.left; - style.left = ret || 0; - ret = style.pixelLeft + "px"; - - // Revert the changed values - style.left = left; - elem.runtimeStyle.left = rsLeft; - } - } - - return ret; - }, - - clean: function( elems, context, fragment ) { - context = context || document; - - // !context.createElement fails in IE with an error but returns typeof 'object' - if ( typeof context.createElement === "undefined" ) - context = context.ownerDocument || context[0] && context[0].ownerDocument || document; - - // If a single string is passed in and it's a single tag - // just do a createElement and skip the rest - if ( !fragment && elems.length === 1 && typeof elems[0] === "string" ) { - var match = /^<(\w+)\s*\/?>$/.exec(elems[0]); - if ( match ) - return [ context.createElement( match[1] ) ]; - } - - var ret = [], scripts = [], div = context.createElement("div"); - - jQuery.each(elems, function(i, elem){ - if ( typeof elem === "number" ) - elem += ''; - - if ( !elem ) - return; - - // Convert html string into DOM nodes - if ( typeof elem === "string" ) { - // Fix "XHTML"-style tags in all browsers - elem = elem.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front, tag){ - return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i) ? - all : - front + ">"; - }); - - // Trim whitespace, otherwise indexOf won't work as expected - var tags = jQuery.trim( elem ).toLowerCase(); - - var wrap = - // option or optgroup - !tags.indexOf("", "" ] || - - !tags.indexOf("", "" ] || - - tags.match(/^<(thead|tbody|tfoot|colg|cap)/) && - [ 1, "", "
    " ] || - - !tags.indexOf("", "" ] || - - // matched above - (!tags.indexOf("", "" ] || - - !tags.indexOf("", "" ] || - - // IE can't serialize and