Wao-commits
Threads by month
- ----- 2026 -----
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- 2352 discussions
r1737 - in trunk: wao-persistence/src/main/java/fr/ifremer/wao wao-services/src/main/java/fr/ifremer/wao/services/service wao-web/src/main/java/fr/ifremer/wao/web/action/obsmer
by tchemit@users.forge.codelutin.com 25 Mar '14
by tchemit@users.forge.codelutin.com 25 Mar '14
25 Mar '14
Author: tchemit
Date: 2014-03-25 10:15:32 +0100 (Tue, 25 Mar 2014)
New Revision: 1737
Url: http://forge.codelutin.com/projects/wao/repository/revisions/1737
Log:
refs-20 #4483 (add SamplingPlan Builder)
Added:
trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ObsMerSamplingPlanBuilder.java
Modified:
trunk/wao-persistence/src/main/java/fr/ifremer/wao/SampleRowsFilter.java
trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ObsMerSamplingPlan.java
trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ObsMerSamplingPlanService.java
trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/obsmer/SamplingPlanAction.java
Modified: trunk/wao-persistence/src/main/java/fr/ifremer/wao/SampleRowsFilter.java
===================================================================
--- trunk/wao-persistence/src/main/java/fr/ifremer/wao/SampleRowsFilter.java 2014-03-25 09:06:02 UTC (rev 1736)
+++ trunk/wao-persistence/src/main/java/fr/ifremer/wao/SampleRowsFilter.java 2014-03-25 09:15:32 UTC (rev 1737)
@@ -1,5 +1,26 @@
package fr.ifremer.wao;
+/*
+ * #%L
+ * Wao :: Persistence
+ * %%
+ * Copyright (C) 2009 - 2014 Ifremer
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * #L%
+ */
+
import fr.ifremer.wao.entity.ObsProgram;
import fr.ifremer.wao.entity.ObservationType;
import fr.ifremer.wao.entity.SamplingStrategy;
@@ -47,6 +68,8 @@
protected Set<String> orderByArguments;
+ protected boolean estimatedTides;
+
public ObsProgram getObsProgram() {
return obsProgram;
}
@@ -199,4 +222,11 @@
this.orderByArguments = orderByArguments;
}
+ public boolean isEstimatedTides() {
+ return estimatedTides;
+ }
+
+ public void setEstimatedTides(boolean estimatedTides) {
+ this.estimatedTides = estimatedTides;
+ }
}
Modified: trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ObsMerSamplingPlan.java
===================================================================
--- trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ObsMerSamplingPlan.java 2014-03-25 09:06:02 UTC (rev 1736)
+++ trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ObsMerSamplingPlan.java 2014-03-25 09:15:32 UTC (rev 1737)
@@ -1,5 +1,362 @@
package fr.ifremer.wao.services.service;
-public class ObsMerSamplingPlan {
+/*
+ * #%L
+ * Wao :: Services
+ * %%
+ * Copyright (C) 2009 - 2014 Ifremer
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * #L%
+ */
+import fr.ifremer.wao.entity.SampleMonth;
+import fr.ifremer.wao.entity.SampleRow;
+
+import java.io.Serializable;
+import java.text.NumberFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+public class ObsMerSamplingPlan implements Iterable<ObsMerSamplingPlan.ObsMerSamplingPlanFacadePart>, Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * All facades of the sampling plan.
+ */
+ protected List<ObsMerSamplingPlanFacadePart> facades;
+
+ /**
+ * Statistics over the plan by month.
+ */
+ protected Map<Date, ObsMerSamplingPlanStatistics> statisticsMap;
+
+ /**
+ * Total of observation times in days planned.
+ * FIXME Voir si on doit garder un *D*ouble
+ */
+ protected Double observationTimesInDaysTotalPlanned;
+
+ /**
+ * Total of observation times in days actual.
+ * FIXME Voir si on doit garder un *L*ong
+ */
+ protected Long observationTimesInDaysTotalActual;
+
+ /**
+ * ?
+ * FIXME Voir si on doit garder un *I*integer
+ */
+ protected Integer highTotalExpected;
+
+ /**
+ * ?
+ * FIXME Voir si on doit garder un *I*integer
+ */
+ protected Integer highTotalReal;
+
+ /**
+ * List of month used by sample rows.
+ */
+ protected List<Date> months;
+
+ public ObsMerSamplingPlan(List<Date> months,
+ List<ObsMerSamplingPlanFacadePart> facadeParts,
+ Map<Date, ObsMerSamplingPlanStatistics> statisticsMap,
+ Integer highTotalExpected,
+ Integer highTotalReal,
+ Double observationTimesInDaysTotalPlanned,
+ Long observationTimesInDaysTotalActual) {
+ this.months = months;
+ this.facades = facadeParts;
+ this.statisticsMap = statisticsMap;
+ this.observationTimesInDaysTotalPlanned = observationTimesInDaysTotalPlanned;
+ this.observationTimesInDaysTotalActual = observationTimesInDaysTotalActual;
+ this.highTotalExpected = highTotalExpected;
+ this.highTotalReal = highTotalReal;
+ }
+
+ //FIXME Remove this
+ public List<SampleRow> getRows() {
+ List<SampleRow> result = new ArrayList<>();
+ for (ObsMerSamplingPlanFacadePart facade : facades) {
+ for (ObsMerSamplingPlanSectorPart sectors : facade) {
+ for (ObsMerSamplingPlanSampleRowPart row : sectors) {
+ result.add(row.getSampleRow());
+ }
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public Iterator<ObsMerSamplingPlanFacadePart> iterator() {
+ return facades.iterator();
+ }
+
+ public List<Date> getMonths() {
+ return months;
+ }
+
+ public Double getObservationTimesInDaysTotalPlanned() {
+ return observationTimesInDaysTotalPlanned;
+ }
+
+ public Long getObservationTimesInDaysTotalActual() {
+ return observationTimesInDaysTotalActual;
+ }
+
+ public Integer getTotalExpectedForMonth(Date month) {
+ Integer result = statisticsMap.get(month).getTotalExpected();
+ return result;
+ }
+
+ public Integer getTotalRealForMonth(Date month) {
+ Integer result = statisticsMap.get(month).getTotalReal();
+ return result;
+ }
+
+ public String getRatioForMonth(Date month) {
+ String result = statisticsMap.get(month).getRatioForMonth();
+ return result;
+ }
+
+ public Integer getHighTotalExpected() {
+ return highTotalExpected;
+ }
+
+ public Integer getHighTotalReal() {
+ return highTotalReal;
+ }
+
+ public String getHighTotalRatio() {
+ String ratio = "";
+ if (highTotalExpected > 0) {
+ double percent = ((double) highTotalReal / highTotalExpected);
+ ratio = NumberFormat.getPercentInstance().format(percent);
+ }
+ return ratio;
+ }
+
+ /**
+ * All sectors part for a given facade.
+ * <p/>
+ * Created on 3/24/14.
+ *
+ * @author Tony Chemit <chemit(a)codelutin.com>
+ * @since 4.0
+ */
+ public static class ObsMerSamplingPlanFacadePart implements Iterable<ObsMerSamplingPlanSectorPart>, Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ protected String facade;
+
+ /**
+ * All sector parts for this facade.
+ */
+ protected Collection<ObsMerSamplingPlanSectorPart> sectors;
+
+ public ObsMerSamplingPlanFacadePart(String facade,
+ Collection<ObsMerSamplingPlanSectorPart> sectors) {
+ this.facade = facade;
+ this.sectors = sectors;
+ }
+
+ public String getFacade() {
+ return facade;
+ }
+
+ @Override
+ public Iterator<ObsMerSamplingPlanSectorPart> iterator() {
+ return sectors.iterator();
+ }
+
+ }
+
+ /**
+ * Contains sample rows of a same sectors.
+ */
+ public static class ObsMerSamplingPlanSectorPart implements Iterable<ObsMerSamplingPlanSampleRowPart>, Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ protected String sectors;
+
+ protected Collection<ObsMerSamplingPlanSampleRowPart> sampleRows;
+
+ public ObsMerSamplingPlanSectorPart(String sectors,
+ Collection<ObsMerSamplingPlanSampleRowPart> sampleRows) {
+ this.sectors = sectors;
+ this.sampleRows = sampleRows;
+ }
+
+ public String getSectors() {
+ return sectors;
+ }
+
+ @Override
+ public Iterator<ObsMerSamplingPlanSampleRowPart> iterator() {
+ return sampleRows.iterator();
+ }
+ }
+
+ protected static final SimpleDateFormat dateFormat = new SimpleDateFormat("MM/yyyy");
+
+ /**
+ * Created on 3/24/14.
+ *
+ * @author Tony Chemit <chemit(a)codelutin.com>
+ * @since 4.0
+ */
+ public static class ObsMerSamplingPlanSampleRowPart implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Boxed sample row.
+ */
+ protected SampleRow sampleRow;
+
+ /**
+ * Times of observation days planned.
+ * <p/>
+ * FIXME Voir si on doit garder un *D*ouble
+ */
+ protected Double observationTimesInDaysPlanned;
+
+ /**
+ * Actual times of observation in days.
+ * <p/>
+ * FIXME Voir si on doit garder un *D*ouble
+ */
+ protected Long observationTimesInDaysActual;
+
+
+ public ObsMerSamplingPlanSampleRowPart(SampleRow sampleRow,
+ Double observationTimesInDaysPlanned,
+ Long observationTimesInDaysActual) {
+ this.sampleRow = sampleRow;
+ this.observationTimesInDaysPlanned = observationTimesInDaysPlanned;
+ this.observationTimesInDaysActual = observationTimesInDaysActual;
+ }
+
+ public SampleRow getSampleRow() {
+ return sampleRow;
+ }
+
+ public Integer getNbTidesExpected(Date month) {
+ Integer result = null;
+ SampleMonth sampleMonth = sampleRow.getSampleMonth(month);
+ if (sampleMonth != null) {
+ result = sampleMonth.getExpectedTidesValue();
+ }
+ return result;
+ }
+
+ public Integer getNbTidesReal(Date month, boolean estimatedTides) {
+ Integer result = null;
+ SampleMonth sampleMonth = sampleRow.getSampleMonth(month);
+ if (sampleMonth != null) {
+ // result = getFilter().getEstimatedTides() ?
+ result = estimatedTides ?
+ sampleMonth.getEstimatedTidesValue() :
+ sampleMonth.getRealTidesValue();
+ }
+ return result;
+ }
+
+ //FIXME Move this in ui ?
+ public String getTotalPercentage() {
+ String result;
+ if (sampleRow.getTotalTidesExpected() > 0) {
+ double percentage = (double) sampleRow.getTotalTidesReal() / (double) sampleRow.getTotalTidesExpected();
+ result = NumberFormat.getPercentInstance().format(percentage);
+ } else {
+ result = "- %";
+ }
+ return result;
+ }
+
+ public Double getObservationTimesInDaysPlanned() {
+ return observationTimesInDaysPlanned;
+ }
+
+ public Long getObservationTimesInDaysActual() {
+ return observationTimesInDaysActual;
+ }
+
+ public boolean hasNbTidesReal(Date month, boolean estimatedTides) {
+ Date current = new Date();
+ boolean validMonth = month.before(current) || isCurrentMonth(month);
+ return validMonth && getNbTidesReal(month, estimatedTides) != null;
+ }
+
+ public boolean isCurrentMonth(Date month) {
+ String currentStr = dateFormat.format(new Date());
+ String monthStr = dateFormat.format(month);
+ return currentStr.equals(monthStr);
+ }
+ }
+
+ public static class ObsMerSamplingPlanStatistics implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Total of expected tides.
+ * <p/>
+ * FIXME Voir si on doit garder un *I*nteger
+ */
+ protected Integer totalExpected;
+
+ /**
+ * Total of real tides.
+ * <p/>
+ * FIXME Voir si on doit garder un *I*nteger
+ */
+ protected Integer totalReal;
+
+ public ObsMerSamplingPlanStatistics(Integer totalExpected, Integer totalReal) {
+ this.totalExpected = totalExpected;
+ this.totalReal = totalReal;
+ }
+
+ public Integer getTotalExpected() {
+ return totalExpected;
+ }
+
+ public Integer getTotalReal() {
+ return totalReal;
+ }
+
+ //FIXME Move this in ui ?
+ public String getRatioForMonth() {
+ String ratio = "-";
+ if (totalExpected != null && totalExpected > 0 &&
+ totalReal != null && totalReal > 0) {
+ double percent = ((double) totalReal / totalExpected);
+ ratio = NumberFormat.getPercentInstance().format(percent);
+ }
+ return ratio;
+ }
+
+ }
}
Added: trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ObsMerSamplingPlanBuilder.java
===================================================================
--- trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ObsMerSamplingPlanBuilder.java (rev 0)
+++ trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ObsMerSamplingPlanBuilder.java 2014-03-25 09:15:32 UTC (rev 1737)
@@ -0,0 +1,278 @@
+package fr.ifremer.wao.services.service;
+
+/*
+ * #%L
+ * Wao :: Services
+ * %%
+ * Copyright (C) 2009 - 2014 Ifremer
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * #L%
+ */
+
+import fr.ifremer.wao.SampleRowsFilter;
+import fr.ifremer.wao.entity.SampleRow;
+import org.apache.commons.lang3.mutable.MutableDouble;
+import org.apache.commons.lang3.mutable.MutableInt;
+import org.apache.commons.lang3.mutable.MutableLong;
+import org.nuiton.util.PeriodDates;
+
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * To build a new {@link ObsMerSamplingPlan} from a {@link SampleRowsFilter}
+ * and some {@link SampleRow}.
+ * <p/>
+ * Created on 3/24/14.
+ *
+ * @author Tony Chemit <chemit(a)codelutin.com>
+ * @since 4.0
+ */
+public class ObsMerSamplingPlanBuilder {
+
+ /**
+ * Incoming filter used.
+ */
+ protected SampleRowsFilter sampleRowsFilter;
+
+ /**
+ * List of month computed from the filter.
+ */
+ protected List<Date> months;
+
+ /**
+ * Dictionnary of facades indexed by their facade name.
+ */
+ protected LinkedHashMap<String, FacadeContext> facadeMap;
+
+ /**
+ * To compute the high total expected.
+ *
+ * @see ObsMerSamplingPlan#highTotalExpected
+ */
+ protected MutableInt highTotalExpected;
+
+ /**
+ * To compute the high total real.
+ *
+ * @see ObsMerSamplingPlan#highTotalReal
+ */
+ protected MutableInt highTotalReal;
+
+ /**
+ * To compute the total of planned observation times in days.
+ *
+ * @see ObsMerSamplingPlan#observationTimesInDaysTotalPlanned
+ */
+ protected MutableDouble observationTimesInDaysTotalPlanned;
+
+ /**
+ * To compute the total of actual observation times in days.
+ *
+ * @see ObsMerSamplingPlan#observationTimesInDaysTotalActual
+ */
+ protected MutableLong observationTimesInDaysTotalActual;
+
+ /**
+ * To compute by month the total of expected tides.
+ *
+ * @see ObsMerSamplingPlan.ObsMerSamplingPlanStatistics#totalExpected
+ */
+ protected Map<Date, MutableInt> totalExpectedForMonths;
+
+ /**
+ * To compute by month the total of real tides.
+ *
+ * @see ObsMerSamplingPlan.ObsMerSamplingPlanStatistics#totalReal
+ */
+ protected Map<Date, MutableInt> totalRealForMonths;
+
+ public ObsMerSamplingPlanBuilder(SampleRowsFilter sampleRowsFilter) {
+ this.sampleRowsFilter = sampleRowsFilter;
+ this.facadeMap = new LinkedHashMap<>();
+ this.highTotalExpected = new MutableInt();
+ this.highTotalReal = new MutableInt();
+ this.observationTimesInDaysTotalPlanned = new MutableDouble();
+ this.observationTimesInDaysTotalActual = new MutableLong();
+
+ PeriodDates periodDates = new PeriodDates(sampleRowsFilter.getPeriodFrom(),
+ sampleRowsFilter.getPeriodTo());
+ this.months = periodDates.getMonths();
+ }
+
+ public ObsMerSamplingPlanBuilder addSampleRow(SampleRow sampleRow,
+ Double observationTimesInDaysPlanned,
+ Long observationTimesInDaysActual) {
+
+ String facade = sampleRow.getFacade();
+ FacadeContext facadeContext = facadeMap.get(facade);
+
+ if (facadeContext == null) {
+
+ // register a new facade
+ facadeContext = new FacadeContext(facade);
+ facadeMap.put(facade, facadeContext);
+ }
+
+ String sectors = sampleRow.getSectors();
+
+ // get sector context
+ ServiceContext sectorPart = facadeContext.getOrAddSectorContext(sectors);
+
+ // add sample row
+ ObsMerSamplingPlan.ObsMerSamplingPlanSampleRowPart sampleRowPart =
+ sectorPart.addSampleRow(sampleRow,
+ observationTimesInDaysPlanned,
+ observationTimesInDaysActual);
+
+ // update totals
+ updateTotals(sampleRowPart);
+
+ // Sum total observation times in days
+ observationTimesInDaysTotalPlanned.add(observationTimesInDaysPlanned);
+ observationTimesInDaysTotalActual.add(observationTimesInDaysActual);
+
+ return this;
+ }
+
+ public ObsMerSamplingPlan toPlan() {
+
+ LinkedList<ObsMerSamplingPlan.ObsMerSamplingPlanFacadePart> facadeParts = new LinkedList<>();
+ for (FacadeContext facadeContext : facadeMap.values()) {
+ ObsMerSamplingPlan.ObsMerSamplingPlanFacadePart facadePart = facadeContext.toBean();
+ facadeParts.add(facadePart);
+ }
+
+ TreeMap<Date, ObsMerSamplingPlan.ObsMerSamplingPlanStatistics> statisticsMap = new TreeMap<>();
+ for (Date month : months) {
+
+ MutableInt totalExpected = totalExpectedForMonths.get(month);
+ MutableInt totalReal = totalRealForMonths.get(month);
+ ObsMerSamplingPlan.ObsMerSamplingPlanStatistics planStatistics =
+ new ObsMerSamplingPlan.ObsMerSamplingPlanStatistics(totalExpected.toInteger(),
+ totalReal.toInteger());
+ statisticsMap.put(month, planStatistics);
+ }
+
+ ObsMerSamplingPlan result = new ObsMerSamplingPlan(months,
+ facadeParts,
+ statisticsMap,
+ highTotalExpected.toInteger(),
+ highTotalReal.toInteger(),
+ observationTimesInDaysTotalPlanned.toDouble(),
+ observationTimesInDaysTotalActual.toLong());
+ return result;
+ }
+
+ protected void updateTotals(ObsMerSamplingPlan.ObsMerSamplingPlanSampleRowPart sampleRowPart) {
+ for (Date month : months) {
+
+ Integer expected = sampleRowPart.getNbTidesExpected(month);
+ Integer real = sampleRowPart.getNbTidesReal(month, sampleRowsFilter.isEstimatedTides());
+
+ if (expected != null) {
+
+ MutableInt totalExpected = totalExpectedForMonths.get(month);
+ if (totalExpected == null) {
+ totalExpected = new MutableInt();
+ totalExpectedForMonths.put(month, totalExpected);
+ }
+ totalExpected.add(expected);
+ highTotalExpected.add(totalExpected);
+ }
+
+ if (real != null) {
+ MutableInt totalReal = totalRealForMonths.get(month);
+ if (totalReal == null) {
+ totalReal = new MutableInt();
+ totalRealForMonths.put(month, totalReal);
+ }
+ totalReal.add(real);
+ highTotalReal.add(totalReal);
+ }
+ }
+ }
+
+ protected static class FacadeContext {
+
+ protected String facade;
+
+ protected LinkedHashMap<String, ServiceContext> sectorMap;
+
+ protected FacadeContext(String facade) {
+ this.facade = facade;
+ this.sectorMap = new LinkedHashMap<>();
+ }
+
+ protected ServiceContext getOrAddSectorContext(String sectors) {
+ ServiceContext sectorPart = sectorMap.get(sectors);
+ if (sectorPart == null) {
+
+ // register a new sector
+ sectorPart = new ServiceContext(sectors);
+ sectorMap.put(sectors, sectorPart);
+ }
+ return sectorPart;
+ }
+
+ protected ObsMerSamplingPlan.ObsMerSamplingPlanFacadePart toBean() {
+
+ LinkedList<ObsMerSamplingPlan.ObsMerSamplingPlanSectorPart> sectorParts = new LinkedList<>();
+ for (ServiceContext serviceContext : sectorMap.values()) {
+ ObsMerSamplingPlan.ObsMerSamplingPlanSectorPart sectorPart = serviceContext.toBean();
+ sectorParts.add(sectorPart);
+ }
+ ObsMerSamplingPlan.ObsMerSamplingPlanFacadePart result =
+ new ObsMerSamplingPlan.ObsMerSamplingPlanFacadePart(facade, sectorParts);
+ return result;
+ }
+ }
+
+ protected static class ServiceContext {
+
+ protected String sectors;
+
+ protected LinkedList<ObsMerSamplingPlan.ObsMerSamplingPlanSampleRowPart> rows;
+
+ protected ServiceContext(String sectors) {
+ this.sectors = sectors;
+ rows = new LinkedList<>();
+ }
+
+ protected ObsMerSamplingPlan.ObsMerSamplingPlanSampleRowPart addSampleRow(SampleRow row,
+ Double observationTimesInDaysPlanned,
+ Long observationTimesInDaysActual) {
+
+ ObsMerSamplingPlan.ObsMerSamplingPlanSampleRowPart rowPart =
+ new ObsMerSamplingPlan.ObsMerSamplingPlanSampleRowPart(row,
+ observationTimesInDaysPlanned,
+ observationTimesInDaysActual);
+ rows.add(rowPart);
+
+ return rowPart;
+ }
+
+ protected ObsMerSamplingPlan.ObsMerSamplingPlanSectorPart toBean() {
+
+ ObsMerSamplingPlan.ObsMerSamplingPlanSectorPart result =
+ new ObsMerSamplingPlan.ObsMerSamplingPlanSectorPart(sectors, rows);
+ return result;
+ }
+ }
+}
Property changes on: trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ObsMerSamplingPlanBuilder.java
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision
Added: svn:eol-style
+ native
Modified: trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ObsMerSamplingPlanService.java
===================================================================
--- trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ObsMerSamplingPlanService.java 2014-03-25 09:06:02 UTC (rev 1736)
+++ trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ObsMerSamplingPlanService.java 2014-03-25 09:15:32 UTC (rev 1737)
@@ -1,5 +1,26 @@
package fr.ifremer.wao.services.service;
+/*
+ * #%L
+ * Wao :: Services
+ * %%
+ * Copyright (C) 2009 - 2014 Ifremer
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * #L%
+ */
+
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
@@ -216,7 +237,7 @@
for (ElligibleBoat elligibleBoat : sampleRow.getElligibleBoat()) {
Boat boat = elligibleBoat.getBoat();
- boolean isNoLongerActive = ! elligibleBoats.contains(boat);
+ boolean isNoLongerActive = !elligibleBoats.contains(boat);
if (isNoLongerActive) {
if (authenticatedWaoUser.isAdmin()) {
elligibleBoat.setGlobalActive(false);
@@ -280,7 +301,7 @@
List<SampleRow> existingSampleRowsForTheSameCode = dao.forCodeEquals(sampleRow.getCode()).findAll();
if (existingSampleRowsForTheSameCode.size() > 1) {
throw new SampleRowCodeMustBeUniqueException();
- } else if (existingSampleRowsForTheSameCode.size() == 1 && ! Iterables.getOnlyElement(existingSampleRowsForTheSameCode).equals(sampleRow)) {
+ } else if (existingSampleRowsForTheSameCode.size() == 1 && !Iterables.getOnlyElement(existingSampleRowsForTheSameCode).equals(sampleRow)) {
throw new SampleRowCodeMustBeUniqueException();
}
@@ -290,7 +311,7 @@
SampleRow sampleRow = updateSampleRowCommand.getSampleRow();
- if ( ! updateSampleRowCommand.isCreation()) {
+ if (!updateSampleRowCommand.isCreation()) {
SampleRowLog sampleRowLog = updateSampleRowCommand.getSampleRowLog();
getSampleRowLogDao().create(sampleRowLog);
}
@@ -337,7 +358,7 @@
}
- public List<SampleRow> getSamplingPlan(SampleRowsFilter sampleRowsFilter) {
+ public List<SampleRow> getSamplingPlanRows(SampleRowsFilter sampleRowsFilter) {
SampleRowTopiaDao dao = getSampleRowDao();
@@ -345,6 +366,26 @@
}
+ public ObsMerSamplingPlan getSamplingPlan(SampleRowsFilter sampleRowsFilter) {
+
+ SampleRowTopiaDao dao = getSampleRowDao();
+
+ List<SampleRow> sampleRows = dao.findAll(sampleRowsFilter);
+ ObsMerSamplingPlanBuilder builder = new ObsMerSamplingPlanBuilder(sampleRowsFilter);
+ for (SampleRow sampleRow : sampleRows) {
+ //TODO Compute see ServiceSamplingImpl#executeGetObservationTimesInDays
+ Double observationTimesInDaysPlanned = 0d;
+ Long observationTimesInDaysActual = 0l;
+ builder.addSampleRow(sampleRow,
+ observationTimesInDaysPlanned,
+ observationTimesInDaysActual);
+ }
+ ObsMerSamplingPlan result = builder.toPlan();
+
+ return result;
+
+ }
+
public SampleRowsFilter newSampleRowsFilter(AuthenticatedWaoUser authenticatedWaoUser) {
SampleRowsFilter newFilter = new SampleRowsFilter();
@@ -484,7 +525,7 @@
ImportModel<SampleRow> samplingPlanImportModel =
new ObsMerObsVenteSamplingPlanImportExportModel(obsProgram,
- activeCompanies, fishingZones, terrestrialDistricts, referentialService);
+ activeCompanies, fishingZones, terrestrialDistricts, referentialService);
return samplingPlanImportModel;
Modified: trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/obsmer/SamplingPlanAction.java
===================================================================
--- trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/obsmer/SamplingPlanAction.java 2014-03-25 09:06:02 UTC (rev 1736)
+++ trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/obsmer/SamplingPlanAction.java 2014-03-25 09:15:32 UTC (rev 1737)
@@ -1,7 +1,29 @@
package fr.ifremer.wao.web.action.obsmer;
+/*
+ * #%L
+ * Wao :: Web
+ * %%
+ * Copyright (C) 2009 - 2014 Ifremer
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * #L%
+ */
+
import fr.ifremer.wao.SampleRowsFilter;
import fr.ifremer.wao.entity.SampleRow;
+import fr.ifremer.wao.services.service.ObsMerSamplingPlan;
import fr.ifremer.wao.services.service.ObsMerSamplingPlanService;
import fr.ifremer.wao.web.WaoJspActionSupport;
@@ -11,7 +33,7 @@
protected ObsMerSamplingPlanService service;
- protected List<SampleRow> samplingPlan;
+ protected ObsMerSamplingPlan samplingPlan;
public void setService(ObsMerSamplingPlanService service) {
this.service = service;
@@ -29,7 +51,7 @@
}
public List<SampleRow> getSamplingPlan() {
- return samplingPlan;
+ return samplingPlan.getRows();
}
public String getSampleRowToHighlightId() {
1
0
25 Mar '14
Author: tchemit
Date: 2014-03-25 10:06:02 +0100 (Tue, 25 Mar 2014)
New Revision: 1736
Url: http://forge.codelutin.com/projects/wao/repository/revisions/1736
Log:
add log configuration for tests
Added:
trunk/wao-persistence/src/test/resources/log4j.properties
Copied: trunk/wao-persistence/src/test/resources/log4j.properties (from rev 1733, trunk/wao-services/src/test/resources/log4j.properties)
===================================================================
--- trunk/wao-persistence/src/test/resources/log4j.properties (rev 0)
+++ trunk/wao-persistence/src/test/resources/log4j.properties 2014-03-25 09:06:02 UTC (rev 1736)
@@ -0,0 +1,34 @@
+###
+# #%L
+# Wao :: Persistence
+# %%
+# Copyright (C) 2009 - 2014 Ifremer
+# %%
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# #L%
+###
+log4j.rootCategory=WARN, console
+
+log4j.appender.console=org.apache.log4j.ConsoleAppender
+log4j.appender.console.layout=org.apache.log4j.PatternLayout
+log4j.appender.console.layout.ConversionPattern=%d{yyyy/MM/dd hh:mm:ss} %5p (%F:%L) %M %m%n
+
+# global level
+log4j.logger.fr.ifremer.wao=TRACE
+
+### persistence level
+# log4j.logger.org.nuiton.topia=TRACE
+
+### services level
+# log4j.logger.fr.ifremer.wao.services=TRACE
1
0
r1735 - in trunk: . wao-persistence wao-persistence/src wao-persistence/src/license wao-services wao-services/src wao-services/src/license wao-web wao-web/src wao-web/src/license
by tchemit@users.forge.codelutin.com 25 Mar '14
by tchemit@users.forge.codelutin.com 25 Mar '14
25 Mar '14
Author: tchemit
Date: 2014-03-25 10:03:44 +0100 (Tue, 25 Mar 2014)
New Revision: 1735
Url: http://forge.codelutin.com/projects/wao/repository/revisions/1735
Log:
fix licenses
fix third-parties
fix dependencies
Added:
trunk/wao-persistence/src/license/
trunk/wao-persistence/src/license/THIRD-PARTY.properties
trunk/wao-services/src/license/
trunk/wao-services/src/license/THIRD-PARTY.properties
trunk/wao-web/src/license/
trunk/wao-web/src/license/THIRD-PARTY.properties
Modified:
trunk/LICENSE.txt
trunk/pom.xml
trunk/wao-persistence/LICENSE.txt
trunk/wao-persistence/pom.xml
trunk/wao-services/LICENSE.txt
trunk/wao-services/pom.xml
trunk/wao-web/LICENSE.txt
trunk/wao-web/pom.xml
Modified: trunk/LICENSE.txt
===================================================================
--- trunk/LICENSE.txt 2014-03-24 10:06:46 UTC (rev 1734)
+++ trunk/LICENSE.txt 2014-03-25 09:03:44 UTC (rev 1735)
@@ -658,4 +658,4 @@
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
-<http://www.gnu.org/licenses/>.
\ No newline at end of file
+<http://www.gnu.org/licenses/>.
Modified: trunk/pom.xml
===================================================================
--- trunk/pom.xml 2014-03-24 10:06:46 UTC (rev 1734)
+++ trunk/pom.xml 2014-03-25 09:03:44 UTC (rev 1735)
@@ -106,7 +106,7 @@
<bootstrapPluginVersion>1.6.1</bootstrapPluginVersion>
<shiroVersion>1.2.2</shiroVersion>
<slf4jVersion>1.7.6</slf4jVersion>
- <hibernateVersion>4.2.8.Final</hibernateVersion>
+ <hibernateVersion>4.3.1.Final</hibernateVersion>
<mockitoVersion>1.9.5</mockitoVersion>
<postgresqlDriverVersion>9.3-1101-jdbc41</postgresqlDriverVersion>
<commonsEmailVersion>1.3.2</commonsEmailVersion>
@@ -237,6 +237,13 @@
<dependency>
<groupId>org.hibernate</groupId>
+ <artifactId>hibernate-core</artifactId>
+ <version>${hibernateVersion}</version>
+ <scope>compile</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.hibernate</groupId>
<artifactId>hibernate-c3p0</artifactId>
<version>${hibernateVersion}</version>
<scope>runtime</scope>
Modified: trunk/wao-persistence/LICENSE.txt
===================================================================
--- trunk/wao-persistence/LICENSE.txt 2014-03-24 10:06:46 UTC (rev 1734)
+++ trunk/wao-persistence/LICENSE.txt 2014-03-25 09:03:44 UTC (rev 1735)
@@ -658,4 +658,4 @@
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
-<http://www.gnu.org/licenses/>.
\ No newline at end of file
+<http://www.gnu.org/licenses/>.
Modified: trunk/wao-persistence/pom.xml
===================================================================
--- trunk/wao-persistence/pom.xml 2014-03-24 10:06:46 UTC (rev 1734)
+++ trunk/wao-persistence/pom.xml 2014-03-25 09:03:44 UTC (rev 1735)
@@ -22,11 +22,21 @@
<dependency>
<groupId>org.hibernate</groupId>
+ <artifactId>hibernate-core</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.hibernate</groupId>
<artifactId>hibernate-c3p0</artifactId>
</dependency>
<dependency>
<groupId>org.nuiton</groupId>
+ <artifactId>nuiton-utils</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.nuiton</groupId>
<artifactId>nuiton-config</artifactId>
</dependency>
Added: trunk/wao-persistence/src/license/THIRD-PARTY.properties
===================================================================
--- trunk/wao-persistence/src/license/THIRD-PARTY.properties (rev 0)
+++ trunk/wao-persistence/src/license/THIRD-PARTY.properties 2014-03-25 09:03:44 UTC (rev 1735)
@@ -0,0 +1,31 @@
+# Generated by org.codehaus.mojo.license.AddThirdPartyMojo
+#-------------------------------------------------------------------------------
+# Already used licenses in project :
+# - AL 2.0
+# - Apache License 2.0
+# - Apache License, version 2.0
+# - BSD License
+# - COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
+# - Common Development and Distribution License
+# - Common Public License Version 1.0
+# - Eclipse Distribution License (EDL), Version 1.0
+# - Eclipse Public License (EPL), Version 1.0
+# - Eclipse Public License, Version 1.0
+# - GNU General Public License, Version 2 with the Classpath Exception
+# - GNU Lesser General Public License, Version 2.1
+# - Indiana University Extreme! Lab Software License, vesion 1.1.1
+# - Lesser General Public License (LGPL) v 3.0
+# - Lesser General Public License (LPGL)
+# - Lesser General Public License (LPGL) v 2.1
+# - MIT License
+# - MPL 1.1
+# - New BSD License
+# - Public Domain
+# - The Apache Software License, Version 2.0
+#-------------------------------------------------------------------------------
+# Please fill the missing licenses for dependencies :
+#
+#
+#Tue Mar 25 09:09:51 CET 2014
+commons-primitives--commons-primitives--1.0=The Apache Software License, Version 2.0
+dom4j--dom4j--1.6.1=BSD License
Property changes on: trunk/wao-persistence/src/license/THIRD-PARTY.properties
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision
Added: svn:eol-style
+ native
Modified: trunk/wao-services/LICENSE.txt
===================================================================
--- trunk/wao-services/LICENSE.txt 2014-03-24 10:06:46 UTC (rev 1734)
+++ trunk/wao-services/LICENSE.txt 2014-03-25 09:03:44 UTC (rev 1735)
@@ -658,4 +658,4 @@
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
-<http://www.gnu.org/licenses/>.
\ No newline at end of file
+<http://www.gnu.org/licenses/>.
Modified: trunk/wao-services/pom.xml
===================================================================
--- trunk/wao-services/pom.xml 2014-03-24 10:06:46 UTC (rev 1734)
+++ trunk/wao-services/pom.xml 2014-03-25 09:03:44 UTC (rev 1735)
@@ -20,10 +20,10 @@
<artifactId>nuiton-csv</artifactId>
</dependency>
- <dependency>
+ <!--dependency>
<groupId>org.nuiton</groupId>
<artifactId>nuiton-validator</artifactId>
- </dependency>
+ </dependency-->
<dependency>
<groupId>org.nuiton.i18n</groupId>
@@ -31,6 +31,11 @@
</dependency>
<dependency>
+ <groupId>org.nuiton</groupId>
+ <artifactId>nuiton-utils</artifactId>
+ </dependency>
+
+ <dependency>
<groupId>com.github.spullara.mustache.java</groupId>
<artifactId>compiler</artifactId>
</dependency>
@@ -81,10 +86,10 @@
<artifactId>commons-io</artifactId>
</dependency>
- <dependency>
+ <!--dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
- </dependency>
+ </dependency-->
<dependency>
<groupId>org.slf4j</groupId>
Added: trunk/wao-services/src/license/THIRD-PARTY.properties
===================================================================
--- trunk/wao-services/src/license/THIRD-PARTY.properties (rev 0)
+++ trunk/wao-services/src/license/THIRD-PARTY.properties 2014-03-25 09:03:44 UTC (rev 1735)
@@ -0,0 +1,37 @@
+# Generated by org.codehaus.mojo.license.AddThirdPartyMojo
+#-------------------------------------------------------------------------------
+# Already used licenses in project :
+# - AL 2.0
+# - Affero General Public License (AGPL)
+# - Apache License 2.0
+# - Apache License, version 2.0
+# - BSD License
+# - CDDL
+# - COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
+# - Common Development and Distribution License
+# - Common Public License Version 1.0
+# - Eclipse Distribution License (EDL), Version 1.0
+# - Eclipse Public License (EPL), Version 1.0
+# - Eclipse Public License, Version 1.0
+# - GNU General Public License, Version 2 with the Classpath Exception
+# - GNU Lesser General Public License, Version 2.1
+# - GNU Library or Lesser General Public License
+# - GPLv2+CE
+# - Indiana University Extreme! Lab Software License, vesion 1.1.1
+# - Lesser General Public License (LGPL) v 3.0
+# - Lesser General Public License (LPGL)
+# - Lesser General Public License (LPGL) v 2.1
+# - MIT License
+# - MPL 1.1
+# - New BSD License
+# - Public Domain
+# - The Apache Software License, Version 2.0
+# - The H2 License, Version 1.0
+# - The MIT License
+#-------------------------------------------------------------------------------
+# Please fill the missing licenses for dependencies :
+#
+#
+#Tue Mar 25 09:19:02 CET 2014
+commons-primitives--commons-primitives--1.0=The Apache Software License, Version 2.0
+dom4j--dom4j--1.6.1=BSD License
Property changes on: trunk/wao-services/src/license/THIRD-PARTY.properties
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision
Added: svn:eol-style
+ native
Modified: trunk/wao-web/LICENSE.txt
===================================================================
--- trunk/wao-web/LICENSE.txt 2014-03-24 10:06:46 UTC (rev 1734)
+++ trunk/wao-web/LICENSE.txt 2014-03-25 09:03:44 UTC (rev 1735)
@@ -658,4 +658,4 @@
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
-<http://www.gnu.org/licenses/>.
\ No newline at end of file
+<http://www.gnu.org/licenses/>.
Modified: trunk/wao-web/pom.xml
===================================================================
--- trunk/wao-web/pom.xml 2014-03-24 10:06:46 UTC (rev 1734)
+++ trunk/wao-web/pom.xml 2014-03-25 09:03:44 UTC (rev 1735)
@@ -129,6 +129,7 @@
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-json-plugin</artifactId>
+ <scope>runtime</scope>
</dependency>
<dependency>
@@ -138,7 +139,13 @@
<dependency>
<groupId>org.apache.shiro</groupId>
+ <artifactId>shiro-core</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
+ <scope>runtime</scope>
</dependency>
<!-- TODO enable guava caching -->
Added: trunk/wao-web/src/license/THIRD-PARTY.properties
===================================================================
--- trunk/wao-web/src/license/THIRD-PARTY.properties (rev 0)
+++ trunk/wao-web/src/license/THIRD-PARTY.properties 2014-03-25 09:03:44 UTC (rev 1735)
@@ -0,0 +1,38 @@
+# Generated by org.codehaus.mojo.license.AddThirdPartyMojo
+#-------------------------------------------------------------------------------
+# Already used licenses in project :
+# - AL 2.0
+# - Affero General Public License (AGPL)
+# - Apache License 2.0
+# - Apache License, version 2.0
+# - BSD License
+# - BSD-style license
+# - CDDL
+# - COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
+# - Common Development and Distribution License
+# - Eclipse Distribution License (EDL), Version 1.0
+# - Eclipse Public License (EPL), Version 1.0
+# - Eclipse Public License, Version 1.0
+# - GNU General Public License, Version 2 with the Classpath Exception
+# - GNU Lesser General Public License, Version 2.1
+# - GNU Library or Lesser General Public License
+# - GPLv2+CE
+# - Indiana University Extreme! Lab Software License, vesion 1.1.1
+# - Lesser General Public License (LGPL) v 3.0
+# - Lesser General Public License (LPGL)
+# - Lesser General Public License (LPGL) v 2.1
+# - MIT License
+# - MPL 1.1
+# - Public Domain
+# - The Apache Software License, Version 1.1
+# - The Apache Software License, Version 2.0
+# - The H2 License, Version 1.0
+#-------------------------------------------------------------------------------
+# Please fill the missing licenses for dependencies :
+#
+#
+#Tue Mar 25 09:20:32 CET 2014
+commons-primitives--commons-primitives--1.0=The Apache Software License, Version 2.0
+dom4j--dom4j--1.6.1=BSD License
+javax.servlet--servlet-api--2.5=COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
+oro--oro--2.0.8=The Apache Software License, Version 2.0
Property changes on: trunk/wao-web/src/license/THIRD-PARTY.properties
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision
Added: svn:eol-style
+ native
1
0
Author: tchemit
Date: 2014-03-24 11:06:46 +0100 (Mon, 24 Mar 2014)
New Revision: 1734
Url: http://forge.codelutin.com/projects/wao/repository/revisions/1734
Log:
update pom
Modified:
trunk/pom.xml
Modified: trunk/pom.xml
===================================================================
--- trunk/pom.xml 2014-03-20 16:53:39 UTC (rev 1733)
+++ trunk/pom.xml 2014-03-24 10:06:46 UTC (rev 1734)
@@ -5,7 +5,7 @@
<parent>
<groupId>org.nuiton</groupId>
<artifactId>mavenpom4redmine</artifactId>
- <version>4.4</version>
+ <version>5.0.4</version>
</parent>
<groupId>fr.ifremer</groupId>
@@ -15,7 +15,7 @@
<name>Wao</name>
<description>Application pour le suivi contractuels d'observations scientifiques de la pêche</description>
- <url>http://maven-site.forge.codelutin.com/wao</url>
+ <url>http://doc.codelutin.com/wao</url>
<inceptionYear>2009</inceptionYear>
<organization>
<name>Ifremer</name>
@@ -29,7 +29,7 @@
<email>fdesbois(a)codelutin.com</email>
<organization>CodeLutin</organization>
<organizationUrl>http://www.codelutin.com</organizationUrl>
- <timezone>+1</timezone>
+ <timezone>Europe/Paris</timezone>
<roles>
<role>Chef de Projet</role>
<role>Analyste</role>
@@ -42,7 +42,7 @@
<email>chemit(a)codelutin.com</email>
<organization>CodeLutin</organization>
<organizationUrl>http://www.codelutin.com</organizationUrl>
- <timezone>+2</timezone>
+ <timezone>Europe/Paris</timezone>
<roles>
<role>developer</role>
</roles>
@@ -53,7 +53,7 @@
<email>bleny(a)codelutin.com</email>
<organization>CodeLutin</organization>
<organizationUrl>http://www.codelutin.com</organizationUrl>
- <timezone>+2</timezone>
+ <timezone>Europe/Paris</timezone>
<roles>
<role>Développeur</role>
</roles>
@@ -64,7 +64,7 @@
<email>letellier(a)codelutin.com</email>
<organization>CodeLutin</organization>
<organizationUrl>http://www.codelutin.com</organizationUrl>
- <timezone>+2</timezone>
+ <timezone>Europe/Paris</timezone>
<roles>
<role>Développeur</role>
</roles>
@@ -86,9 +86,9 @@
</modules>
<scm>
- <connection>scm:svn:http://svn.forge.codelutin.com/svn/wao/trunk</connection>
- <developerConnection>scm:svn:http://svn.forge.codelutin.com/svn/wao/trunk</developerConnection>
- <url>http://forge.codelutin.com/repositories/browse/wao/trunk</url>
+ <connection>scm:svn:http://svn.codelutin.com/wao/trunk</connection>
+ <developerConnection>scm:svn:https://svn.codelutin.com/wao/trunk</developerConnection>
+ <url>https://forge.codelutin.com/repositories/browse/wao/trunk</url>
</scm>
<properties>
@@ -96,24 +96,24 @@
<license.licenseName>agpl_v3</license.licenseName>
<!-- redmine configuration -->
- <platform>forge.codelutin.com</platform>
+ <platform>codelutin.com</platform>
<projectId>wao</projectId>
<!-- versions -->
- <h2Version>1.3.174</h2Version>
- <struts2Version>2.3.15.3</struts2Version>
- <jqueryPluginVersion>3.6.1</jqueryPluginVersion>
+ <h2Version>1.3.175</h2Version>
+ <struts2Version>2.3.16.1</struts2Version>
+ <jqueryPluginVersion>3.7.0</jqueryPluginVersion>
<bootstrapPluginVersion>1.6.1</bootstrapPluginVersion>
<shiroVersion>1.2.2</shiroVersion>
- <slf4jVersion>1.7.5</slf4jVersion>
+ <slf4jVersion>1.7.6</slf4jVersion>
<hibernateVersion>4.2.8.Final</hibernateVersion>
<mockitoVersion>1.9.5</mockitoVersion>
- <postgresqlDriverVersion>9.3-1100-jdbc41</postgresqlDriverVersion>
+ <postgresqlDriverVersion>9.3-1101-jdbc41</postgresqlDriverVersion>
<commonsEmailVersion>1.3.2</commonsEmailVersion>
- <nuitonWebVersion>1.15-SNAPSHOT</nuitonWebVersion>
+ <nuitonWebVersion>1.16</nuitonWebVersion>
<nuitonI18nVersion>3.0</nuitonI18nVersion>
- <nuitonConfigVersion>3.0-alpha-1</nuitonConfigVersion>
+ <nuitonConfigVersion>3.0-alpha-2</nuitonConfigVersion>
<nuitonCsvVersion>3.0-alpha-3</nuitonCsvVersion>
<nuitonUtilsVersion>3.0-SNAPSHOT</nuitonUtilsVersion>
<eugeneVersion>2.7.3</eugeneVersion>
@@ -128,8 +128,7 @@
<i18n.bundleOutputName>wao</i18n.bundleOutputName>
<!-- Using Java 7 -->
- <maven.compiler.source>1.7</maven.compiler.source>
- <maven.compiler.target>1.7</maven.compiler.target>
+ <javaVersion>1.7</javaVersion>
<signatureArtifactId>java17</signatureArtifactId>
<signatureVersion>1.0</signatureVersion>
</properties>
@@ -137,29 +136,21 @@
<repositories>
<repository>
<id>wao-group</id>
- <name>Wao dependencies</name>
<url>http://nexus.nuiton.org/nexus/content/groups/wao-group/</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
- <id>wao-nexus-repository</id>
- <name>wao-nexus-repository</name>
- <url>http://nexus.nuiton.org/nexus/content/groups/wao</url>
- <snapshots>
- <enabled>true</enabled>
- </snapshots>
- <releases>
- <enabled>true</enabled>
- </releases>
+ <id>wao-group</id>
+ <url>http://nexus.nuiton.org/nexus/content/groups/wao-group</url>
</pluginRepository>
</pluginRepositories>
<!--Distribution-->
<distributionManagement>
<site>
- <id>${platform}</id>
+ <id>doc.${platform}</id>
<url>${our.site.repository}/${projectId}</url>
</site>
</distributionManagement>
1
0
20 Mar '14
Author: bleny
Date: 2014-03-20 17:53:39 +0100 (Thu, 20 Mar 2014)
New Revision: 1733
Url: http://forge.codelutin.com/projects/wao/repository/revisions/1733
Log:
fixes #4496 user login and logout
Added:
trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/administration/InactiveWaoUserException.java
trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/administration/NoRoleAttributedException.java
trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/administration/WrongCredentialsException.java
trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/IndexAction.java
trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/authentication/LogoutAction.java
Modified:
trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/ObsProgram.java
trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/UserProfileImpl.java
trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/UserRole.java
trunk/wao-persistence/src/main/xmi/wao-model.zargo
trunk/wao-services/src/main/java/fr/ifremer/wao/services/AuthenticatedWaoUser.java
trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/administration/WaoUsersService.java
trunk/wao-web/src/main/java/fr/ifremer/wao/web/WaoInterceptor.java
trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/authentication/LoginAction.java
trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/obsmer/SamplingPlanAction.java
trunk/wao-web/src/main/resources/i18n/wao-web_en_GB.properties
trunk/wao-web/src/main/resources/i18n/wao-web_fr_FR.properties
trunk/wao-web/src/main/resources/struts.xml
trunk/wao-web/src/main/webapp/WEB-INF/content/authentication/login.jsp
trunk/wao-web/src/main/webapp/WEB-INF/content/obsmer/sampling-plan.jsp
trunk/wao-web/src/main/webapp/WEB-INF/decorators/layout-login.jsp
trunk/wao-web/src/main/webapp/WEB-INF/decorators/layout.jsp
trunk/wao-web/src/main/webapp/css/wao.css
Modified: trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/ObsProgram.java
===================================================================
--- trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/ObsProgram.java 2014-03-20 10:21:05 UTC (rev 1732)
+++ trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/ObsProgram.java 2014-03-20 16:53:39 UTC (rev 1733)
@@ -62,4 +62,7 @@
return OBSDEB == this;
}
+ public String getI18nKey() {
+ return i18nKey;
+ }
}
Modified: trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/UserProfileImpl.java
===================================================================
--- trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/UserProfileImpl.java 2014-03-20 10:21:05 UTC (rev 1732)
+++ trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/UserProfileImpl.java 2014-03-20 16:53:39 UTC (rev 1733)
@@ -20,22 +20,10 @@
*/
package fr.ifremer.wao.entity;
-import java.util.UUID;
+import com.google.common.base.Objects;
public class UserProfileImpl extends UserProfileAbstract {
- public UserProfileImpl() {
- String newToken = UUID.randomUUID().toString();
- setToken(newToken);
- }
-
- public UserProfileImpl(ObsProgram obsProgram, UserRole userRole, boolean canWrite) {
- this();
- setObsProgram(obsProgram);
- setUserRole(userRole);
- setCanWrite(canWrite);
- }
-
@Override
public UserRole getUserRole() {
return UserRole.valueOf(getUserRoleOrdinal());
@@ -105,36 +93,11 @@
return getObsProgram() == ObsProgram.OBSVENTE;
}
- @Override
- public String getDescription() {
- String role;
- if (getUserRoleOrdinal() == null) {
- role = "<no user role>";
- } else {
- role = getUserRole().getTranslation();
- }
- String program;
- if (getObsProgramOrdinal() == null) {
- program = "<no program>";
- } else {
- program = getObsProgram().toString();
- }
- String readOnly = "";
- if (getCanWrite() == null) {
- program = "<no write access specified>";
- } else if (isReadOnly()) {
- // readOnly = WaoUtils._("wao.business.readOnly");
- throw new UnsupportedOperationException();
- }
-
-// String result = WaoUtils._("wao.business.entity.UserProfile.description",
-// role, program, readOnly);
- throw new UnsupportedOperationException();
-
-// return result;
- }
-
public String toString() {
- return getDescription() + " " + getTopiaId();
+ String toString = Objects.toStringHelper(this)
+ .add("obsProgram", getObsProgram())
+ .add("userRole", getUserRole())
+ .add("readOnly", isReadOnly()).toString();
+ return toString;
}
}
\ No newline at end of file
Modified: trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/UserRole.java
===================================================================
--- trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/UserRole.java 2014-03-20 10:21:05 UTC (rev 1732)
+++ trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/UserRole.java 2014-03-20 16:53:39 UTC (rev 1733)
@@ -66,13 +66,8 @@
throw new IllegalArgumentException("ordinal " + userRoleOrdinal);
}
- // bleny 2011-01-26 calling this method toString make UI unstable.
- // In Administration form, when choosing a role, changing the form value lead to
- // an Enum.valueOf exception. It seems that Tapestry use toString()
- // instead of name() to know witch value is chosen
- public String getTranslation() {
- throw new UnsupportedOperationException();
- // return WaoUtils.t(i18nKey);
+ public String getI18nKey() {
+ return i18nKey;
}
/** for a given program, return the roles that can be assigned by someone
Modified: trunk/wao-persistence/src/main/xmi/wao-model.zargo
===================================================================
(Binary files differ)
Modified: trunk/wao-services/src/main/java/fr/ifremer/wao/services/AuthenticatedWaoUser.java
===================================================================
--- trunk/wao-services/src/main/java/fr/ifremer/wao/services/AuthenticatedWaoUser.java 2014-03-20 10:21:05 UTC (rev 1732)
+++ trunk/wao-services/src/main/java/fr/ifremer/wao/services/AuthenticatedWaoUser.java 2014-03-20 16:53:39 UTC (rev 1733)
@@ -44,7 +44,7 @@
}
public void logout() {
- getCurrentUser().logout();
+ // TODO brendan 20/03/14 getCurrentUser().logout();
}
public boolean isAdmin() {
Added: trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/administration/InactiveWaoUserException.java
===================================================================
--- trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/administration/InactiveWaoUserException.java (rev 0)
+++ trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/administration/InactiveWaoUserException.java 2014-03-20 16:53:39 UTC (rev 1733)
@@ -0,0 +1,17 @@
+package fr.ifremer.wao.services.service.administration;
+
+import fr.ifremer.wao.WaoException;
+import fr.ifremer.wao.entity.WaoUser;
+
+public class InactiveWaoUserException extends WaoException {
+
+ protected WaoUser waoUser;
+
+ public InactiveWaoUserException(WaoUser waoUser) {
+ this.waoUser = waoUser;
+ }
+
+ public WaoUser getWaoUser() {
+ return waoUser;
+ }
+}
Added: trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/administration/NoRoleAttributedException.java
===================================================================
--- trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/administration/NoRoleAttributedException.java (rev 0)
+++ trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/administration/NoRoleAttributedException.java 2014-03-20 16:53:39 UTC (rev 1733)
@@ -0,0 +1,17 @@
+package fr.ifremer.wao.services.service.administration;
+
+import fr.ifremer.wao.WaoException;
+import fr.ifremer.wao.entity.WaoUser;
+
+public class NoRoleAttributedException extends WaoException {
+
+ protected WaoUser waoUser;
+
+ public NoRoleAttributedException(WaoUser waoUser) {
+ this.waoUser = waoUser;
+ }
+
+ public WaoUser getWaoUser() {
+ return waoUser;
+ }
+}
Modified: trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/administration/WaoUsersService.java
===================================================================
--- trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/administration/WaoUsersService.java 2014-03-20 10:21:05 UTC (rev 1732)
+++ trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/administration/WaoUsersService.java 2014-03-20 16:53:39 UTC (rev 1733)
@@ -18,6 +18,8 @@
import fr.ifremer.wao.services.service.mail.UserCredentialsEmail;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
import org.nuiton.topia.persistence.TopiaEntities;
import org.nuiton.topia.persistence.TopiaEntity;
import org.nuiton.topia.persistence.TopiaQueryBuilderAddCriteriaOrRunQueryStep;
@@ -28,6 +30,8 @@
public class WaoUsersService extends WaoServiceSupport {
+ private static final Log log = LogFactory.getLog(WaoUsersService.class);
+
public List<WaoUser> getWaoUsers(Optional<String> optionalCompanyId) {
WaoUserTopiaDao dao = getWaoUserDao();
@@ -207,4 +211,53 @@
}
+ public WaoUser authenticate(String login, String clearPassword)
+ throws WrongCredentialsException, NoRoleAttributedException, InactiveWaoUserException {
+
+ WaoUserTopiaDao dao = getWaoUserDao();
+
+ Optional<WaoUser> optionalWaoUser = dao.forLoginEquals(login).tryFindUnique();
+
+ WaoUser waoUser;
+
+ if ( ! optionalWaoUser.isPresent()) {
+ if (log.isInfoEnabled()) {
+ log.info("no such user " + login);
+ }
+ throw new WrongCredentialsException();
+ }
+
+ waoUser = optionalWaoUser.get();
+ String hashedPassword = StringUtil.encodeMD5(clearPassword);
+
+ if ( ! waoUser.getPassword().equals(hashedPassword)) {
+ if (log.isWarnEnabled()) {
+ log.warn("wrong credentials provided for " + login);
+ }
+ throw new WrongCredentialsException();
+ }
+
+ if ( ! waoUser.isActive()) {
+ throw new InactiveWaoUserException(waoUser);
+ }
+
+ if (waoUser.isUserProfileEmpty()) {
+ throw new NoRoleAttributedException(waoUser);
+ }
+
+ waoUser.sizeUserProfile();
+ waoUser.sizeCanReadBoats();
+ waoUser.getCompany().getTopiaId();
+
+ return waoUser;
+
+ }
+
+ public void acceptCgu(WaoUser waoUser) {
+
+ waoUser.setCguAccepted(serviceContext.getNow());
+
+ commit();
+
+ }
}
Added: trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/administration/WrongCredentialsException.java
===================================================================
--- trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/administration/WrongCredentialsException.java (rev 0)
+++ trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/administration/WrongCredentialsException.java 2014-03-20 16:53:39 UTC (rev 1733)
@@ -0,0 +1,7 @@
+package fr.ifremer.wao.services.service.administration;
+
+import fr.ifremer.wao.WaoException;
+
+public class WrongCredentialsException extends WaoException {
+
+}
Modified: trunk/wao-web/src/main/java/fr/ifremer/wao/web/WaoInterceptor.java
===================================================================
--- trunk/wao-web/src/main/java/fr/ifremer/wao/web/WaoInterceptor.java 2014-03-20 10:21:05 UTC (rev 1732)
+++ trunk/wao-web/src/main/java/fr/ifremer/wao/web/WaoInterceptor.java 2014-03-20 16:53:39 UTC (rev 1733)
@@ -1,6 +1,7 @@
package fr.ifremer.wao.web;
import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableSet;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;
import fr.ifremer.wao.WaoApplicationConfig;
@@ -13,6 +14,7 @@
import fr.ifremer.wao.services.AuthenticatedWaoUser;
import fr.ifremer.wao.services.WaoService;
import fr.ifremer.wao.services.WaoServiceContext;
+import fr.ifremer.wao.web.action.authentication.LoginAction;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -26,6 +28,9 @@
private static final Log log = LogFactory.getLog(WaoInterceptor.class);
+ protected static final ImmutableSet<Class<LoginAction>> ACTIONS_ACCESSIBLE_WITHOUT_LOGIN =
+ ImmutableSet.of(LoginAction.class);
+
public static final String SESSION_LAST_LOCATION = "lastLocation";
@Override
@@ -53,17 +58,26 @@
WaoSession waoSession = getWaoSession(invocation);
if (waoSession.getAuthenticatedWaoUser() == null) {
- // login à l'arrache
- WaoUser admin = serviceContext.getPersistenceContext().getWaoUserDao().forLoginEquals("admin").findUnique();
- admin.sizeUserProfile();
- admin.sizeCanReadBoats();
- admin.getCompany().getTopiaId();
- UserProfile userProfile = new UserProfileImpl();
- userProfile.setUserRole(UserRole.ADMIN);
- userProfile.setObsProgram(ObsProgram.OBSMER);
- userProfile.setCanWrite(true);
- AuthenticatedWaoUser authenticatedWaoUser = new AuthenticatedWaoUser(admin, userProfile);
- waoSession.setAuthenticatedWaoUser(authenticatedWaoUser);
+
+ boolean loginCheat = false;
+ if (loginCheat) {
+ // login à l'arrache
+ WaoUser admin = serviceContext.getPersistenceContext().getWaoUserDao().forLoginEquals("admin").findUnique();
+ admin.sizeUserProfile();
+ admin.sizeCanReadBoats();
+ admin.getCompany().getTopiaId();
+ UserProfile userProfile = new UserProfileImpl();
+ userProfile.setUserRole(UserRole.ADMIN);
+ userProfile.setObsProgram(ObsProgram.OBSMER);
+ userProfile.setCanWrite(true);
+ AuthenticatedWaoUser authenticatedWaoUser = new AuthenticatedWaoUser(admin, userProfile);
+ waoSession.setAuthenticatedWaoUser(authenticatedWaoUser);
+ } else {
+ if ( ! ACTIONS_ACCESSIBLE_WITHOUT_LOGIN.contains(waoAction.getClass())) {
+ return "redirect-to-login";
+ }
+ }
+
}
if (CollectionUtils.isNotEmpty(waoSession.getMessages())) {
Added: trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/IndexAction.java
===================================================================
--- trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/IndexAction.java (rev 0)
+++ trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/IndexAction.java 2014-03-20 16:53:39 UTC (rev 1733)
@@ -0,0 +1,31 @@
+package fr.ifremer.wao.web.action;
+
+import fr.ifremer.wao.entity.ObsProgram;
+import fr.ifremer.wao.web.WaoJspActionSupport;
+import org.apache.struts2.convention.annotation.Result;
+import org.apache.struts2.convention.annotation.Results;
+
+@Results({
+ @Result(name="error", type="redirectAction", params = { "namespace", "/authentication", "actionName", "login!input" }),
+ @Result(name="success", type="redirectAction", params = { "namespace", "/${obsProgram.name().toLowerCase()}", "actionName", "news" })
+})
+public class IndexAction extends WaoJspActionSupport {
+
+ protected ObsProgram obsProgram;
+
+ @Override
+ public String execute() {
+
+ if (getSession().getAuthenticatedWaoUser() == null) {
+ return ERROR;
+ } else {
+ obsProgram = getSession().getAuthenticatedWaoUser().getObsProgram();
+ return SUCCESS;
+ }
+
+ }
+
+ public ObsProgram getObsProgram() {
+ return obsProgram;
+ }
+}
Modified: trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/authentication/LoginAction.java
===================================================================
--- trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/authentication/LoginAction.java 2014-03-20 10:21:05 UTC (rev 1732)
+++ trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/authentication/LoginAction.java 2014-03-20 16:53:39 UTC (rev 1733)
@@ -1,12 +1,157 @@
package fr.ifremer.wao.web.action.authentication;
+import com.google.common.collect.Iterables;
+import fr.ifremer.wao.entity.ObsProgram;
+import fr.ifremer.wao.entity.UserProfile;
+import fr.ifremer.wao.entity.WaoUser;
+import fr.ifremer.wao.services.AuthenticatedWaoUser;
+import fr.ifremer.wao.services.service.administration.InactiveWaoUserException;
+import fr.ifremer.wao.services.service.administration.NoRoleAttributedException;
+import fr.ifremer.wao.services.service.administration.WaoUsersService;
+import fr.ifremer.wao.services.service.administration.WrongCredentialsException;
import fr.ifremer.wao.web.WaoJspActionSupport;
+import org.apache.commons.lang3.BooleanUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.struts2.convention.annotation.Result;
+import org.apache.struts2.convention.annotation.Results;
+import java.util.HashMap;
+import java.util.Map;
+
+@Results({
+ @Result(name="success", type="redirectAction", params = { "namespace", "/${obsProgram.name().toLowerCase()}", "actionName", "news" })
+})
public class LoginAction extends WaoJspActionSupport {
+ protected WaoUsersService service;
+
+ protected String login;
+
+ protected String password;
+
+ protected String userProfileId;
+
+ protected boolean userProfileAsked;
+
+ protected Map<String, String> userProfiles;
+
+ protected boolean acceptCguAsked;
+
+ protected boolean cguAccepted;
+
+ protected ObsProgram obsProgram;
+
+ protected WaoUser waoUser;
+
+ public void setLogin(String login) {
+ this.login = login;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public void setService(WaoUsersService service) {
+ this.service = service;
+ }
+
+ public void setUserProfileId(String userProfileId) {
+ this.userProfileId = userProfileId;
+ }
+
+ public void setCguAccepted(boolean cguAccepted) {
+ this.cguAccepted = cguAccepted;
+ }
+
@Override
+ public void validate() {
+
+ try {
+
+ waoUser = service.authenticate(login, password);
+
+ if (cguAccepted) {
+ service.acceptCgu(waoUser);
+ }
+
+ if (waoUser.getCguAccepted() == null) {
+ acceptCguAsked = true;
+ addFieldError("cguAccepted", t("wao.ui.form.authentication.error.userMustAcceptCgu"));
+ }
+
+ if (waoUser.getUserProfile().size() == 1) {
+ userProfileId = Iterables.getOnlyElement(waoUser.getUserProfile()).getTopiaId();
+ } else {
+ userProfileAsked = true;
+ userProfiles = new HashMap<>();
+ for (UserProfile userProfile : waoUser.getUserProfile()) {
+ String label = t(userProfile.getUserRole().getI18nKey());
+ label += " " + t(userProfile.getObsProgram().getI18nKey());
+ if (BooleanUtils.isTrue(userProfile.isReadOnly())) {
+ label += " (" + t("wao.ui.form.readOnly") + ")";
+ }
+ userProfiles.put(userProfile.getTopiaId(), label);
+ }
+ }
+
+ } catch (WrongCredentialsException e) {
+ addFieldError("login", t("wao.ui.form.authentication.error.wrongCredentials"));
+ } catch (NoRoleAttributedException e) {
+ addFieldError("login", t("wao.ui.form.authentication.error.noRoleAttributed"));
+ } catch (InactiveWaoUserException e) {
+ addFieldError("login", t("wao.ui.form.authentication.error.inactiveWaoUser"));
+ }
+
+ }
+
+ @Override
public String execute() {
+
+ if (StringUtils.isNotBlank(userProfileId)) {
+
+ UserProfile userProfile = waoUser.getUserProfileByTopiaId(userProfileId);
+ AuthenticatedWaoUser authenticatedWaoUser = new AuthenticatedWaoUser(waoUser, userProfile);
+ session.setAuthenticatedWaoUser(authenticatedWaoUser);
+
+ obsProgram = userProfile.getObsProgram();
+
+ return SUCCESS;
+
+ }
+
return INPUT;
+
}
+ public String getPassword() {
+ return password;
+ }
+
+ public String getLogin() {
+ return login;
+ }
+
+ public String getUserProfileId() {
+ return userProfileId;
+ }
+
+ public boolean isUserProfileAsked() {
+ return userProfileAsked;
+ }
+
+ public ObsProgram getObsProgram() {
+ return obsProgram;
+ }
+
+ public boolean isAcceptCguAsked() {
+ return acceptCguAsked;
+ }
+
+ public boolean isCguAccepted() {
+ return cguAccepted;
+ }
+
+ public Map<String, String> getUserProfiles() {
+ return userProfiles;
+ }
}
Added: trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/authentication/LogoutAction.java
===================================================================
--- trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/authentication/LogoutAction.java (rev 0)
+++ trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/authentication/LogoutAction.java 2014-03-20 16:53:39 UTC (rev 1733)
@@ -0,0 +1,20 @@
+package fr.ifremer.wao.web.action.authentication;
+
+import fr.ifremer.wao.web.WaoJspActionSupport;
+import org.apache.struts2.convention.annotation.Result;
+import org.apache.struts2.convention.annotation.Results;
+
+@Results({
+ @Result(name="success", type="redirectAction", params = { "actionName", "login!input" })
+})
+public class LogoutAction extends WaoJspActionSupport {
+
+ @Override
+ public String execute() {
+
+ session.logout();
+
+ return SUCCESS;
+
+ }
+}
Modified: trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/obsmer/SamplingPlanAction.java
===================================================================
--- trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/obsmer/SamplingPlanAction.java 2014-03-20 10:21:05 UTC (rev 1732)
+++ trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/obsmer/SamplingPlanAction.java 2014-03-20 16:53:39 UTC (rev 1733)
@@ -22,9 +22,6 @@
SampleRowsFilter filter = service.newSampleRowsFilter(getAuthenticatedWaoUser());
- filter.setPeriodFrom(null);
- filter.setPeriodTo(null);
-
samplingPlan = service.getSamplingPlan(filter);
return SUCCESS;
Modified: trunk/wao-web/src/main/resources/i18n/wao-web_en_GB.properties
===================================================================
--- trunk/wao-web/src/main/resources/i18n/wao-web_en_GB.properties 2014-03-20 10:21:05 UTC (rev 1732)
+++ trunk/wao-web/src/main/resources/i18n/wao-web_en_GB.properties 2014-03-20 16:53:39 UTC (rev 1733)
@@ -234,6 +234,14 @@
wao.ui.form.addComment=Add a comment
wao.ui.form.addComment.success=Comment saved
wao.ui.form.addRole=Add this ru00F4le
+wao.ui.form.authentication.acceptCgu=
+wao.ui.form.authentication.action.submit=Login
+wao.ui.form.authentication.chooseUserProfile=
+wao.ui.form.authentication.error.inactiveWaoUser=This wao user is not active. Please, contact an administrator
+wao.ui.form.authentication.error.noRoleAttributed=This wao user has no role affected. Please, contact an administrator
+wao.ui.form.authentication.error.userMustAcceptCgu=You must accept the end-user agreement
+wao.ui.form.authentication.error.wrongCredentials=Incorrect credentials
+wao.ui.form.authentication.title=WAO authentication
wao.ui.form.boardingFrom=Boardings since
wao.ui.form.contactsFile=Contacts file
wao.ui.form.definePasswordManually=Define password manually
Modified: trunk/wao-web/src/main/resources/i18n/wao-web_fr_FR.properties
===================================================================
--- trunk/wao-web/src/main/resources/i18n/wao-web_fr_FR.properties 2014-03-20 10:21:05 UTC (rev 1732)
+++ trunk/wao-web/src/main/resources/i18n/wao-web_fr_FR.properties 2014-03-20 16:53:39 UTC (rev 1733)
@@ -234,6 +234,14 @@
wao.ui.form.addComment=Ajouter un commentaire
wao.ui.form.addComment.success=Commentaire enregistré
wao.ui.form.addRole=Ajouter ce rôle
+wao.ui.form.authentication.acceptCgu=Vous acceptez les CGU
+wao.ui.form.authentication.action.submit=S'identifier
+wao.ui.form.authentication.chooseUserProfile=Rôle
+wao.ui.form.authentication.error.inactiveWaoUser=Ce compte est inactif, veuillez contacter un responsable
+wao.ui.form.authentication.error.noRoleAttributed=Aucun rôle n'est attribué à ce compte, veuillez contacter un responsable
+wao.ui.form.authentication.error.userMustAcceptCgu=Vous devez accepter les conditions générales d'utilisation
+wao.ui.form.authentication.error.wrongCredentials=Les informations d'authenfication ne sont pas correctes
+wao.ui.form.authentication.title=Identification WAO
wao.ui.form.boardingFrom=Sollicitations du navire depuis le
wao.ui.form.contactsFile=Fichier des contacts
wao.ui.form.definePasswordManually=définir manuellement
Modified: trunk/wao-web/src/main/resources/struts.xml
===================================================================
--- trunk/wao-web/src/main/resources/struts.xml 2014-03-20 10:21:05 UTC (rev 1732)
+++ trunk/wao-web/src/main/resources/struts.xml 2014-03-20 16:53:39 UTC (rev 1733)
@@ -52,6 +52,12 @@
<default-interceptor-ref name="waoStack"/>
+ <global-results>
+ <result name="redirect-to-login" type="redirect">
+ /authentication/login!input
+ </result>
+ </global-results>
+
</package>
Modified: trunk/wao-web/src/main/webapp/WEB-INF/content/authentication/login.jsp
===================================================================
--- trunk/wao-web/src/main/webapp/WEB-INF/content/authentication/login.jsp 2014-03-20 10:21:05 UTC (rev 1732)
+++ trunk/wao-web/src/main/webapp/WEB-INF/content/authentication/login.jsp 2014-03-20 16:53:39 UTC (rev 1733)
@@ -1,28 +1,90 @@
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
-<!DOCTYPE html>
-<%@taglib uri="/struts-tags" prefix="s" %>
-<%@taglib prefix="sj" uri="/struts-jquery-tags" %>
+<%@taglib prefix="s" uri="/struts-tags" %>
+<%@taglib prefix="sj" uri="/struts-jquery-tags" %>
+
<html>
<head>
- <title>Identification</title>
+ <title>
+ <s:text name="wao.ui.form.authentication.title" />
+ </title>
</head>
<body>
- <p>Veuillez entrer vos identifiants pour accéder à votre espace</p>
+ <h1>
+ <s:text name="wao.ui.form.authentication.title" />
+ </h1>
- <s:form action="login" namespace="/authentication" method="post" cssClass="form-horizontal">
+ <s:form action="login" namespace="/authentication" method="POST" cssClass="form-horizontal">
- <s:textfield name="email"
- label="Votre adresse de courrier électronique :"/>
+ <fieldset>
- <s:password name="password"
- label="Votre mot de passe :"/>
+ <s:textfield name="login"
+ label="%{getText('wao.ui.field.WaoUser.login')}" />
- <sj:a openDialog="forgottenPasswordForm" cssClass="controls">J'ai oublié mon mot de passe</sj:a>
+ <s:password name="password"
+ label="%{getText('wao.ui.field.WaoUser.password')}" />
- <s:submit value="S'identifier" type='button' cssClass="btn btn-primary"/>
+ <s:if test="userProfileAsked">
+ <s:radio name="userProfileId" list="userProfiles" label="%{getText('wao.ui.form.authentication.chooseUserProfile')}" />
+
+ </s:if>
+
+ <s:if test="acceptCguAsked">
+
+ <s:checkbox name="cguAccepted" label="%{getText('wao.ui.form.authentication.acceptCgu')}" />
+
+ </s:if>
+
+ </fieldset>
+
+ <s:submit type="button" cssClass="btn btn-primary">
+ <s:text name="wao.ui.form.authentication.action.submit" />
+ </s:submit>
+
</s:form>
+ <s:if test="acceptCguAsked">
+
+ <article id="cgu">
+ <h2>CONDITIONS D’UTILISATION DU PORTAIL WAO (web applicatif obsmer)</h2>
+ <p>La base de données WAO est accessible via l’adresse internet suivante : http://www.ifremer.fr/wao/ (le « Portail »).</p>
+ <p>Les données et informations qui composent le Portail, quelle que soit leur forme, et notamment mais non exclusivement, les données nominatives et techniques, (ci-après communément et indistinctement désignées sous le terme « Données»), sont soumises aux présentes conditions d’utilisation.</p>
+ <p>Le titulaire (le « Titulaire ») du log in et du mot de passe accepte expressément et sans réserve les présentes conditions d’utilisation par le simple fait d’utiliser le log in et le mot de passe et d’accéder aux Données.</p>
+ <p>Le log in et le mot de passe sont strictement personnels et confidentiels. Ils ne peuvent être communiqués à un tiers sans l’accord préalable, exprès et écrit de la direction des pêches maritimes et de l’aquaculture (DPMA) et de l’Institut français de recherche pour l’exploitation de la mer (IFREMER). Sauf accord préalable et exprès de la DPMA et de l’IFREMER, seul le Titulaire est fondé à accéder aux Données, à l’exclusion de toute autre personne..</p>
+ <h3>ARTICLE 1 – PROPRIETE DES DONNEES</h3>
+ <p>Les Données sont la propriété exclusive de la DPMA et de l’IFREMER.</p>
+ <p>La divulgation des Données au Titulaire ne saurait, en aucun cas, être interprétée comme lui conférant, de manière expresse ou implicite un droit quelconque sur ces Donnéesappartenant conjointement à la DPMA et/ou à l’IFREMER.</p>
+ <h3>ARTICLE 2 – CONDITION D’UTILISATION DES DONNEES</h3>
+ <p>Les Données ne pourront être consultées et utilisées que dans le cadre du programme Obsmer (le « Programme Obsmer ») et dans les strictes limites suivantes :</p>
+ <p>Appui des observateurs des bureaux d’études mandatés par le MAAPRAT auprès des professionnels susceptibles d’embarquer un observateur scientifique</p>
+ <p>Appui auprès des professionnels pour la mise en conformité vis-à-vis des obligations administratives nécessaires pour l’embarquement d’un observateur scientifique (note de service DPMA/DAM 2307 du 20 octobre 2008)</p>
+ <p>Les Données consultables par le Titulaire sont strictement dédiées au Programme Obsmer de sorte qu’en dehors de la DPMA, de l’IFREMER, des bureaux d’étude en charge de la réalisation du Programme Obsmer et du Titulaire, aucune autre personne n’a accès aux Données.</p>
+ <p>Par conséquent, en cas de constat d’une utilisation des Données dans un domaine autre que le Programme Obsmer, la DPMA et l’IFREMER se réservent le droit de suspendre, sans formalité préalable, le log in et le mot de passe du Titulaire.</p>
+ <p>Cette suspension est non exclusive d’éventuelles actions destinées à réparer le préjudice subi par la DPMA et l’IFREMER.</p>
+ <p>Les Parties conviennent d’ores et déjà qu’en cas de contestation ou de litige, les données de connexion feront foi.</p>
+ <h3>ARTICLE 3 - INTERDICTION D’EXTRACTION OU DE DUPPLICATION DES DONNEES EN DEHORS DU PROGRAMME OBSMER</h3>
+ <p>Sauf dans le cadre du Programme Obsmer et dans les conditions de l’article 2 des présentes conditions d’utilisation des Données, le Titulaire ne pourra en aucun cas procéder à une extraction ou duplication des Données sans autorisation écrite et préalable de la DPMA et de l’IFREMER.</p>
+ <p>Le Titulaire s’interdit également de communiquer, revendre tout ou partie des Données auxquelles il a accès via le Portail.</p>
+ <p>A ce titre, le Titulaire ne procédera pas, notamment, à des copier / coller et / ou toute autre action ayant pour effet de permettre l’extraction ou la duplication de tout ou partie des Données.</p>
+ <h3>ARTICLE 4 – PERTE DU LOG IN ET DU MOT DE PASSE</h3>
+ <p>En cas de perte du log in et / ou du mot de passe, le Titulaire s’engage à prévenir la DPMA et l’IFREMER dans les plus brefs délais afin que ceux-ci soient désactivés. Il sera attribué au Titulaire un nouveau log in et un nouveau mot de passe.</p>
+ <h3>ARTICLE 5 - INFORMATIQUES ET LIBERTES</h3>
+ <p>Certaines des Données sont des données à caractère personnel ayant fait l’objet d’une déclaration auprès de la Commission National Informatique et Libertés.</p>
+ <p>Le Titulaire consulte et utilise les Données dans le respect de la loi n°78-17 du 6 janvier 1978 modifiée dite loi Informatique et Libertés.</p>
+ <h3>ARTICLE 6 - CONFIDENTIALITE</h3>
+ <p>Le Titulaire gardera confidentiel les Données qu’il consultera.</p>
+ <p>Le Titulaire traitera les Données avec le même degré de précaution et de protection que celui qu’il accorde à ses propres informations confidentielles de même importance.</p>
+ <p>Le Titulaire conservera de manière confidentielle, pour une durée de trente (30) ans à compter de la dernière consultation du Portail, les Données disponibles depuis la base de données WAO et s'abstiendra de les divulguer sauf à des employés ou à des préposés responsables qui, astreints au secret professionnel, en auront besoin pour l’accomplissement de leur mission au titre du Programme Obsmer.</p>
+ <p>Le Titulaire informera par écrit la DPMA et l’IFREMER de toute perte de document ou d’objet contenant des Données.</p>
+ <p>La DPMA et l’IFREMER pourront exiger, à tout moment et sous quelque forme que ce soit, que tous les documents portant des Données soient impérativement restitués ou détruits par le Titulaire.</p>
+ <h3>ARTICLE 7 - LIMITATION DE RESPONSABILITE</h3>
+ <p>La DPMA et l’IFREMER ne garantissent en rien que les Données seront exempts d’erreurs. Par conséquent, la DPMA et l’IFREMER déclinent toute responsabilité quant à l’utilisation qui en est faite et qui s’effectue sous la seule, pleine et entière responsabilité du Titulaire.</p>
+ <p>Par conséquent, le Titulaire ne pourra en aucun cas mettre en cause la responsabilité de la DPMA et de l’IFREMER en raison d’un préjudice subi par le Titulaire du fait de l’utilisation des Données, quel qu’il soit et quel qu’en soit la cause, que le préjudice ait été prévisible ou non.</p>
+ <p>En outre, la DPMA et l’IFREMER déclinent toute responsabilité sur l’utilisation du site internet et ne garantissent en rien que le site soit exempt de virus, bugs…</p>
+ </article>
+
+ </s:if>
+
</body>
</html>
Modified: trunk/wao-web/src/main/webapp/WEB-INF/content/obsmer/sampling-plan.jsp
===================================================================
--- trunk/wao-web/src/main/webapp/WEB-INF/content/obsmer/sampling-plan.jsp 2014-03-20 10:21:05 UTC (rev 1732)
+++ trunk/wao-web/src/main/webapp/WEB-INF/content/obsmer/sampling-plan.jsp 2014-03-20 16:53:39 UTC (rev 1733)
@@ -18,6 +18,13 @@
<i class="icon-download"></i> <s:text name="wao.ui.action.csvExport" />
</s:a>
+ <s:if test="authenticatedWaoUser.authorizedToEditSamplingPlan">
+ <s:url action="edit-sample-row!input" id="createSampleRow" />
+ <s:a href="%{createSampleRow}" cssClass="btn">
+ <i class="icon-plus"></i> <s:text name="wao.ui.action.createSampleRow" />
+ </s:a>
+ </s:if>
+
<table class="large-table table-hover">
<thead>
<th>
@@ -102,11 +109,4 @@
</tfoot>
</table>
- <s:if test="authenticatedWaoUser.authorizedToEditSamplingPlan">
- <s:url action="edit-sample-row!input" id="createSampleRow" />
- <s:a href="%{createSampleRow}">
- <i class="icon-plus"></i> <s:text name="wao.ui.action.createSampleRow" />
- </s:a>
- </s:if>
-
</html>
Modified: trunk/wao-web/src/main/webapp/WEB-INF/decorators/layout-login.jsp
===================================================================
--- trunk/wao-web/src/main/webapp/WEB-INF/decorators/layout-login.jsp 2014-03-20 10:21:05 UTC (rev 1732)
+++ trunk/wao-web/src/main/webapp/WEB-INF/decorators/layout-login.jsp 2014-03-20 16:53:39 UTC (rev 1733)
@@ -21,66 +21,12 @@
<body>
- <content>
+ <main>
<s:actionerror theme="bootstrap" />
<s:actionmessage theme="bootstrap" />
<s:fielderror theme="bootstrap" />
<decorator:body />
- </content>
+ </main>
- <footer class="hidden-print<s:if test="%{instanceDisclaimer != null}"> disclaimer-displayed</s:if>" >
- <ul>
- <li>
- <a href="http://maven-site.forge.codelutin.com/wao/" target="_blank">
- WAO
- </a>
- </li>
- <li>
- <a href="http://forge.codelutin.com/projects/wao/news" target="_blank">
- <%@include file="version.jsp" %>
- </a>
- </li>
- <t:if test="connectedUser.obsMer">
- <li>
- <a href="mailto:harmonie@ifremer.fr" title="Contacter un responsable Obsmer">
- Obsmer
- </a>
- </li>
- </t:if>
- <li>
- <a href="http://sih.ifremer.fr/" title="Page d'accueil du SIH" target="_blank">
- Ifremer SIH
- </a>
- </li>
- <li>
- <a href="http://www.gnu.org/licenses/agpl.html" title="License AGPL v3" target="_blank">
- AGPLv3
- </a>
- </li>
- <li>
- Copyright 2009-${currentYear}
- <a href="http://www.ifremer.fr" title="Ifremer" target="_blank">
- Ifremer
- </a>,
- <a href="http://www.codelutin.com" title="Code Lutin" target="_blank">
- Code Lutin
- </a>
- </li>
- </ul>
- <s:if test="obsMer">
- <p class="cnil">
- ${message:wao.ui.disclaimer}
- </p>
- </s:if>
- </footer>
-
- <s:if test="%{instanceDisclaimer != null}">
- <div id="instance-disclaimer">
- <div>
- <s:property value="instanceDisclaimer" />
- </div>
- </div>
- </s:if>
-
</body>
</html>
Modified: trunk/wao-web/src/main/webapp/WEB-INF/decorators/layout.jsp
===================================================================
--- trunk/wao-web/src/main/webapp/WEB-INF/decorators/layout.jsp 2014-03-20 10:21:05 UTC (rev 1732)
+++ trunk/wao-web/src/main/webapp/WEB-INF/decorators/layout.jsp 2014-03-20 16:53:39 UTC (rev 1733)
@@ -132,7 +132,10 @@
</s:a>
</li>
<li>
- <a href="#"><i class="icon-off"></i> <s:text name="wao.ui.action.logout" /></a>
+ <s:url namespace="/authentication" action="logout" id="logoutUrl" />
+ <s:a href="%{logoutUrl}">
+ <i class="icon-off"></i> <s:text name="wao.ui.action.logout" />
+ </s:a>
</li>
</ul>
</li>
Modified: trunk/wao-web/src/main/webapp/css/wao.css
===================================================================
--- trunk/wao-web/src/main/webapp/css/wao.css 2014-03-20 10:21:05 UTC (rev 1732)
+++ trunk/wao-web/src/main/webapp/css/wao.css 2014-03-20 16:53:39 UTC (rev 1733)
@@ -74,7 +74,7 @@
list-style-type: none;
}
-.large-table tr:hover {
+.large-table tbody tr:hover {
background-color: #f5f5f5;
}
@@ -98,3 +98,15 @@
text-align: right;
}
+form#login button[type="submit"] {
+ margin-left: 180px;
+}
+
+#cgu {
+ overflow-y: auto;
+ max-height: 300px;
+ padding: 5px;
+ border: solid 5px #f2f2f2;
+ margin-bottom: 20px;
+}
+
1
0
r1732 - in trunk: wao-services/src/main/java/fr/ifremer/wao/services/service/csv/operations wao-web/src/main/java/fr/ifremer/wao/web/action wao-web/src/main/java/fr/ifremer/wao/web/action/obsmer wao-web/src/main/resources/i18n wao-web/src/main/webapp/WEB-INF/content/obsmer
by bleny@users.forge.codelutin.com 20 Mar '14
by bleny@users.forge.codelutin.com 20 Mar '14
20 Mar '14
Author: bleny
Date: 2014-03-20 11:21:05 +0100 (Thu, 20 Mar 2014)
New Revision: 1732
Url: http://forge.codelutin.com/projects/wao/repository/revisions/1732
Log:
refs #4483 add export sampling plan ui
Added:
trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/AbstractDownloadCsvAction.java
trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/obsmer/ExportSamplingPlanAction.java
Modified:
trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/csv/operations/DCF5CodesParserFormatter.java
trunk/wao-web/src/main/resources/i18n/wao-web_en_GB.properties
trunk/wao-web/src/main/resources/i18n/wao-web_fr_FR.properties
trunk/wao-web/src/main/webapp/WEB-INF/content/obsmer/sampling-plan.jsp
Modified: trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/csv/operations/DCF5CodesParserFormatter.java
===================================================================
--- trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/csv/operations/DCF5CodesParserFormatter.java 2014-03-20 09:06:44 UTC (rev 1731)
+++ trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/csv/operations/DCF5CodesParserFormatter.java 2014-03-20 10:21:05 UTC (rev 1732)
@@ -57,6 +57,7 @@
@Override
public List<DCF5Code> parse(String codes) {
+ // FIXME brendan 20/03/14 la gestion d'exception fait qu'on a pas le message d'erreur dans l'UI
try {
Collection<DCF5Code> dcf5Codes = referentialService.getDcf5Codes(codes);
List<DCF5Code> value = new ArrayList<>(dcf5Codes);
Added: trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/AbstractDownloadCsvAction.java
===================================================================
--- trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/AbstractDownloadCsvAction.java (rev 0)
+++ trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/AbstractDownloadCsvAction.java 2014-03-20 10:21:05 UTC (rev 1732)
@@ -0,0 +1,26 @@
+package fr.ifremer.wao.web.action;
+
+import fr.ifremer.wao.web.WaoJspActionSupport;
+import org.apache.struts2.convention.annotation.Result;
+
+import java.io.InputStream;
+import java.text.SimpleDateFormat;
+
+@Result(
+ name="success",
+ type="stream",
+ params = {
+ "contentType", "text/csv",
+ "inputName", "inputStream",
+ "contentDisposition", "attachment;filename=${fileName}"
+ }
+)
+public abstract class AbstractDownloadCsvAction extends WaoJspActionSupport {
+
+ protected SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-dd-MM_HHhmm");
+
+ public abstract String getFileName();
+
+ public abstract InputStream getInputStream();
+
+}
Added: trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/obsmer/ExportSamplingPlanAction.java
===================================================================
--- trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/obsmer/ExportSamplingPlanAction.java (rev 0)
+++ trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/obsmer/ExportSamplingPlanAction.java 2014-03-20 10:21:05 UTC (rev 1732)
@@ -0,0 +1,49 @@
+package fr.ifremer.wao.web.action.obsmer;
+
+import com.opensymphony.xwork2.Preparable;
+import fr.ifremer.wao.SampleRowsFilter;
+import fr.ifremer.wao.services.service.ObsMerSamplingPlanService;
+import fr.ifremer.wao.web.action.AbstractDownloadCsvAction;
+
+import java.io.InputStream;
+import java.util.Date;
+
+public class ExportSamplingPlanAction extends AbstractDownloadCsvAction implements Preparable {
+
+ protected ObsMerSamplingPlanService service;
+
+ protected SampleRowsFilter filter;
+
+ public void setService(ObsMerSamplingPlanService service) {
+ this.service = service;
+ }
+
+ public SampleRowsFilter getFilter() {
+ if (filter == null) {
+ prepare();
+ }
+ return filter;
+ }
+
+ @Override
+ public void prepare() {
+
+ filter = service.newSampleRowsFilter(getAuthenticatedWaoUser());
+
+ }
+
+ @Override
+ public String getFileName() {
+
+ return "plan_" + getObsProgram().name() + "_" + dateFormat.format(new Date()) + ".csv";
+
+ }
+
+ @Override
+ public InputStream getInputStream() {
+
+ return service.exportSamplingPlan(filter);
+
+ }
+
+}
Modified: trunk/wao-web/src/main/resources/i18n/wao-web_en_GB.properties
===================================================================
--- trunk/wao-web/src/main/resources/i18n/wao-web_en_GB.properties 2014-03-20 09:06:44 UTC (rev 1731)
+++ trunk/wao-web/src/main/resources/i18n/wao-web_en_GB.properties 2014-03-20 10:21:05 UTC (rev 1732)
@@ -31,6 +31,7 @@
wao.ui.action.createNews.success=News created
wao.ui.action.createSampleRow=Add a sample row to the plan
wao.ui.action.createWaoUser=Create a user
+wao.ui.action.csvExport=Export as CSV
wao.ui.action.delete=Delete
wao.ui.action.deleteCompany=Delete company
wao.ui.action.deleteCompany.confirm=Are you sure you want to delete this company ?
Modified: trunk/wao-web/src/main/resources/i18n/wao-web_fr_FR.properties
===================================================================
--- trunk/wao-web/src/main/resources/i18n/wao-web_fr_FR.properties 2014-03-20 09:06:44 UTC (rev 1731)
+++ trunk/wao-web/src/main/resources/i18n/wao-web_fr_FR.properties 2014-03-20 10:21:05 UTC (rev 1732)
@@ -31,6 +31,7 @@
wao.ui.action.createNews.success=Actualité enregistrée avec succès
wao.ui.action.createSampleRow=Ajouter une ligne au plan
wao.ui.action.createWaoUser=Créer un utilisateur
+wao.ui.action.csvExport=Exporter au format CSV
wao.ui.action.delete=Supprimer
wao.ui.action.deleteCompany=Supprimer la société
wao.ui.action.deleteCompany.confirm=Êtes-vous sûr de vouloir supprimer la société ?
Modified: trunk/wao-web/src/main/webapp/WEB-INF/content/obsmer/sampling-plan.jsp
===================================================================
--- trunk/wao-web/src/main/webapp/WEB-INF/content/obsmer/sampling-plan.jsp 2014-03-20 09:06:44 UTC (rev 1731)
+++ trunk/wao-web/src/main/webapp/WEB-INF/content/obsmer/sampling-plan.jsp 2014-03-20 10:21:05 UTC (rev 1732)
@@ -13,6 +13,11 @@
<s:text name="wao.ui.page.SamplingPlan.title" />
</h1>
+ <s:url action="export-sampling-plan" id="exportSamplingPlanUrl" />
+ <s:a href="%{exportSamplingPlanUrl}" cssClass="btn">
+ <i class="icon-download"></i> <s:text name="wao.ui.action.csvExport" />
+ </s:a>
+
<table class="large-table table-hover">
<thead>
<th>
1
0
r1731 - in trunk: wao-persistence/src/main/java/fr/ifremer/wao/entity wao-services/src/main/java/fr/ifremer/wao/services/service wao-services/src/main/java/fr/ifremer/wao/services/service/csv wao-services/src/main/java/fr/ifremer/wao/services/service/csv/operations wao-services/src/test/java/fr/ifremer/wao/services/service
by bleny@users.forge.codelutin.com 20 Mar '14
by bleny@users.forge.codelutin.com 20 Mar '14
20 Mar '14
Author: bleny
Date: 2014-03-20 10:06:44 +0100 (Thu, 20 Mar 2014)
New Revision: 1731
Url: http://forge.codelutin.com/projects/wao/repository/revisions/1731
Log:
refs #4483 add export sampling plan service
Added:
trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/DCF5Codes.java
Modified:
trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ObsMerSamplingPlanService.java
trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/csv/ObsMerObsVenteSamplingPlanImportExportModel.java
trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/csv/operations/DCF5CodesParserFormatter.java
trunk/wao-services/src/test/java/fr/ifremer/wao/services/service/ObsMerSamplingPlanServiceTest.java
Added: trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/DCF5Codes.java
===================================================================
--- trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/DCF5Codes.java (rev 0)
+++ trunk/wao-persistence/src/main/java/fr/ifremer/wao/entity/DCF5Codes.java 2014-03-20 09:06:44 UTC (rev 1731)
@@ -0,0 +1,18 @@
+package fr.ifremer.wao.entity;
+
+import com.google.common.base.Function;
+
+public class DCF5Codes {
+
+ public static Function<DCF5Code, String> getCode() {
+ return new GetCode();
+ }
+
+ protected static class GetCode implements Function<DCF5Code, String> {
+
+ @Override
+ public String apply(DCF5Code input) {
+ return input.getCode();
+ }
+ }
+}
Modified: trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ObsMerSamplingPlanService.java
===================================================================
--- trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ObsMerSamplingPlanService.java 2014-03-19 16:53:56 UTC (rev 1730)
+++ trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/ObsMerSamplingPlanService.java 2014-03-20 09:06:44 UTC (rev 1731)
@@ -3,10 +3,12 @@
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import fr.ifremer.wao.SampleRowsFilter;
+import fr.ifremer.wao.WaoTechnicalException;
import fr.ifremer.wao.entity.Boat;
import fr.ifremer.wao.entity.Boats;
import fr.ifremer.wao.entity.Company;
@@ -37,11 +39,14 @@
import fr.ifremer.wao.services.service.administration.UnknownFishingGearDcfCodeException;
import fr.ifremer.wao.services.service.administration.UnknownTargetSpeciesDcfCodeException;
import fr.ifremer.wao.services.service.csv.ObsMerObsVenteSamplingPlanImportExportModel;
+import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.nuiton.csv.Export;
+import org.nuiton.csv.ExportModel;
import org.nuiton.csv.Import;
import org.nuiton.csv.ImportModel;
import org.nuiton.csv.ImportRuntimeException;
@@ -49,6 +54,7 @@
import org.nuiton.util.DateUtil;
import java.io.InputStream;
+import java.nio.charset.Charset;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
@@ -483,4 +489,39 @@
return samplingPlanImportModel;
}
+
+ public InputStream exportSamplingPlan(SampleRowsFilter filter) {
+
+ Preconditions.checkArgument(filter.getPeriodFrom() != null);
+ Preconditions.checkArgument(filter.getPeriodTo() != null);
+
+ // ignore pagination when exporting
+ filter.setOrderByArguments(ImmutableSet.of(SampleRow.PROPERTY_CODE));
+
+ SampleRowTopiaDao dao = getSampleRowDao();
+
+ List<SampleRow> sampleRows = dao.findAll(filter);
+
+ ExportModel<SampleRow> exportModel =
+ new ObsMerObsVenteSamplingPlanImportExportModel(
+ filter.getPeriodFrom(),
+ filter.getPeriodTo(),
+ ObsProgram.OBSMER);
+
+ Export<SampleRow> export = Export.newExport(exportModel, sampleRows);
+
+ try {
+
+ String csvContent = export.toString(Charset.forName("UTF-8"));
+
+ InputStream csvInputStream = IOUtils.toInputStream(csvContent, "UTF-8");
+
+ return csvInputStream;
+
+ } catch (Exception e) {
+ throw new WaoTechnicalException(e);
+ }
+
+ }
+
}
Modified: trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/csv/ObsMerObsVenteSamplingPlanImportExportModel.java
===================================================================
--- trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/csv/ObsMerObsVenteSamplingPlanImportExportModel.java 2014-03-19 16:53:56 UTC (rev 1730)
+++ trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/csv/ObsMerObsVenteSamplingPlanImportExportModel.java 2014-03-20 09:06:44 UTC (rev 1731)
@@ -124,8 +124,8 @@
protected PeriodDates periodDates;
/** Pour l'export */
- public ObsMerObsVenteSamplingPlanImportExportModel(PeriodDates periodDates, ObsProgram obsProgram) {
- this.periodDates = periodDates;
+ public ObsMerObsVenteSamplingPlanImportExportModel(Date fromMonth, Date toMonth, ObsProgram obsProgram) {
+ this.periodDates = new PeriodDates(fromMonth, toMonth);
this.obsProgram = obsProgram;
}
Modified: trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/csv/operations/DCF5CodesParserFormatter.java
===================================================================
--- trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/csv/operations/DCF5CodesParserFormatter.java 2014-03-19 16:53:56 UTC (rev 1730)
+++ trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/csv/operations/DCF5CodesParserFormatter.java 2014-03-20 09:06:44 UTC (rev 1731)
@@ -23,7 +23,9 @@
*/
package fr.ifremer.wao.services.service.csv.operations;
+import com.google.common.collect.Iterables;
import fr.ifremer.wao.entity.DCF5Code;
+import fr.ifremer.wao.entity.DCF5Codes;
import fr.ifremer.wao.services.service.administration.ReferentialService;
import fr.ifremer.wao.services.service.administration.UnknownFishingGearDcfCodeException;
import fr.ifremer.wao.services.service.administration.UnknownTargetSpeciesDcfCodeException;
@@ -49,7 +51,8 @@
@Override
public String format(List<DCF5Code> dcf5Codes) {
- return StringUtil.join(dcf5Codes, DCF5_CODES_SEPARATOR, true);
+ String join = StringUtil.join(Iterables.transform(dcf5Codes, DCF5Codes.getCode()), DCF5_CODES_SEPARATOR, true);
+ return join;
}
@Override
Modified: trunk/wao-services/src/test/java/fr/ifremer/wao/services/service/ObsMerSamplingPlanServiceTest.java
===================================================================
--- trunk/wao-services/src/test/java/fr/ifremer/wao/services/service/ObsMerSamplingPlanServiceTest.java 2014-03-19 16:53:56 UTC (rev 1730)
+++ trunk/wao-services/src/test/java/fr/ifremer/wao/services/service/ObsMerSamplingPlanServiceTest.java 2014-03-20 09:06:44 UTC (rev 1731)
@@ -13,6 +13,7 @@
import org.junit.Test;
import org.nuiton.util.DateUtil;
+import java.io.IOException;
import java.io.InputStream;
import java.util.List;
@@ -82,4 +83,23 @@
}
+ @Test
+ public void testExportSamplingPlan() throws IOException {
+
+ fixtures.samplingPlan();
+
+ serviceContext.setDate(DateUtil.createDate(15, 5, 2010));
+
+ SampleRowsFilter filter = service.newSampleRowsFilter(fixtures.admin());
+
+ InputStream inputStream = service.exportSamplingPlan(filter);
+
+ String csvContent = IOUtils.toString(inputStream);
+
+ if (log.isDebugEnabled()) {
+ log.debug("csvContent = \n" + csvContent);
+ }
+
+ }
+
}
1
0
r1730 - in trunk/wao-services/src/main/java/fr/ifremer/wao/services/service: . administration
by bleny@users.forge.codelutin.com 19 Mar '14
by bleny@users.forge.codelutin.com 19 Mar '14
19 Mar '14
Author: bleny
Date: 2014-03-19 17:53:56 +0100 (Wed, 19 Mar 2014)
New Revision: 1730
Url: http://forge.codelutin.com/projects/wao/repository/revisions/1730
Log:
refs #4560 enable to delete user
Modified:
trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/IllegalDeletionException.java
trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/administration/CompaniesService.java
trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/administration/WaoUsersService.java
Modified: trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/IllegalDeletionException.java
===================================================================
--- trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/IllegalDeletionException.java 2014-03-19 15:15:10 UTC (rev 1729)
+++ trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/IllegalDeletionException.java 2014-03-19 16:53:56 UTC (rev 1730)
@@ -3,7 +3,8 @@
import fr.ifremer.wao.WaoException;
import org.nuiton.topia.persistence.TopiaEntity;
-import java.util.Set;
+import java.util.List;
+import java.util.Map;
/**
* L'utilisateur a voulu supprimer une entité mais on doit refuser sa demande car
@@ -12,14 +13,14 @@
public class IllegalDeletionException extends WaoException {
/** Les types d'entités qui utilisent l'entité qu'on ne peut pas supprimer. */
- protected Set<Class<? extends TopiaEntity>> classes;
+ private Map<Class<? extends TopiaEntity>, List<? extends TopiaEntity>> allUsages;
- public IllegalDeletionException(Set<Class<? extends TopiaEntity>> classes) {
- this.classes = classes;
+ public IllegalDeletionException(Map<Class<? extends TopiaEntity>, List<? extends TopiaEntity>> allUsages) {
+ this.allUsages = allUsages;
}
- public Set<Class<? extends TopiaEntity>> getClasses() {
- return classes;
+ public Map<Class<? extends TopiaEntity>, List<? extends TopiaEntity>> getAllUsages() {
+ return allUsages;
}
}
Modified: trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/administration/CompaniesService.java
===================================================================
--- trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/administration/CompaniesService.java 2014-03-19 15:15:10 UTC (rev 1729)
+++ trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/administration/CompaniesService.java 2014-03-19 16:53:56 UTC (rev 1730)
@@ -68,7 +68,7 @@
if (allUsages.isEmpty()) {
dao.delete(company);
} else {
- throw new IllegalDeletionException(allUsages.keySet());
+ throw new IllegalDeletionException(allUsages);
}
commit();
Modified: trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/administration/WaoUsersService.java
===================================================================
--- trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/administration/WaoUsersService.java 2014-03-19 15:15:10 UTC (rev 1729)
+++ trunk/wao-services/src/main/java/fr/ifremer/wao/services/service/administration/WaoUsersService.java 2014-03-19 16:53:56 UTC (rev 1730)
@@ -193,12 +193,14 @@
WaoUser waoUser = dao.findByTopiaId(waoUserId);
+ waoUser.setCompany(null);
+
Map<Class<? extends TopiaEntity>, List<? extends TopiaEntity>> allUsages = dao.findAllUsages(waoUser);
if (allUsages.isEmpty()) {
dao.delete(waoUser);
} else {
- throw new IllegalDeletionException(allUsages.keySet());
+ throw new IllegalDeletionException(allUsages);
}
commit();
1
0
r1729 - in trunk: wao-services/src/main/java/fr/ifremer/wao/services wao-web/src/main/java/fr/ifremer/wao/web wao-web/src/main/java/fr/ifremer/wao/web/action/obsmer wao-web/src/main/resources/i18n wao-web/src/main/webapp/WEB-INF/content/obsmer wao-web/src/main/webapp/WEB-INF/decorators wao-web/src/main/webapp/css wao-web/src/main/webapp/js
by bleny@users.forge.codelutin.com 19 Mar '14
by bleny@users.forge.codelutin.com 19 Mar '14
19 Mar '14
Author: bleny
Date: 2014-03-19 16:15:10 +0100 (Wed, 19 Mar 2014)
New Revision: 1729
Url: http://forge.codelutin.com/projects/wao/repository/revisions/1729
Log:
refs #4483 start sampling plan table
Added:
trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/obsmer/SamplingPlanAction.java
trunk/wao-web/src/main/webapp/WEB-INF/content/obsmer/sampling-plan.jsp
trunk/wao-web/src/main/webapp/js/wao.js
Modified:
trunk/wao-services/src/main/java/fr/ifremer/wao/services/AuthenticatedWaoUser.java
trunk/wao-web/src/main/java/fr/ifremer/wao/web/WaoSession.java
trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/obsmer/EditSampleRowAction.java
trunk/wao-web/src/main/resources/i18n/wao-web_en_GB.properties
trunk/wao-web/src/main/resources/i18n/wao-web_fr_FR.properties
trunk/wao-web/src/main/webapp/WEB-INF/content/obsmer/edit-sample-row-input.jsp
trunk/wao-web/src/main/webapp/WEB-INF/decorators/layout.jsp
trunk/wao-web/src/main/webapp/css/wao.css
Modified: trunk/wao-services/src/main/java/fr/ifremer/wao/services/AuthenticatedWaoUser.java
===================================================================
--- trunk/wao-services/src/main/java/fr/ifremer/wao/services/AuthenticatedWaoUser.java 2014-03-19 15:11:43 UTC (rev 1728)
+++ trunk/wao-services/src/main/java/fr/ifremer/wao/services/AuthenticatedWaoUser.java 2014-03-19 15:15:10 UTC (rev 1729)
@@ -178,4 +178,13 @@
public boolean isAuthorizedToImportSamplingPlan() {
return userProfile.isAdmin();
}
+
+ public boolean isAuthorizedToEditSamplingPlan() {
+ return userProfile.isAdmin();
+ }
+
+ public boolean isAuthorizedToCreateContact() {
+ return userProfile.isCoordinatorOrObserver();
+ }
+
}
Modified: trunk/wao-web/src/main/java/fr/ifremer/wao/web/WaoSession.java
===================================================================
--- trunk/wao-web/src/main/java/fr/ifremer/wao/web/WaoSession.java 2014-03-19 15:11:43 UTC (rev 1728)
+++ trunk/wao-web/src/main/java/fr/ifremer/wao/web/WaoSession.java 2014-03-19 15:15:10 UTC (rev 1729)
@@ -16,6 +16,8 @@
protected AuthenticatedWaoUser authenticatedWaoUser;
+ protected String sampleRowToHighlightId;
+
public Collection<String> getMessages() {
if (messages == null) {
messages = Lists.newLinkedList();
@@ -51,4 +53,11 @@
this.authenticatedWaoUser = authenticatedWaoUser;
}
+ public String getSampleRowToHighlightId() {
+ return sampleRowToHighlightId;
+ }
+
+ public void setSampleRowToHighlightId(String sampleRowToHighlightId) {
+ this.sampleRowToHighlightId = sampleRowToHighlightId;
+ }
}
Modified: trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/obsmer/EditSampleRowAction.java
===================================================================
--- trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/obsmer/EditSampleRowAction.java 2014-03-19 15:11:43 UTC (rev 1728)
+++ trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/obsmer/EditSampleRowAction.java 2014-03-19 15:15:10 UTC (rev 1729)
@@ -118,6 +118,8 @@
session.addMessage(t("wao.ui.form.updateSampleRowCommand.success", updateSampleRowCommand.getSampleRow().getCode()));
+ session.setSampleRowToHighlightId(updateSampleRowCommand.getSampleRow().getTopiaId());
+
return SUCCESS;
}
Added: trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/obsmer/SamplingPlanAction.java
===================================================================
--- trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/obsmer/SamplingPlanAction.java (rev 0)
+++ trunk/wao-web/src/main/java/fr/ifremer/wao/web/action/obsmer/SamplingPlanAction.java 2014-03-19 15:15:10 UTC (rev 1729)
@@ -0,0 +1,41 @@
+package fr.ifremer.wao.web.action.obsmer;
+
+import fr.ifremer.wao.SampleRowsFilter;
+import fr.ifremer.wao.entity.SampleRow;
+import fr.ifremer.wao.services.service.ObsMerSamplingPlanService;
+import fr.ifremer.wao.web.WaoJspActionSupport;
+
+import java.util.List;
+
+public class SamplingPlanAction extends WaoJspActionSupport {
+
+ protected ObsMerSamplingPlanService service;
+
+ protected List<SampleRow> samplingPlan;
+
+ public void setService(ObsMerSamplingPlanService service) {
+ this.service = service;
+ }
+
+ @Override
+ public String execute() {
+
+ SampleRowsFilter filter = service.newSampleRowsFilter(getAuthenticatedWaoUser());
+
+ filter.setPeriodFrom(null);
+ filter.setPeriodTo(null);
+
+ samplingPlan = service.getSamplingPlan(filter);
+
+ return SUCCESS;
+
+ }
+
+ public List<SampleRow> getSamplingPlan() {
+ return samplingPlan;
+ }
+
+ public String getSampleRowToHighlightId() {
+ return getSession().getSampleRowToHighlightId();
+ }
+}
Modified: trunk/wao-web/src/main/resources/i18n/wao-web_en_GB.properties
===================================================================
--- trunk/wao-web/src/main/resources/i18n/wao-web_en_GB.properties 2014-03-19 15:11:43 UTC (rev 1728)
+++ trunk/wao-web/src/main/resources/i18n/wao-web_en_GB.properties 2014-03-19 15:15:10 UTC (rev 1729)
@@ -25,9 +25,11 @@
wao.ui.action.changeLocale=Change language
wao.ui.action.contactAdmin=Contact an admin
wao.ui.action.create=Create
+wao.ui.action.createAssociatedContact=Create a new contact for this sample row
wao.ui.action.createCompany=Create a company
wao.ui.action.createNews=Create news
wao.ui.action.createNews.success=News created
+wao.ui.action.createSampleRow=Add a sample row to the plan
wao.ui.action.createWaoUser=Create a user
wao.ui.action.delete=Delete
wao.ui.action.deleteCompany=Delete company
@@ -66,9 +68,12 @@
wao.ui.action.showDetails=Show details
wao.ui.action.showFilters=Show filters
wao.ui.action.unvalidateContact=Unvalidate contact
+wao.ui.action.viewAssociatedContacts=View sample row contacts
wao.ui.action.viewBoatsForRow=View the boats for this sample row
wao.ui.action.viewCompanyWaoUsers=View users for this company
+wao.ui.action.viewElligibleBoats=View eligible boats
wao.ui.action.viewIndicatorsHistory=View indicators historic
+wao.ui.action.viewSampleRowLog=View sample row log
wao.ui.actions=Actions
wao.ui.boatList=List of %s boats
wao.ui.boatinfo.title=Infos about %s
Modified: trunk/wao-web/src/main/resources/i18n/wao-web_fr_FR.properties
===================================================================
--- trunk/wao-web/src/main/resources/i18n/wao-web_fr_FR.properties 2014-03-19 15:11:43 UTC (rev 1728)
+++ trunk/wao-web/src/main/resources/i18n/wao-web_fr_FR.properties 2014-03-19 15:15:10 UTC (rev 1729)
@@ -25,9 +25,11 @@
wao.ui.action.changeLocale=Changer de langue
wao.ui.action.contactAdmin=Contacter un responsable ObsMer
wao.ui.action.create=Créer
+wao.ui.action.createAssociatedContact=Créer un contact pour cette ligne
wao.ui.action.createCompany=Créer une société
wao.ui.action.createNews=Créer une actualité
wao.ui.action.createNews.success=Actualité enregistrée avec succès
+wao.ui.action.createSampleRow=Ajouter une ligne au plan
wao.ui.action.createWaoUser=Créer un utilisateur
wao.ui.action.delete=Supprimer
wao.ui.action.deleteCompany=Supprimer la société
@@ -66,9 +68,12 @@
wao.ui.action.showDetails=Voir les détails
wao.ui.action.showFilters=Afficher les filtres
wao.ui.action.unvalidateContact=Invalider le contact
+wao.ui.action.viewAssociatedContacts=Voir les contacts associés à cette ligne
wao.ui.action.viewBoatsForRow=Voir les navires présentis pour cette ligne
wao.ui.action.viewCompanyWaoUsers=Voir les utilisateurs associés à cette société
+wao.ui.action.viewElligibleBoats=Consulter les navires éligibles
wao.ui.action.viewIndicatorsHistory=Voir l'historique des modifications des indicateurs
+wao.ui.action.viewSampleRowLog=Consulter l'historique de cette ligne
wao.ui.actions=Actions
wao.ui.boatList=Liste de %s navires
wao.ui.boatinfo.title=Informations sur %s
Modified: trunk/wao-web/src/main/webapp/WEB-INF/content/obsmer/edit-sample-row-input.jsp
===================================================================
--- trunk/wao-web/src/main/webapp/WEB-INF/content/obsmer/edit-sample-row-input.jsp 2014-03-19 15:11:43 UTC (rev 1728)
+++ trunk/wao-web/src/main/webapp/WEB-INF/content/obsmer/edit-sample-row-input.jsp 2014-03-19 15:15:10 UTC (rev 1729)
@@ -20,37 +20,43 @@
var $expectedObservationsByMonthsTable = $('#expectedObservationsByMonthsTable');
var $expectedObservationsByMonthsTableHead = $expectedObservationsByMonthsTable.find('thead');
var $expectedObservationsByMonthsTableBody = $expectedObservationsByMonthsTable.find('tbody');
- var $periodBeginInput = $('input[name="updateSampleRowCommand.sampleRow.periodBegin"');
- var $periodEndInput = $('input[name="updateSampleRowCommand.sampleRow.periodEnd"');
+ var $periodBeginInput = $('input[name="updateSampleRowCommand.sampleRow.periodBegin"]');
+ var $periodEndInput = $('input[name="updateSampleRowCommand.sampleRow.periodEnd"]');
var updateExpectedObservationsByMonthsTable = function() {
- var periodBegin = moment($periodBeginInput.val(), "MM/YYYY");
- var periodEnd = moment($periodEndInput.val(), "MM/YYYY");
- if (periodBegin > periodEnd) {
- $periodEndInput.val($periodBeginInput.val());
- periodEnd = moment($periodEndInput.val(), "MM/YYYY");
- }
- var months = [];
- do {
- months.push(periodBegin.format("YYYYMM"));
- periodBegin.add('months', 1);
- } while (periodBegin <= periodEnd);
$expectedObservationsByMonthsTableHead.empty();
$expectedObservationsByMonthsTableBody.empty();
- $expectedObservationsByMonthsTableHead.append('<tr></tr>');
- $expectedObservationsByMonthsTableBody.append('<tr></tr>');
- $(months).each(function (index, month) {
- var newInput = ' <td>'
- + ' ' + moment(month, "YYYYMM").format('MM/YYYY')
- + ' </td>';
- $expectedObservationsByMonthsTableHead.find('tr').append(newInput);
- });
- $(months).each(function (index, month) {
- var newInput = ' <td>'
- + ' <input type="number" name="expectedObservationsByMonths[\'' + month + '\']" value="' + expectedObservationsByMonths[month] + '" class="input-small" />'
- + ' </td>';
- $expectedObservationsByMonthsTableBody.find('tr').append(newInput);
- });
+ var periodBegin = moment($periodBeginInput.val(), 'MM/YYYY');
+ var periodEnd = moment($periodEndInput.val(), 'MM/YYYY');
+ if (periodBegin.isValid() && periodEnd.isValid()) {
+ if (periodBegin > periodEnd) {
+ $periodEndInput.val($periodBeginInput.val());
+ periodEnd = moment($periodEndInput.val(), 'MM/YYYY');
+ }
+ var months = [];
+ do {
+ months.push(periodBegin.format('YYYYMM'));
+ periodBegin.add('months', 1);
+ } while (periodBegin <= periodEnd);
+ $expectedObservationsByMonthsTableHead.append('<tr></tr>');
+ $expectedObservationsByMonthsTableBody.append('<tr></tr>');
+ $(months).each(function (index, month) {
+ var newInput = ' <td>'
+ + ' ' + moment(month, 'YYYYMM').format('MM/YYYY')
+ + ' </td>';
+ $expectedObservationsByMonthsTableHead.find('tr').append(newInput);
+ });
+ $(months).each(function (index, month) {
+ var value = "";
+ if (expectedObservationsByMonths[month]) {
+ value = expectedObservationsByMonths[month];
+ }
+ var newInput = ' <td>'
+ + ' <input type="number" name="expectedObservationsByMonths[\'' + month + '\']" value="' + value + '" class="input-small" />'
+ + ' </td>';
+ $expectedObservationsByMonthsTableBody.find('tr').append(newInput);
+ });
+ }
}
updateExpectedObservationsByMonthsTable();
@@ -145,8 +151,14 @@
<s:textfield name="updateSampleRowCommand.sampleRow.programName"
label="%{getText('wao.ui.field.SampleRow.programName')}"
disabled="updateSampleRowCommand.observationAlreadyStarted" />
- <s:textfield name="updateSampleRowCommand.sampleRow.periodBegin" label="%{getText('wao.ui.field.SampleRow.periodBegin')}" cssClass="input-small" />
- <s:textfield name="updateSampleRowCommand.sampleRow.periodEnd" label="%{getText('wao.ui.field.SampleRow.periodEnd')}" cssClass="input-small" />
+ <s:textfield name="updateSampleRowCommand.sampleRow.periodBegin"
+ label="%{getText('wao.ui.field.SampleRow.periodBegin')}"
+ placeholder="04/2014"
+ cssClass="input-small" />
+ <s:textfield name="updateSampleRowCommand.sampleRow.periodEnd"
+ label="%{getText('wao.ui.field.SampleRow.periodEnd')}"
+ placeholder="03/2015"
+ cssClass="input-small" />
<div class="control-group">
Added: trunk/wao-web/src/main/webapp/WEB-INF/content/obsmer/sampling-plan.jsp
===================================================================
--- trunk/wao-web/src/main/webapp/WEB-INF/content/obsmer/sampling-plan.jsp (rev 0)
+++ trunk/wao-web/src/main/webapp/WEB-INF/content/obsmer/sampling-plan.jsp 2014-03-19 15:15:10 UTC (rev 1729)
@@ -0,0 +1,107 @@
+<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
+<%@taglib uri="/struts-tags" prefix="s" %>
+
+<html>
+
+ <head>
+ <title>
+ <s:text name="wao.ui.page.SamplingPlan.title" />
+ </title>
+ </head>
+
+ <h1>
+ <s:text name="wao.ui.page.SamplingPlan.title" />
+ </h1>
+
+ <table class="large-table table-hover">
+ <thead>
+ <th>
+ <s:text name="wao.ui.field.SampleRow.code" />
+ </th>
+ <th>
+ <s:text name="wao.ui.actions" />
+ </th>
+ </thead>
+ <tbody>
+ <s:iterator value="samplingPlan" var="sampleRow">
+ <tr<s:if test="sampleRowToHighlightId.equals(topiaId)"> class="highlight"</s:if>>
+ <th>
+ <s:property value="code" />
+ </th>
+ <td class="actions">
+ <%--
+ <td class="actions dropdown">
+ <a class="btn dropdown-toggle" data-toggle="dropdown" href="#"><s:text name="wao.ui.actions" /> <b class="caret"></b></a>
+ <ul class="dropdown-menu">
+ --%>
+ <ul>
+ <s:if test="authenticatedWaoUser.authorizedToEditSamplingPlan">
+ <li>
+ <s:url action="edit-sample-row!input" id="editSampleRowUrl">
+ <s:param name="sampleRowId" value="topiaId" />
+ </s:url>
+ <s:a href="%{editSampleRowUrl}">
+ <i class="icon-edit"></i> <s:text name="wao.ui.action.edit" />
+ </s:a>
+ </li>
+ <li>
+ <s:url action="delete-sample-row" id="deleteSampleRowUrl">
+ <s:param name="companyId" value="topiaId" />
+ </s:url>
+ <s:a href="%{deleteSampleRowUrl}">
+ <i class="icon-trash"></i> <s:text name="wao.ui.action.delete" />
+ </s:a>
+ </li>
+ </s:if>
+ <li>
+ <s:url action="sample-row-log" id="sampleRowLogUrl">
+ <s:param name="sampleRowId" value="topiaId" />
+ </s:url>
+ <s:a href="%{sampleRowLogUrl}">
+ <i class="icon-time"></i> <s:text name="wao.ui.action.viewSampleRowLog" />
+ </s:a>
+ </li>
+ <li>
+ <s:url action="boats" id="viewElligibleBoatsUrl">
+ <s:param name="sampleRowIds" value="topiaId" />
+ </s:url>
+ <s:a href="%{viewElligibleBoatsUrl}">
+ <s:text name="wao.ui.action.viewElligibleBoats" />
+ </s:a>
+ </li>
+ <li>
+ <s:url action="contacts" id="viewAssociatedContactsUrl">
+ <s:param name="sampleRowIds" value="topiaId" />
+ </s:url>
+ <s:a href="%{viewAssociatedContactsUrl}">
+ <s:text name="wao.ui.action.viewAssociatedContacts" />
+ </s:a>
+ </li>
+ <s:if test="authenticatedWaoUser.authorizedToCreateContact">
+ <li>
+ <s:url action="contacts" id="createAssociatedContactUrl">
+ <s:param name="sampleRowIds" value="topiaId" />
+ </s:url>
+ <s:a href="%{createAssociatedContactUrl}">
+ <i class="icon-add"></i> <s:text name="wao.ui.action.createAssociatedContact" />
+ </s:a>
+ </li>
+ </s:if>
+ </ul>
+ </td>
+ </tr>
+ </s:iterator>
+ </todby>
+ <tfoot>
+
+ </tfoot>
+ </table>
+
+ <s:if test="authenticatedWaoUser.authorizedToEditSamplingPlan">
+ <s:url action="edit-sample-row!input" id="createSampleRow" />
+ <s:a href="%{createSampleRow}">
+ <i class="icon-plus"></i> <s:text name="wao.ui.action.createSampleRow" />
+ </s:a>
+ </s:if>
+
+</html>
Modified: trunk/wao-web/src/main/webapp/WEB-INF/decorators/layout.jsp
===================================================================
--- trunk/wao-web/src/main/webapp/WEB-INF/decorators/layout.jsp 2014-03-19 15:11:43 UTC (rev 1728)
+++ trunk/wao-web/src/main/webapp/WEB-INF/decorators/layout.jsp 2014-03-19 15:15:10 UTC (rev 1729)
@@ -11,10 +11,11 @@
<sj:head locale="fr" jqueryui="true" loadAtOnce="true" jquerytheme="start" />
<sb:head />
<script type="text/javascript" src="<s:url value='/js/moment-js-2.5.1/moment-with-langs.js' />"></script>
- <script type="text/javascript" src="<s:url value='/js/select2/select2.min.js' />"></script>
- <script type="text/javascript" src="<s:url value='/js/select2/select2_locale_fr.js' />"></script>
+ <script type="text/javascript" src="<s:url value='/js/select2-3.4.5/select2.min.js' />"></script>
+ <script type="text/javascript" src="<s:url value='/js/select2-3.4.5/select2_locale_fr.js' />"></script>
<script type="text/javascript" src="<s:url value='/js/wao.js' />"></script>
- <link rel="stylesheet" type="text/css" href="<s:url value='/css/select2/select2.css' />" />
+ <link rel="stylesheet" type="text/css" href="<s:url value='/js/select2-3.4.5/select2.css' />" />
+ <link rel="stylesheet" type="text/css" href="<s:url value='/js/select2-3.4.5/select2-bootstrap.css' />" />
<link rel="stylesheet" type="text/css" href="<s:url value='/css/wao.css' />" media="all" />
<link rel="stylesheet" type="text/css" href="<s:url value='/css/wao-screen.css' />" media="screen">
<decorator:head />
Modified: trunk/wao-web/src/main/webapp/css/wao.css
===================================================================
--- trunk/wao-web/src/main/webapp/css/wao.css 2014-03-19 15:11:43 UTC (rev 1728)
+++ trunk/wao-web/src/main/webapp/css/wao.css 2014-03-19 15:15:10 UTC (rev 1729)
@@ -49,6 +49,10 @@
*/
/* pour représente qu'une entité (société, utilisateur) est inactive */
+.highlight {
+ background-color: #ffff99;
+}
+
.inactive {
text-decoration: line-through;
}
@@ -57,9 +61,34 @@
white-space: nowrap;
}
+.large-table, .large-table thead th {
+ border: solid 1px #aaaaaa;
+}
+
+.large-table * {
+ padding: 0px;
+ margin: 0px;
+}
+
+.large-table li {
+ list-style-type: none;
+}
+
+.large-table tr:hover {
+ background-color: #f5f5f5;
+}
+
+.large-table tbody th, .large-table td {
+ border: solid 1px #aaaaaa;
+ border-left-style: dashed;
+ border-right-style: dashed;
+ padding: 2px;
+}
+
/**
* Styles spécifiques pour certainse pages de l'appli
*/
+
#expectedObservationsByMonthsTable th {
white-space: nowrap;
}
Added: trunk/wao-web/src/main/webapp/js/wao.js
===================================================================
--- trunk/wao-web/src/main/webapp/js/wao.js (rev 0)
+++ trunk/wao-web/src/main/webapp/js/wao.js 2014-03-19 15:15:10 UTC (rev 1729)
@@ -0,0 +1,5 @@
+$(document).ready(function () {
+
+ $('select').select2();
+
+});
\ No newline at end of file
1
0
r1728 - in trunk/wao-web/src/main/webapp/js: . select2-3.4.5
by bleny@users.forge.codelutin.com 19 Mar '14
by bleny@users.forge.codelutin.com 19 Mar '14
19 Mar '14
Author: bleny
Date: 2014-03-19 16:11:43 +0100 (Wed, 19 Mar 2014)
New Revision: 1728
Url: http://forge.codelutin.com/projects/wao/repository/revisions/1728
Log:
add select2
Added:
trunk/wao-web/src/main/webapp/js/select2-3.4.5/
trunk/wao-web/src/main/webapp/js/select2-3.4.5/LICENSE
trunk/wao-web/src/main/webapp/js/select2-3.4.5/README.md
trunk/wao-web/src/main/webapp/js/select2-3.4.5/select2-bootstrap.css
trunk/wao-web/src/main/webapp/js/select2-3.4.5/select2-spinner.gif
trunk/wao-web/src/main/webapp/js/select2-3.4.5/select2.css
trunk/wao-web/src/main/webapp/js/select2-3.4.5/select2.js
trunk/wao-web/src/main/webapp/js/select2-3.4.5/select2.min.js
trunk/wao-web/src/main/webapp/js/select2-3.4.5/select2.png
trunk/wao-web/src/main/webapp/js/select2-3.4.5/select2_locale_fr.js
trunk/wao-web/src/main/webapp/js/select2-3.4.5/select2x2.png
Added: trunk/wao-web/src/main/webapp/js/select2-3.4.5/LICENSE
===================================================================
--- trunk/wao-web/src/main/webapp/js/select2-3.4.5/LICENSE (rev 0)
+++ trunk/wao-web/src/main/webapp/js/select2-3.4.5/LICENSE 2014-03-19 15:11:43 UTC (rev 1728)
@@ -0,0 +1,18 @@
+Copyright 2012 Igor Vaynberg
+
+Version: @@ver@@ Timestamp: @@timestamp@@
+
+This software is licensed under the Apache License, Version 2.0 (the "Apache License") or the GNU
+General Public License version 2 (the "GPL License"). You may choose either license to govern your
+use of this software only upon the condition that you accept all of the terms of either the Apache
+License or the GPL License.
+
+You may obtain a copy of the Apache License and the GPL License at:
+
+http://www.apache.org/licenses/LICENSE-2.0
+http://www.gnu.org/licenses/gpl-2.0.html
+
+Unless required by applicable law or agreed to in writing, software distributed under the Apache License
+or the GPL Licesnse is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+either express or implied. See the Apache License and the GPL License for the specific language governing
+permissions and limitations under the Apache License and the GPL License.
\ No newline at end of file
Added: trunk/wao-web/src/main/webapp/js/select2-3.4.5/README.md
===================================================================
--- trunk/wao-web/src/main/webapp/js/select2-3.4.5/README.md (rev 0)
+++ trunk/wao-web/src/main/webapp/js/select2-3.4.5/README.md 2014-03-19 15:11:43 UTC (rev 1728)
@@ -0,0 +1,83 @@
+Select2
+=======
+
+Select2 is a jQuery-based replacement for select boxes. It supports searching, remote data sets, and infinite scrolling of results.
+
+To get started, checkout examples and documentation at http://ivaynberg.github.com/select2
+
+Use cases
+---------
+
+* Enhancing native selects with search.
+* Enhancing native selects with a better multi-select interface.
+* Loading data from JavaScript: easily load items via ajax and have them searchable.
+* Nesting optgroups: native selects only support one level of nested. Select2 does not have this restriction.
+* Tagging: ability to add new items on the fly.
+* Working with large, remote datasets: ability to partially load a dataset based on the search term.
+* Paging of large datasets: easy support for loading more pages when the results are scrolled to the end.
+* Templating: support for custom rendering of results and selections.
+
+Browser compatibility
+---------------------
+* IE 8+
+* Chrome 8+
+* Firefox 10+
+* Safari 3+
+* Opera 10.6+
+
+Integrations
+------------
+
+* [Wicket-Select2](https://github.com/ivaynberg/wicket-select2) (Java / [Apache Wicket](http://wicket.apache.org))
+* [select2-rails](https://github.com/argerim/select2-rails) (Ruby on Rails)
+* [AngularUI](http://angular-ui.github.com/#directives-select2) ([AngularJS](angularjs.org))
+* [Django](https://github.com/applegrew/django-select2)
+* [Symfony](https://github.com/19Gerhard85/sfSelect2WidgetsPlugin)
+* [Bootstrap](https://github.com/t0m/select2-bootstrap-css) (CSS skin)
+* [Yii](https://github.com/tonybolzan/yii-select2)
+
+Internationalization (i18n)
+---------------------------
+
+Select2 supports multiple languages by simply including the right
+language JS file (`select2_locale_it.js`, `select2_locale_nl.js`, etc.).
+
+Missing a language? Just copy `select2_locale_en.js.template`, translate
+it, and make a pull request back to Select2 here on GitHub.
+
+Bug tracker
+-----------
+
+Have a bug? Please create an issue here on GitHub!
+
+https://github.com/ivaynberg/select2/issues
+
+Mailing list
+------------
+
+Have a question? Ask on our mailing list!
+
+select2(a)googlegroups.com
+
+https://groups.google.com/d/forum/select2
+
+
+Copyright and license
+---------------------
+
+Copyright 2012 Igor Vaynberg
+
+This software is licensed under the Apache License, Version 2.0 (the "Apache License") or the GNU
+General Public License version 2 (the "GPL License"). You may choose either license to govern your
+use of this software only upon the condition that you accept all of the terms of either the Apache
+License or the GPL License.
+
+You may obtain a copy of the Apache License and the GPL License in the LICENSE file, or at:
+
+http://www.apache.org/licenses/LICENSE-2.0
+http://www.gnu.org/licenses/gpl-2.0.html
+
+Unless required by applicable law or agreed to in writing, software distributed under the Apache License
+or the GPL License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+either express or implied. See the Apache License and the GPL License for the specific language governing
+permissions and limitations under the Apache License and the GPL License.
Added: trunk/wao-web/src/main/webapp/js/select2-3.4.5/select2-bootstrap.css
===================================================================
--- trunk/wao-web/src/main/webapp/js/select2-3.4.5/select2-bootstrap.css (rev 0)
+++ trunk/wao-web/src/main/webapp/js/select2-3.4.5/select2-bootstrap.css 2014-03-19 15:11:43 UTC (rev 1728)
@@ -0,0 +1,87 @@
+.form-control .select2-choice {
+ border: 0;
+ border-radius: 2px;
+}
+
+.form-control .select2-choice .select2-arrow {
+ border-radius: 0 2px 2px 0;
+}
+
+.form-control.select2-container {
+ height: auto !important;
+ padding: 0px;
+}
+
+.form-control.select2-container.select2-dropdown-open {
+ border-color: #5897FB;
+ border-radius: 3px 3px 0 0;
+}
+
+.form-control .select2-container.select2-dropdown-open .select2-choices {
+ border-radius: 3px 3px 0 0;
+}
+
+.form-control.select2-container .select2-choices {
+ border: 0 !important;
+ border-radius: 3px;
+}
+
+.control-group.warning .select2-container .select2-choice,
+.control-group.warning .select2-container .select2-choices,
+.control-group.warning .select2-container-active .select2-choice,
+.control-group.warning .select2-container-active .select2-choices,
+.control-group.warning .select2-dropdown-open.select2-drop-above .select2-choice,
+.control-group.warning .select2-dropdown-open.select2-drop-above .select2-choices,
+.control-group.warning .select2-container-multi.select2-container-active .select2-choices {
+ border: 1px solid #C09853 !important;
+}
+
+.control-group.warning .select2-container .select2-choice div {
+ border-left: 1px solid #C09853 !important;
+ background: #FCF8E3 !important;
+}
+
+.control-group.error .select2-container .select2-choice,
+.control-group.error .select2-container .select2-choices,
+.control-group.error .select2-container-active .select2-choice,
+.control-group.error .select2-container-active .select2-choices,
+.control-group.error .select2-dropdown-open.select2-drop-above .select2-choice,
+.control-group.error .select2-dropdown-open.select2-drop-above .select2-choices,
+.control-group.error .select2-container-multi.select2-container-active .select2-choices {
+ border: 1px solid #B94A48 !important;
+}
+
+.control-group.error .select2-container .select2-choice div {
+ border-left: 1px solid #B94A48 !important;
+ background: #F2DEDE !important;
+}
+
+.control-group.info .select2-container .select2-choice,
+.control-group.info .select2-container .select2-choices,
+.control-group.info .select2-container-active .select2-choice,
+.control-group.info .select2-container-active .select2-choices,
+.control-group.info .select2-dropdown-open.select2-drop-above .select2-choice,
+.control-group.info .select2-dropdown-open.select2-drop-above .select2-choices,
+.control-group.info .select2-container-multi.select2-container-active .select2-choices {
+ border: 1px solid #3A87AD !important;
+}
+
+.control-group.info .select2-container .select2-choice div {
+ border-left: 1px solid #3A87AD !important;
+ background: #D9EDF7 !important;
+}
+
+.control-group.success .select2-container .select2-choice,
+.control-group.success .select2-container .select2-choices,
+.control-group.success .select2-container-active .select2-choice,
+.control-group.success .select2-container-active .select2-choices,
+.control-group.success .select2-dropdown-open.select2-drop-above .select2-choice,
+.control-group.success .select2-dropdown-open.select2-drop-above .select2-choices,
+.control-group.success .select2-container-multi.select2-container-active .select2-choices {
+ border: 1px solid #468847 !important;
+}
+
+.control-group.success .select2-container .select2-choice div {
+ border-left: 1px solid #468847 !important;
+ background: #DFF0D8 !important;
+}
Added: trunk/wao-web/src/main/webapp/js/select2-3.4.5/select2-spinner.gif
===================================================================
(Binary files differ)
Property changes on: trunk/wao-web/src/main/webapp/js/select2-3.4.5/select2-spinner.gif
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: trunk/wao-web/src/main/webapp/js/select2-3.4.5/select2.css
===================================================================
--- trunk/wao-web/src/main/webapp/js/select2-3.4.5/select2.css (rev 0)
+++ trunk/wao-web/src/main/webapp/js/select2-3.4.5/select2.css 2014-03-19 15:11:43 UTC (rev 1728)
@@ -0,0 +1,615 @@
+/*
+Version: 3.4.5 Timestamp: Mon Nov 4 08:22:42 PST 2013
+*/
+.select2-container {
+ margin: 0;
+ position: relative;
+ display: inline-block;
+ /* inline-block for ie7 */
+ zoom: 1;
+ *display: inline;
+ vertical-align: middle;
+}
+
+.select2-container,
+.select2-drop,
+.select2-search,
+.select2-search input {
+ /*
+ Force border-box so that % widths fit the parent
+ container without overlap because of margin/padding.
+
+ More Info : http://www.quirksmode.org/css/box.html
+ */
+ -webkit-box-sizing: border-box; /* webkit */
+ -moz-box-sizing: border-box; /* firefox */
+ box-sizing: border-box; /* css3 */
+}
+
+.select2-container .select2-choice {
+ display: block;
+ height: 26px;
+ padding: 0 0 0 8px;
+ overflow: hidden;
+ position: relative;
+
+ border: 1px solid #aaa;
+ white-space: nowrap;
+ line-height: 26px;
+ color: #444;
+ text-decoration: none;
+
+ border-radius: 4px;
+
+ background-clip: padding-box;
+
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+
+ background-color: #fff;
+ background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(0.5, #fff));
+ background-image: -webkit-linear-gradient(center bottom, #eee 0%, #fff 50%);
+ background-image: -moz-linear-gradient(center bottom, #eee 0%, #fff 50%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr = '#ffffff', endColorstr = '#eeeeee', GradientType = 0);
+ background-image: linear-gradient(top, #fff 0%, #eee 50%);
+}
+
+.select2-container.select2-drop-above .select2-choice {
+ border-bottom-color: #aaa;
+
+ border-radius: 0 0 4px 4px;
+
+ background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(0.9, #fff));
+ background-image: -webkit-linear-gradient(center bottom, #eee 0%, #fff 90%);
+ background-image: -moz-linear-gradient(center bottom, #eee 0%, #fff 90%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
+ background-image: linear-gradient(top, #eee 0%, #fff 90%);
+}
+
+.select2-container.select2-allowclear .select2-choice .select2-chosen {
+ margin-right: 42px;
+}
+
+.select2-container .select2-choice > .select2-chosen {
+ margin-right: 26px;
+ display: block;
+ overflow: hidden;
+
+ white-space: nowrap;
+
+ text-overflow: ellipsis;
+}
+
+.select2-container .select2-choice abbr {
+ display: none;
+ width: 12px;
+ height: 12px;
+ position: absolute;
+ right: 24px;
+ top: 8px;
+
+ font-size: 1px;
+ text-decoration: none;
+
+ border: 0;
+ background: url('select2.png') right top no-repeat;
+ cursor: pointer;
+ outline: 0;
+}
+
+.select2-container.select2-allowclear .select2-choice abbr {
+ display: inline-block;
+}
+
+.select2-container .select2-choice abbr:hover {
+ background-position: right -11px;
+ cursor: pointer;
+}
+
+.select2-drop-mask {
+ border: 0;
+ margin: 0;
+ padding: 0;
+ position: fixed;
+ left: 0;
+ top: 0;
+ min-height: 100%;
+ min-width: 100%;
+ height: auto;
+ width: auto;
+ opacity: 0;
+ z-index: 9998;
+ /* styles required for IE to work */
+ background-color: #fff;
+ filter: alpha(opacity=0);
+}
+
+.select2-drop {
+ width: 100%;
+ margin-top: -1px;
+ position: absolute;
+ z-index: 9999;
+ top: 100%;
+
+ background: #fff;
+ color: #000;
+ border: 1px solid #aaa;
+ border-top: 0;
+
+ border-radius: 0 0 4px 4px;
+
+ -webkit-box-shadow: 0 4px 5px rgba(0, 0, 0, .15);
+ box-shadow: 0 4px 5px rgba(0, 0, 0, .15);
+}
+
+.select2-drop-auto-width {
+ border-top: 1px solid #aaa;
+ width: auto;
+}
+
+.select2-drop-auto-width .select2-search {
+ padding-top: 4px;
+}
+
+.select2-drop.select2-drop-above {
+ margin-top: 1px;
+ border-top: 1px solid #aaa;
+ border-bottom: 0;
+
+ border-radius: 4px 4px 0 0;
+
+ -webkit-box-shadow: 0 -4px 5px rgba(0, 0, 0, .15);
+ box-shadow: 0 -4px 5px rgba(0, 0, 0, .15);
+}
+
+.select2-drop-active {
+ border: 1px solid #5897fb;
+ border-top: none;
+}
+
+.select2-drop.select2-drop-above.select2-drop-active {
+ border-top: 1px solid #5897fb;
+}
+
+.select2-container .select2-choice .select2-arrow {
+ display: inline-block;
+ width: 18px;
+ height: 100%;
+ position: absolute;
+ right: 0;
+ top: 0;
+
+ border-left: 1px solid #aaa;
+ border-radius: 0 4px 4px 0;
+
+ background-clip: padding-box;
+
+ background: #ccc;
+ background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #ccc), color-stop(0.6, #eee));
+ background-image: -webkit-linear-gradient(center bottom, #ccc 0%, #eee 60%);
+ background-image: -moz-linear-gradient(center bottom, #ccc 0%, #eee 60%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr = '#eeeeee', endColorstr = '#cccccc', GradientType = 0);
+ background-image: linear-gradient(top, #ccc 0%, #eee 60%);
+}
+
+.select2-container .select2-choice .select2-arrow b {
+ display: block;
+ width: 100%;
+ height: 100%;
+ background: url('select2.png') no-repeat 0 1px;
+}
+
+.select2-search {
+ display: inline-block;
+ width: 100%;
+ min-height: 26px;
+ margin: 0;
+ padding-left: 4px;
+ padding-right: 4px;
+
+ position: relative;
+ z-index: 10000;
+
+ white-space: nowrap;
+}
+
+.select2-search input {
+ width: 100%;
+ height: auto !important;
+ min-height: 26px;
+ padding: 4px 20px 4px 5px;
+ margin: 0;
+
+ outline: 0;
+ font-family: sans-serif;
+ font-size: 1em;
+
+ border: 1px solid #aaa;
+ border-radius: 0;
+
+ -webkit-box-shadow: none;
+ box-shadow: none;
+
+ background: #fff url('select2.png') no-repeat 100% -22px;
+ background: url('select2.png') no-repeat 100% -22px, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, #fff), color-stop(0.99, #eee));
+ background: url('select2.png') no-repeat 100% -22px, -webkit-linear-gradient(center bottom, #fff 85%, #eee 99%);
+ background: url('select2.png') no-repeat 100% -22px, -moz-linear-gradient(center bottom, #fff 85%, #eee 99%);
+ background: url('select2.png') no-repeat 100% -22px, linear-gradient(top, #fff 85%, #eee 99%);
+}
+
+.select2-drop.select2-drop-above .select2-search input {
+ margin-top: 4px;
+}
+
+.select2-search input.select2-active {
+ background: #fff url('select2-spinner.gif') no-repeat 100%;
+ background: url('select2-spinner.gif') no-repeat 100%, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, #fff), color-stop(0.99, #eee));
+ background: url('select2-spinner.gif') no-repeat 100%, -webkit-linear-gradient(center bottom, #fff 85%, #eee 99%);
+ background: url('select2-spinner.gif') no-repeat 100%, -moz-linear-gradient(center bottom, #fff 85%, #eee 99%);
+ background: url('select2-spinner.gif') no-repeat 100%, linear-gradient(top, #fff 85%, #eee 99%);
+}
+
+.select2-container-active .select2-choice,
+.select2-container-active .select2-choices {
+ border: 1px solid #5897fb;
+ outline: none;
+
+ -webkit-box-shadow: 0 0 5px rgba(0, 0, 0, .3);
+ box-shadow: 0 0 5px rgba(0, 0, 0, .3);
+}
+
+.select2-dropdown-open .select2-choice {
+ border-bottom-color: transparent;
+ -webkit-box-shadow: 0 1px 0 #fff inset;
+ box-shadow: 0 1px 0 #fff inset;
+
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0;
+
+ background-color: #eee;
+ background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #fff), color-stop(0.5, #eee));
+ background-image: -webkit-linear-gradient(center bottom, #fff 0%, #eee 50%);
+ background-image: -moz-linear-gradient(center bottom, #fff 0%, #eee 50%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0);
+ background-image: linear-gradient(top, #fff 0%, #eee 50%);
+}
+
+.select2-dropdown-open.select2-drop-above .select2-choice,
+.select2-dropdown-open.select2-drop-above .select2-choices {
+ border: 1px solid #5897fb;
+ border-top-color: transparent;
+
+ background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #fff), color-stop(0.5, #eee));
+ background-image: -webkit-linear-gradient(center top, #fff 0%, #eee 50%);
+ background-image: -moz-linear-gradient(center top, #fff 0%, #eee 50%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0);
+ background-image: linear-gradient(bottom, #fff 0%, #eee 50%);
+}
+
+.select2-dropdown-open .select2-choice .select2-arrow {
+ background: transparent;
+ border-left: none;
+ filter: none;
+}
+.select2-dropdown-open .select2-choice .select2-arrow b {
+ background-position: -18px 1px;
+}
+
+/* results */
+.select2-results {
+ max-height: 200px;
+ padding: 0 0 0 4px;
+ margin: 4px 4px 4px 0;
+ position: relative;
+ overflow-x: hidden;
+ overflow-y: auto;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+}
+
+.select2-results ul.select2-result-sub {
+ margin: 0;
+ padding-left: 0;
+}
+
+.select2-results ul.select2-result-sub > li .select2-result-label { padding-left: 20px }
+.select2-results ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 40px }
+.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 60px }
+.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 80px }
+.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 100px }
+.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 110px }
+.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 120px }
+
+.select2-results li {
+ list-style: none;
+ display: list-item;
+ background-image: none;
+}
+
+.select2-results li.select2-result-with-children > .select2-result-label {
+ font-weight: bold;
+}
+
+.select2-results .select2-result-label {
+ padding: 3px 7px 4px;
+ margin: 0;
+ cursor: pointer;
+
+ min-height: 1em;
+
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+.select2-results .select2-highlighted {
+ background: #3875d7;
+ color: #fff;
+}
+
+.select2-results li em {
+ background: #feffde;
+ font-style: normal;
+}
+
+.select2-results .select2-highlighted em {
+ background: transparent;
+}
+
+.select2-results .select2-highlighted ul {
+ background: #fff;
+ color: #000;
+}
+
+
+.select2-results .select2-no-results,
+.select2-results .select2-searching,
+.select2-results .select2-selection-limit {
+ background: #f4f4f4;
+ display: list-item;
+}
+
+/*
+disabled look for disabled choices in the results dropdown
+*/
+.select2-results .select2-disabled.select2-highlighted {
+ color: #666;
+ background: #f4f4f4;
+ display: list-item;
+ cursor: default;
+}
+.select2-results .select2-disabled {
+ background: #f4f4f4;
+ display: list-item;
+ cursor: default;
+}
+
+.select2-results .select2-selected {
+ display: none;
+}
+
+.select2-more-results.select2-active {
+ background: #f4f4f4 url('select2-spinner.gif') no-repeat 100%;
+}
+
+.select2-more-results {
+ background: #f4f4f4;
+ display: list-item;
+}
+
+/* disabled styles */
+
+.select2-container.select2-container-disabled .select2-choice {
+ background-color: #f4f4f4;
+ background-image: none;
+ border: 1px solid #ddd;
+ cursor: default;
+}
+
+.select2-container.select2-container-disabled .select2-choice .select2-arrow {
+ background-color: #f4f4f4;
+ background-image: none;
+ border-left: 0;
+}
+
+.select2-container.select2-container-disabled .select2-choice abbr {
+ display: none;
+}
+
+
+/* multiselect */
+
+.select2-container-multi .select2-choices {
+ height: auto !important;
+ height: 1%;
+ margin: 0;
+ padding: 0;
+ position: relative;
+
+ border: 1px solid #aaa;
+ cursor: text;
+ overflow: hidden;
+
+ background-color: #fff;
+ background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(1%, #eee), color-stop(15%, #fff));
+ background-image: -webkit-linear-gradient(top, #eee 1%, #fff 15%);
+ background-image: -moz-linear-gradient(top, #eee 1%, #fff 15%);
+ background-image: linear-gradient(top, #eee 1%, #fff 15%);
+}
+
+.select2-locked {
+ padding: 3px 5px 3px 5px !important;
+}
+
+.select2-container-multi .select2-choices {
+ min-height: 26px;
+}
+
+.select2-container-multi.select2-container-active .select2-choices {
+ border: 1px solid #5897fb;
+ outline: none;
+
+ -webkit-box-shadow: 0 0 5px rgba(0, 0, 0, .3);
+ box-shadow: 0 0 5px rgba(0, 0, 0, .3);
+}
+.select2-container-multi .select2-choices li {
+ float: left;
+ list-style: none;
+}
+.select2-container-multi .select2-choices .select2-search-field {
+ margin: 0;
+ padding: 0;
+ white-space: nowrap;
+}
+
+.select2-container-multi .select2-choices .select2-search-field input {
+ padding: 5px;
+ margin: 1px 0;
+
+ font-family: sans-serif;
+ font-size: 100%;
+ color: #666;
+ outline: 0;
+ border: 0;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+ background: transparent !important;
+}
+
+.select2-container-multi .select2-choices .select2-search-field input.select2-active {
+ background: #fff url('select2-spinner.gif') no-repeat 100% !important;
+}
+
+.select2-default {
+ color: #999 !important;
+}
+
+.select2-container-multi .select2-choices .select2-search-choice {
+ padding: 3px 5px 3px 18px;
+ margin: 3px 0 3px 5px;
+ position: relative;
+
+ line-height: 13px;
+ color: #333;
+ cursor: default;
+ border: 1px solid #aaaaaa;
+
+ border-radius: 3px;
+
+ -webkit-box-shadow: 0 0 2px #fff inset, 0 1px 0 rgba(0, 0, 0, 0.05);
+ box-shadow: 0 0 2px #fff inset, 0 1px 0 rgba(0, 0, 0, 0.05);
+
+ background-clip: padding-box;
+
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+
+ background-color: #e4e4e4;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#f4f4f4', GradientType=0);
+ background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(20%, #f4f4f4), color-stop(50%, #f0f0f0), color-stop(52%, #e8e8e8), color-stop(100%, #eee));
+ background-image: -webkit-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%);
+ background-image: -moz-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%);
+ background-image: linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%);
+}
+.select2-container-multi .select2-choices .select2-search-choice .select2-chosen {
+ cursor: default;
+}
+.select2-container-multi .select2-choices .select2-search-choice-focus {
+ background: #d4d4d4;
+}
+
+.select2-search-choice-close {
+ display: block;
+ width: 12px;
+ height: 13px;
+ position: absolute;
+ right: 3px;
+ top: 4px;
+
+ font-size: 1px;
+ outline: none;
+ background: url('select2.png') right top no-repeat;
+}
+
+.select2-container-multi .select2-search-choice-close {
+ left: 3px;
+}
+
+.select2-container-multi .select2-choices .select2-search-choice .select2-search-choice-close:hover {
+ background-position: right -11px;
+}
+.select2-container-multi .select2-choices .select2-search-choice-focus .select2-search-choice-close {
+ background-position: right -11px;
+}
+
+/* disabled styles */
+.select2-container-multi.select2-container-disabled .select2-choices {
+ background-color: #f4f4f4;
+ background-image: none;
+ border: 1px solid #ddd;
+ cursor: default;
+}
+
+.select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice {
+ padding: 3px 5px 3px 5px;
+ border: 1px solid #ddd;
+ background-image: none;
+ background-color: #f4f4f4;
+}
+
+.select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice .select2-search-choice-close { display: none;
+ background: none;
+}
+/* end multiselect */
+
+
+.select2-result-selectable .select2-match,
+.select2-result-unselectable .select2-match {
+ text-decoration: underline;
+}
+
+.select2-offscreen, .select2-offscreen:focus {
+ clip: rect(0 0 0 0) !important;
+ width: 1px !important;
+ height: 1px !important;
+ border: 0 !important;
+ margin: 0 !important;
+ padding: 0 !important;
+ overflow: hidden !important;
+ position: absolute !important;
+ outline: 0 !important;
+ left: 0px !important;
+ top: 0px !important;
+}
+
+.select2-display-none {
+ display: none;
+}
+
+.select2-measure-scrollbar {
+ position: absolute;
+ top: -10000px;
+ left: -10000px;
+ width: 100px;
+ height: 100px;
+ overflow: scroll;
+}
+/* Retina-ize icons */
+
+@media only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-resolution: 144dpi) {
+ .select2-search input, .select2-search-choice-close, .select2-container .select2-choice abbr, .select2-container .select2-choice .select2-arrow b {
+ background-image: url('select2x2.png') !important;
+ background-repeat: no-repeat !important;
+ background-size: 60px 40px !important;
+ }
+ .select2-search input {
+ background-position: 100% -21px !important;
+ }
+}
Added: trunk/wao-web/src/main/webapp/js/select2-3.4.5/select2.js
===================================================================
--- trunk/wao-web/src/main/webapp/js/select2-3.4.5/select2.js (rev 0)
+++ trunk/wao-web/src/main/webapp/js/select2-3.4.5/select2.js 2014-03-19 15:11:43 UTC (rev 1728)
@@ -0,0 +1,3255 @@
+/*
+Copyright 2012 Igor Vaynberg
+
+Version: 3.4.5 Timestamp: Mon Nov 4 08:22:42 PST 2013
+
+This software is licensed under the Apache License, Version 2.0 (the "Apache License") or the GNU
+General Public License version 2 (the "GPL License"). You may choose either license to govern your
+use of this software only upon the condition that you accept all of the terms of either the Apache
+License or the GPL License.
+
+You may obtain a copy of the Apache License and the GPL License at:
+
+ http://www.apache.org/licenses/LICENSE-2.0
+ http://www.gnu.org/licenses/gpl-2.0.html
+
+Unless required by applicable law or agreed to in writing, software distributed under the
+Apache License or the GPL Licesnse is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+CONDITIONS OF ANY KIND, either express or implied. See the Apache License and the GPL License for
+the specific language governing permissions and limitations under the Apache License and the GPL License.
+*/
+(function ($) {
+ if(typeof $.fn.each2 == "undefined") {
+ $.extend($.fn, {
+ /*
+ * 4-10 times faster .each replacement
+ * use it carefully, as it overrides jQuery context of element on each iteration
+ */
+ each2 : function (c) {
+ var j = $([0]), i = -1, l = this.length;
+ while (
+ ++i < l
+ && (j.context = j[0] = this[i])
+ && c.call(j[0], i, j) !== false //"this"=DOM, i=index, j=jQuery object
+ );
+ return this;
+ }
+ });
+ }
+})(jQuery);
+
+(function ($, undefined) {
+ "use strict";
+ /*global document, window, jQuery, console */
+
+ if (window.Select2 !== undefined) {
+ return;
+ }
+
+ var KEY, AbstractSelect2, SingleSelect2, MultiSelect2, nextUid, sizer,
+ lastMousePosition={x:0,y:0}, $document, scrollBarDimensions,
+
+ KEY = {
+ TAB: 9,
+ ENTER: 13,
+ ESC: 27,
+ SPACE: 32,
+ LEFT: 37,
+ UP: 38,
+ RIGHT: 39,
+ DOWN: 40,
+ SHIFT: 16,
+ CTRL: 17,
+ ALT: 18,
+ PAGE_UP: 33,
+ PAGE_DOWN: 34,
+ HOME: 36,
+ END: 35,
+ BACKSPACE: 8,
+ DELETE: 46,
+ isArrow: function (k) {
+ k = k.which ? k.which : k;
+ switch (k) {
+ case KEY.LEFT:
+ case KEY.RIGHT:
+ case KEY.UP:
+ case KEY.DOWN:
+ return true;
+ }
+ return false;
+ },
+ isControl: function (e) {
+ var k = e.which;
+ switch (k) {
+ case KEY.SHIFT:
+ case KEY.CTRL:
+ case KEY.ALT:
+ return true;
+ }
+
+ if (e.metaKey) return true;
+
+ return false;
+ },
+ isFunctionKey: function (k) {
+ k = k.which ? k.which : k;
+ return k >= 112 && k <= 123;
+ }
+ },
+ MEASURE_SCROLLBAR_TEMPLATE = "<div class='select2-measure-scrollbar'></div>",
+
+ DIACRITICS = {"\u24B6":"A","\uFF21":"A","\u00C0":"A","\u00C1":"A","\u00C2":"A","\u1EA6":"A","\u1EA4":"A","\u1EAA":"A","\u1EA8":"A","\u00C3":"A","\u0100":"A","\u0102":"A","\u1EB0":"A","\u1EAE":"A","\u1EB4":"A","\u1EB2":"A","\u0226":"A","\u01E0":"A","\u00C4":"A","\u01DE":"A","\u1EA2":"A","\u00C5":"A","\u01FA":"A","\u01CD":"A","\u0200":"A","\u0202":"A","\u1EA0":"A","\u1EAC":"A","\u1EB6":"A","\u1E00":"A","\u0104":"A","\u023A":"A","\u2C6F":"A","\uA732":"AA","\u00C6":"AE","\u01FC":"AE","\u01E2":"AE","\uA734":"AO","\uA736":"AU","\uA738":"AV","\uA73A":"AV","\uA73C":"AY","\u24B7":"B","\uFF22":"B","\u1E02":"B","\u1E04":"B","\u1E06":"B","\u0243":"B","\u0182":"B","\u0181":"B","\u24B8":"C","\uFF23":"C","\u0106":"C","\u0108":"C","\u010A":"C","\u010C":"C","\u00C7":"C","\u1E08":"C","\u0187":"C","\u023B":"C","\uA73E":"C","\u24B9":"D","\uFF24":"D","\u1E0A":"D","\u010E":"D","\u1E0C":"D","\u1E10":"D","\u1E12":"D","\u1E0E":"D","\u0110":"D","\u018B":"D","\u018A":"D","\u0189":"D","\uA779":"D","\u01F1":"DZ","\u01C4":"DZ","\u01F2":"Dz","\u01C5":"Dz","\u24BA":"E","\uFF25":"E","\u00C8":"E","\u00C9":"E","\u00CA":"E","\u1EC0":"E","\u1EBE":"E","\u1EC4":"E","\u1EC2":"E","\u1EBC":"E","\u0112":"E","\u1E14":"E","\u1E16":"E","\u0114":"E","\u0116":"E","\u00CB":"E","\u1EBA":"E","\u011A":"E","\u0204":"E","\u0206":"E","\u1EB8":"E","\u1EC6":"E","\u0228":"E","\u1E1C":"E","\u0118":"E","\u1E18":"E","\u1E1A":"E","\u0190":"E","\u018E":"E","\u24BB":"F","\uFF26":"F","\u1E1E":"F","\u0191":"F","\uA77B":"F","\u24BC":"G","\uFF27":"G","\u01F4":"G","\u011C":"G","\u1E20":"G","\u011E":"G","\u0120":"G","\u01E6":"G","\u0122":"G","\u01E4":"G","\u0193":"G","\uA7A0":"G","\uA77D":"G","\uA77E":"G","\u24BD":"H","\uFF28":"H","\u0124":"H","\u1E22":"H","\u1E26":"H","\u021E":"H","\u1E24":"H","\u1E28":"H","\u1E2A":"H","\u0126":"H","\u2C67":"H","\u2C75":"H","\uA78D":"H","\u24BE":"I","\uFF29":"I","\u00CC":"I","\u00CD":"I","\u00CE":"I","\u0128":"I","\u012A":"I","\u012C":"I","\u0130":"I","\u00CF":"I","\u1E2E":"I","\u1EC8":"I","\u01CF":"I","\u0208":"I","\u020A":"I","\u1ECA":"I","\u012E":"I","\u1E2C":"I","\u0197":"I","\u24BF":"J","\uFF2A":"J","\u0134":"J","\u0248":"J","\u24C0":"K","\uFF2B":"K","\u1E30":"K","\u01E8":"K","\u1E32":"K","\u0136":"K","\u1E34":"K","\u0198":"K","\u2C69":"K","\uA740":"K","\uA742":"K","\uA744":"K","\uA7A2":"K","\u24C1":"L","\uFF2C":"L","\u013F":"L","\u0139":"L","\u013D":"L","\u1E36":"L","\u1E38":"L","\u013B":"L","\u1E3C":"L","\u1E3A":"L","\u0141":"L","\u023D":"L","\u2C62":"L","\u2C60":"L","\uA748":"L","\uA746":"L","\uA780":"L","\u01C7":"LJ","\u01C8":"Lj","\u24C2":"M","\uFF2D":"M","\u1E3E":"M","\u1E40":"M","\u1E42":"M","\u2C6E":"M","\u019C":"M","\u24C3":"N","\uFF2E":"N","\u01F8":"N","\u0143":"N","\u00D1":"N","\u1E44":"N","\u0147":"N","\u1E46":"N","\u0145":"N","\u1E4A":"N","\u1E48":"N","\u0220":"N","\u019D":"N","\uA790":"N","\uA7A4":"N","\u01CA":"NJ","\u01CB":"Nj","\u24C4":"O","\uFF2F":"O","\u00D2":"O","\u00D3":"O","\u00D4":"O","\u1ED2":"O","\u1ED0":"O","\u1ED6":"O","\u1ED4":"O","\u00D5":"O","\u1E4C":"O","\u022C":"O","\u1E4E":"O","\u014C":"O","\u1E50":"O","\u1E52":"O","\u014E":"O","\u022E":"O","\u0230":"O","\u00D6":"O","\u022A":"O","\u1ECE":"O","\u0150":"O","\u01D1":"O","\u020C":"O","\u020E":"O","\u01A0":"O","\u1EDC":"O","\u1EDA":"O","\u1EE0":"O","\u1EDE":"O","\u1EE2":"O","\u1ECC":"O","\u1ED8":"O","\u01EA":"O","\u01EC":"O","\u00D8":"O","\u01FE":"O","\u0186":"O","\u019F":"O","\uA74A":"O","\uA74C":"O","\u01A2":"OI","\uA74E":"OO","\u0222":"OU","\u24C5":"P","\uFF30":"P","\u1E54":"P","\u1E56":"P","\u01A4":"P","\u2C63":"P","\uA750":"P","\uA752":"P","\uA754":"P","\u24C6":"Q","\uFF31":"Q","\uA756":"Q","\uA758":"Q","\u024A":"Q","\u24C7":"R","\uFF32":"R","\u0154":"R","\u1E58":"R","\u0158":"R","\u0210":"R","\u0212":"R","\u1E5A":"R","\u1E5C":"R","\u0156":"R","\u1E5E":"R","\u024C":"R","\u2C64":"R","\uA75A":"R","\uA7A6":"R","\uA782":"R","\u24C8":"S","\uFF33":"S","\u1E9E":"S","\u015A":"S","\u1E64":"S","\u015C":"S","\u1E60":"S","\u0160":"S","\u1E66":"S","\u1E62":"S","\u1E68":"S","\u0218":"S","\u015E":"S","\u2C7E":"S","\uA7A8":"S","\uA784":"S","\u24C9":"T","\uFF34":"T","\u1E6A":"T","\u0164":"T","\u1E6C":"T","\u021A":"T","\u0162":"T","\u1E70":"T","\u1E6E":"T","\u0166":"T","\u01AC":"T","\u01AE":"T","\u023E":"T","\uA786":"T","\uA728":"TZ","\u24CA":"U","\uFF35":"U","\u00D9":"U","\u00DA":"U","\u00DB":"U","\u0168":"U","\u1E78":"U","\u016A":"U","\u1E7A":"U","\u016C":"U","\u00DC":"U","\u01DB":"U","\u01D7":"U","\u01D5":"U","\u01D9":"U","\u1EE6":"U","\u016E":"U","\u0170":"U","\u01D3":"U","\u0214":"U","\u0216":"U","\u01AF":"U","\u1EEA":"U","\u1EE8":"U","\u1EEE":"U","\u1EEC":"U","\u1EF0":"U","\u1EE4":"U","\u1E72":"U","\u0172":"U","\u1E76":"U","\u1E74":"U","\u0244":"U","\u24CB":"V","\uFF36":"V","\u1E7C":"V","\u1E7E":"V","\u01B2":"V","\uA75E":"V","\u0245":"V","\uA760":"VY","\u24CC":"W","\uFF37":"W","\u1E80":"W","\u1E82":"W","\u0174":"W","\u1E86":"W","\u1E84":"W","\u1E88":"W","\u2C72":"W","\u24CD":"X","\uFF38":"X","\u1E8A":"X","\u1E8C":"X","\u24CE":"Y","\uFF39":"Y","\u1EF2":"Y","\u00DD":"Y","\u0176":"Y","\u1EF8":"Y","\u0232":"Y","\u1E8E":"Y","\u0178":"Y","\u1EF6":"Y","\u1EF4":"Y","\u01B3":"Y","\u024E":"Y","\u1EFE":"Y","\u24CF":"Z","\uFF3A":"Z","\u0179":"Z","\u1E90":"Z","\u017B":"Z","\u017D":"Z","\u1E92":"Z","\u1E94":"Z","\u01B5":"Z","\u0224":"Z","\u2C7F":"Z","\u2C6B":"Z","\uA762":"Z","\u24D0":"a","\uFF41":"a","\u1E9A":"a","\u00E0":"a","\u00E1":"a","\u00E2":"a","\u1EA7":"a","\u1EA5":"a","\u1EAB":"a","\u1EA9":"a","\u00E3":"a","\u0101":"a","\u0103":"a","\u1EB1":"a","\u1EAF":"a","\u1EB5":"a","\u1EB3":"a","\u0227":"a","\u01E1":"a","\u00E4":"a","\u01DF":"a","\u1EA3":"a","\u00E5":"a","\u01FB":"a","\u01CE":"a","\u0201":"a","\u0203":"a","\u1EA1":"a","\u1EAD":"a","\u1EB7":"a","\u1E01":"a","\u0105":"a","\u2C65":"a","\u0250":"a","\uA733":"aa","\u00E6":"ae","\u01FD":"ae","\u01E3":"ae","\uA735":"ao","\uA737":"au","\uA739":"av","\uA73B":"av","\uA73D":"ay","\u24D1":"b","\uFF42":"b","\u1E03":"b","\u1E05":"b","\u1E07":"b","\u0180":"b","\u0183":"b","\u0253":"b","\u24D2":"c","\uFF43":"c","\u0107":"c","\u0109":"c","\u010B":"c","\u010D":"c","\u00E7":"c","\u1E09":"c","\u0188":"c","\u023C":"c","\uA73F":"c","\u2184":"c","\u24D3":"d","\uFF44":"d","\u1E0B":"d","\u010F":"d","\u1E0D":"d","\u1E11":"d","\u1E13":"d","\u1E0F":"d","\u0111":"d","\u018C":"d","\u0256":"d","\u0257":"d","\uA77A":"d","\u01F3":"dz","\u01C6":"dz","\u24D4":"e","\uFF45":"e","\u00E8":"e","\u00E9":"e","\u00EA":"e","\u1EC1":"e","\u1EBF":"e","\u1EC5":"e","\u1EC3":"e","\u1EBD":"e","\u0113":"e","\u1E15":"e","\u1E17":"e","\u0115":"e","\u0117":"e","\u00EB":"e","\u1EBB":"e","\u011B":"e","\u0205":"e","\u0207":"e","\u1EB9":"e","\u1EC7":"e","\u0229":"e","\u1E1D":"e","\u0119":"e","\u1E19":"e","\u1E1B":"e","\u0247":"e","\u025B":"e","\u01DD":"e","\u24D5":"f","\uFF46":"f","\u1E1F":"f","\u0192":"f","\uA77C":"f","\u24D6":"g","\uFF47":"g","\u01F5":"g","\u011D":"g","\u1E21":"g","\u011F":"g","\u0121":"g","\u01E7":"g","\u0123":"g","\u01E5":"g","\u0260":"g","\uA7A1":"g","\u1D79":"g","\uA77F":"g","\u24D7":"h","\uFF48":"h","\u0125":"h","\u1E23":"h","\u1E27":"h","\u021F":"h","\u1E25":"h","\u1E29":"h","\u1E2B":"h","\u1E96":"h","\u0127":"h","\u2C68":"h","\u2C76":"h","\u0265":"h","\u0195":"hv","\u24D8":"i","\uFF49":"i","\u00EC":"i","\u00ED":"i","\u00EE":"i","\u0129":"i","\u012B":"i","\u012D":"i","\u00EF":"i","\u1E2F":"i","\u1EC9":"i","\u01D0":"i","\u0209":"i","\u020B":"i","\u1ECB":"i","\u012F":"i","\u1E2D":"i","\u0268":"i","\u0131":"i","\u24D9":"j","\uFF4A":"j","\u0135":"j","\u01F0":"j","\u0249":"j","\u24DA":"k","\uFF4B":"k","\u1E31":"k","\u01E9":"k","\u1E33":"k","\u0137":"k","\u1E35":"k","\u0199":"k","\u2C6A":"k","\uA741":"k","\uA743":"k","\uA745":"k","\uA7A3":"k","\u24DB":"l","\uFF4C":"l","\u0140":"l","\u013A":"l","\u013E":"l","\u1E37":"l","\u1E39":"l","\u013C":"l","\u1E3D":"l","\u1E3B":"l","\u017F":"l","\u0142":"l","\u019A":"l","\u026B":"l","\u2C61":"l","\uA749":"l","\uA781":"l","\uA747":"l","\u01C9":"lj","\u24DC":"m","\uFF4D":"m","\u1E3F":"m","\u1E41":"m","\u1E43":"m","\u0271":"m","\u026F":"m","\u24DD":"n","\uFF4E":"n","\u01F9":"n","\u0144":"n","\u00F1":"n","\u1E45":"n","\u0148":"n","\u1E47":"n","\u0146":"n","\u1E4B":"n","\u1E49":"n","\u019E":"n","\u0272":"n","\u0149":"n","\uA791":"n","\uA7A5":"n","\u01CC":"nj","\u24DE":"o","\uFF4F":"o","\u00F2":"o","\u00F3":"o","\u00F4":"o","\u1ED3":"o","\u1ED1":"o","\u1ED7":"o","\u1ED5":"o","\u00F5":"o","\u1E4D":"o","\u022D":"o","\u1E4F":"o","\u014D":"o","\u1E51":"o","\u1E53":"o","\u014F":"o","\u022F":"o","\u0231":"o","\u00F6":"o","\u022B":"o","\u1ECF":"o","\u0151":"o","\u01D2":"o","\u020D":"o","\u020F":"o","\u01A1":"o","\u1EDD":"o","\u1EDB":"o","\u1EE1":"o","\u1EDF":"o","\u1EE3":"o","\u1ECD":"o","\u1ED9":"o","\u01EB":"o","\u01ED":"o","\u00F8":"o","\u01FF":"o","\u0254":"o","\uA74B":"o","\uA74D":"o","\u0275":"o","\u01A3":"oi","\u0223":"ou","\uA74F":"oo","\u24DF":"p","\uFF50":"p","\u1E55":"p","\u1E57":"p","\u01A5":"p","\u1D7D":"p","\uA751":"p","\uA753":"p","\uA755":"p","\u24E0":"q","\uFF51":"q","\u024B":"q","\uA757":"q","\uA759":"q","\u24E1":"r","\uFF52":"r","\u0155":"r","\u1E59":"r","\u0159":"r","\u0211":"r","\u0213":"r","\u1E5B":"r","\u1E5D":"r","\u0157":"r","\u1E5F":"r","\u024D":"r","\u027D":"r","\uA75B":"r","\uA7A7":"r","\uA783":"r","\u24E2":"s","\uFF53":"s","\u00DF":"s","\u015B":"s","\u1E65":"s","\u015D":"s","\u1E61":"s","\u0161":"s","\u1E67":"s","\u1E63":"s","\u1E69":"s","\u0219":"s","\u015F":"s","\u023F":"s","\uA7A9":"s","\uA785":"s","\u1E9B":"s","\u24E3":"t","\uFF54":"t","\u1E6B":"t","\u1E97":"t","\u0165":"t","\u1E6D":"t","\u021B":"t","\u0163":"t","\u1E71":"t","\u1E6F":"t","\u0167":"t","\u01AD":"t","\u0288":"t","\u2C66":"t","\uA787":"t","\uA729":"tz","\u24E4":"u","\uFF55":"u","\u00F9":"u","\u00FA":"u","\u00FB":"u","\u0169":"u","\u1E79":"u","\u016B":"u","\u1E7B":"u","\u016D":"u","\u00FC":"u","\u01DC":"u","\u01D8":"u","\u01D6":"u","\u01DA":"u","\u1EE7":"u","\u016F":"u","\u0171":"u","\u01D4":"u","\u0215":"u","\u0217":"u","\u01B0":"u","\u1EEB":"u","\u1EE9":"u","\u1EEF":"u","\u1EED":"u","\u1EF1":"u","\u1EE5":"u","\u1E73":"u","\u0173":"u","\u1E77":"u","\u1E75":"u","\u0289":"u","\u24E5":"v","\uFF56":"v","\u1E7D":"v","\u1E7F":"v","\u028B":"v","\uA75F":"v","\u028C":"v","\uA761":"vy","\u24E6":"w","\uFF57":"w","\u1E81":"w","\u1E83":"w","\u0175":"w","\u1E87":"w","\u1E85":"w","\u1E98":"w","\u1E89":"w","\u2C73":"w","\u24E7":"x","\uFF58":"x","\u1E8B":"x","\u1E8D":"x","\u24E8":"y","\uFF59":"y","\u1EF3":"y","\u00FD":"y","\u0177":"y","\u1EF9":"y","\u0233":"y","\u1E8F":"y","\u00FF":"y","\u1EF7":"y","\u1E99":"y","\u1EF5":"y","\u01B4":"y","\u024F":"y","\u1EFF":"y","\u24E9":"z","\uFF5A":"z","\u017A":"z","\u1E91":"z","\u017C":"z","\u017E":"z","\u1E93":"z","\u1E95":"z","\u01B6":"z","\u0225":"z","\u0240":"z","\u2C6C":"z","\uA763":"z"};
+
+ $document = $(document);
+
+ nextUid=(function() { var counter=1; return function() { return counter++; }; }());
+
+
+ function stripDiacritics(str) {
+ var ret, i, l, c;
+
+ if (!str || str.length < 1) return str;
+
+ ret = "";
+ for (i = 0, l = str.length; i < l; i++) {
+ c = str.charAt(i);
+ ret += DIACRITICS[c] || c;
+ }
+ return ret;
+ }
+
+ function indexOf(value, array) {
+ var i = 0, l = array.length;
+ for (; i < l; i = i + 1) {
+ if (equal(value, array[i])) return i;
+ }
+ return -1;
+ }
+
+ function measureScrollbar () {
+ var $template = $( MEASURE_SCROLLBAR_TEMPLATE );
+ $template.appendTo('body');
+
+ var dim = {
+ width: $template.width() - $template[0].clientWidth,
+ height: $template.height() - $template[0].clientHeight
+ };
+ $template.remove();
+
+ return dim;
+ }
+
+ /**
+ * Compares equality of a and b
+ * @param a
+ * @param b
+ */
+ function equal(a, b) {
+ if (a === b) return true;
+ if (a === undefined || b === undefined) return false;
+ if (a === null || b === null) return false;
+ // Check whether 'a' or 'b' is a string (primitive or object).
+ // The concatenation of an empty string (+'') converts its argument to a string's primitive.
+ if (a.constructor === String) return a+'' === b+''; // a+'' - in case 'a' is a String object
+ if (b.constructor === String) return b+'' === a+''; // b+'' - in case 'b' is a String object
+ return false;
+ }
+
+ /**
+ * Splits the string into an array of values, trimming each value. An empty array is returned for nulls or empty
+ * strings
+ * @param string
+ * @param separator
+ */
+ function splitVal(string, separator) {
+ var val, i, l;
+ if (string === null || string.length < 1) return [];
+ val = string.split(separator);
+ for (i = 0, l = val.length; i < l; i = i + 1) val[i] = $.trim(val[i]);
+ return val;
+ }
+
+ function getSideBorderPadding(element) {
+ return element.outerWidth(false) - element.width();
+ }
+
+ function installKeyUpChangeEvent(element) {
+ var key="keyup-change-value";
+ element.on("keydown", function () {
+ if ($.data(element, key) === undefined) {
+ $.data(element, key, element.val());
+ }
+ });
+ element.on("keyup", function () {
+ var val= $.data(element, key);
+ if (val !== undefined && element.val() !== val) {
+ $.removeData(element, key);
+ element.trigger("keyup-change");
+ }
+ });
+ }
+
+ $document.on("mousemove", function (e) {
+ lastMousePosition.x = e.pageX;
+ lastMousePosition.y = e.pageY;
+ });
+
+ /**
+ * filters mouse events so an event is fired only if the mouse moved.
+ *
+ * filters out mouse events that occur when mouse is stationary but
+ * the elements under the pointer are scrolled.
+ */
+ function installFilteredMouseMove(element) {
+ element.on("mousemove", function (e) {
+ var lastpos = lastMousePosition;
+ if (lastpos === undefined || lastpos.x !== e.pageX || lastpos.y !== e.pageY) {
+ $(e.target).trigger("mousemove-filtered", e);
+ }
+ });
+ }
+
+ /**
+ * Debounces a function. Returns a function that calls the original fn function only if no invocations have been made
+ * within the last quietMillis milliseconds.
+ *
+ * @param quietMillis number of milliseconds to wait before invoking fn
+ * @param fn function to be debounced
+ * @param ctx object to be used as this reference within fn
+ * @return debounced version of fn
+ */
+ function debounce(quietMillis, fn, ctx) {
+ ctx = ctx || undefined;
+ var timeout;
+ return function () {
+ var args = arguments;
+ window.clearTimeout(timeout);
+ timeout = window.setTimeout(function() {
+ fn.apply(ctx, args);
+ }, quietMillis);
+ };
+ }
+
+ /**
+ * A simple implementation of a thunk
+ * @param formula function used to lazily initialize the thunk
+ * @return {Function}
+ */
+ function thunk(formula) {
+ var evaluated = false,
+ value;
+ return function() {
+ if (evaluated === false) { value = formula(); evaluated = true; }
+ return value;
+ };
+ };
+
+ function installDebouncedScroll(threshold, element) {
+ var notify = debounce(threshold, function (e) { element.trigger("scroll-debounced", e);});
+ element.on("scroll", function (e) {
+ if (indexOf(e.target, element.get()) >= 0) notify(e);
+ });
+ }
+
+ function focus($el) {
+ if ($el[0] === document.activeElement) return;
+
+ /* set the focus in a 0 timeout - that way the focus is set after the processing
+ of the current event has finished - which seems like the only reliable way
+ to set focus */
+ window.setTimeout(function() {
+ var el=$el[0], pos=$el.val().length, range;
+
+ $el.focus();
+
+ /* make sure el received focus so we do not error out when trying to manipulate the caret.
+ sometimes modals or others listeners may steal it after its set */
+ if ($el.is(":visible") && el === document.activeElement) {
+
+ /* after the focus is set move the caret to the end, necessary when we val()
+ just before setting focus */
+ if(el.setSelectionRange)
+ {
+ el.setSelectionRange(pos, pos);
+ }
+ else if (el.createTextRange) {
+ range = el.createTextRange();
+ range.collapse(false);
+ range.select();
+ }
+ }
+ }, 0);
+ }
+
+ function getCursorInfo(el) {
+ el = $(el)[0];
+ var offset = 0;
+ var length = 0;
+ if ('selectionStart' in el) {
+ offset = el.selectionStart;
+ length = el.selectionEnd - offset;
+ } else if ('selection' in document) {
+ el.focus();
+ var sel = document.selection.createRange();
+ length = document.selection.createRange().text.length;
+ sel.moveStart('character', -el.value.length);
+ offset = sel.text.length - length;
+ }
+ return { offset: offset, length: length };
+ }
+
+ function killEvent(event) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ function killEventImmediately(event) {
+ event.preventDefault();
+ event.stopImmediatePropagation();
+ }
+
+ function measureTextWidth(e) {
+ if (!sizer){
+ var style = e[0].currentStyle || window.getComputedStyle(e[0], null);
+ sizer = $(document.createElement("div")).css({
+ position: "absolute",
+ left: "-10000px",
+ top: "-10000px",
+ display: "none",
+ fontSize: style.fontSize,
+ fontFamily: style.fontFamily,
+ fontStyle: style.fontStyle,
+ fontWeight: style.fontWeight,
+ letterSpacing: style.letterSpacing,
+ textTransform: style.textTransform,
+ whiteSpace: "nowrap"
+ });
+ sizer.attr("class","select2-sizer");
+ $("body").append(sizer);
+ }
+ sizer.text(e.val());
+ return sizer.width();
+ }
+
+ function syncCssClasses(dest, src, adapter) {
+ var classes, replacements = [], adapted;
+
+ classes = dest.attr("class");
+ if (classes) {
+ classes = '' + classes; // for IE which returns object
+ $(classes.split(" ")).each2(function() {
+ if (this.indexOf("select2-") === 0) {
+ replacements.push(this);
+ }
+ });
+ }
+ classes = src.attr("class");
+ if (classes) {
+ classes = '' + classes; // for IE which returns object
+ $(classes.split(" ")).each2(function() {
+ if (this.indexOf("select2-") !== 0) {
+ adapted = adapter(this);
+ if (adapted) {
+ replacements.push(adapted);
+ }
+ }
+ });
+ }
+ dest.attr("class", replacements.join(" "));
+ }
+
+
+ function markMatch(text, term, markup, escapeMarkup) {
+ var match=stripDiacritics(text.toUpperCase()).indexOf(stripDiacritics(term.toUpperCase())),
+ tl=term.length;
+
+ if (match<0) {
+ markup.push(escapeMarkup(text));
+ return;
+ }
+
+ markup.push(escapeMarkup(text.substring(0, match)));
+ markup.push("<span class='select2-match'>");
+ markup.push(escapeMarkup(text.substring(match, match + tl)));
+ markup.push("</span>");
+ markup.push(escapeMarkup(text.substring(match + tl, text.length)));
+ }
+
+ function defaultEscapeMarkup(markup) {
+ var replace_map = {
+ '\\': '\',
+ '&': '&',
+ '<': '<',
+ '>': '>',
+ '"': '"',
+ "'": ''',
+ "/": '/'
+ };
+
+ return String(markup).replace(/[&<>"'\/\\]/g, function (match) {
+ return replace_map[match];
+ });
+ }
+
+ /**
+ * Produces an ajax-based query function
+ *
+ * @param options object containing configuration paramters
+ * @param options.params parameter map for the transport ajax call, can contain such options as cache, jsonpCallback, etc. see $.ajax
+ * @param options.transport function that will be used to execute the ajax request. must be compatible with parameters supported by $.ajax
+ * @param options.url url for the data
+ * @param options.data a function(searchTerm, pageNumber, context) that should return an object containing query string parameters for the above url.
+ * @param options.dataType request data type: ajax, jsonp, other datatatypes supported by jQuery's $.ajax function or the transport function if specified
+ * @param options.quietMillis (optional) milliseconds to wait before making the ajaxRequest, helps debounce the ajax function if invoked too often
+ * @param options.results a function(remoteData, pageNumber) that converts data returned form the remote request to the format expected by Select2.
+ * The expected format is an object containing the following keys:
+ * results array of objects that will be used as choices
+ * more (optional) boolean indicating whether there are more results available
+ * Example: {results:[{id:1, text:'Red'},{id:2, text:'Blue'}], more:true}
+ */
+ function ajax(options) {
+ var timeout, // current scheduled but not yet executed request
+ handler = null,
+ quietMillis = options.quietMillis || 100,
+ ajaxUrl = options.url,
+ self = this;
+
+ return function (query) {
+ window.clearTimeout(timeout);
+ timeout = window.setTimeout(function () {
+ var data = options.data, // ajax data function
+ url = ajaxUrl, // ajax url string or function
+ transport = options.transport || $.fn.select2.ajaxDefaults.transport,
+ // deprecated - to be removed in 4.0 - use params instead
+ deprecated = {
+ type: options.type || 'GET', // set type of request (GET or POST)
+ cache: options.cache || false,
+ jsonpCallback: options.jsonpCallback||undefined,
+ dataType: options.dataType||"json"
+ },
+ params = $.extend({}, $.fn.select2.ajaxDefaults.params, deprecated);
+
+ data = data ? data.call(self, query.term, query.page, query.context) : null;
+ url = (typeof url === 'function') ? url.call(self, query.term, query.page, query.context) : url;
+
+ if (handler) { handler.abort(); }
+
+ if (options.params) {
+ if ($.isFunction(options.params)) {
+ $.extend(params, options.params.call(self));
+ } else {
+ $.extend(params, options.params);
+ }
+ }
+
+ $.extend(params, {
+ url: url,
+ dataType: options.dataType,
+ data: data,
+ success: function (data) {
+ // TODO - replace query.page with query so users have access to term, page, etc.
+ var results = options.results(data, query.page);
+ query.callback(results);
+ }
+ });
+ handler = transport.call(self, params);
+ }, quietMillis);
+ };
+ }
+
+ /**
+ * Produces a query function that works with a local array
+ *
+ * @param options object containing configuration parameters. The options parameter can either be an array or an
+ * object.
+ *
+ * If the array form is used it is assumed that it contains objects with 'id' and 'text' keys.
+ *
+ * If the object form is used ti is assumed that it contains 'data' and 'text' keys. The 'data' key should contain
+ * an array of objects that will be used as choices. These objects must contain at least an 'id' key. The 'text'
+ * key can either be a String in which case it is expected that each element in the 'data' array has a key with the
+ * value of 'text' which will be used to match choices. Alternatively, text can be a function(item) that can extract
+ * the text.
+ */
+ function local(options) {
+ var data = options, // data elements
+ dataText,
+ tmp,
+ text = function (item) { return ""+item.text; }; // function used to retrieve the text portion of a data item that is matched against the search
+
+ if ($.isArray(data)) {
+ tmp = data;
+ data = { results: tmp };
+ }
+
+ if ($.isFunction(data) === false) {
+ tmp = data;
+ data = function() { return tmp; };
+ }
+
+ var dataItem = data();
+ if (dataItem.text) {
+ text = dataItem.text;
+ // if text is not a function we assume it to be a key name
+ if (!$.isFunction(text)) {
+ dataText = dataItem.text; // we need to store this in a separate variable because in the next step data gets reset and data.text is no longer available
+ text = function (item) { return item[dataText]; };
+ }
+ }
+
+ return function (query) {
+ var t = query.term, filtered = { results: [] }, process;
+ if (t === "") {
+ query.callback(data());
+ return;
+ }
+
+ process = function(datum, collection) {
+ var group, attr;
+ datum = datum[0];
+ if (datum.children) {
+ group = {};
+ for (attr in datum) {
+ if (datum.hasOwnProperty(attr)) group[attr]=datum[attr];
+ }
+ group.children=[];
+ $(datum.children).each2(function(i, childDatum) { process(childDatum, group.children); });
+ if (group.children.length || query.matcher(t, text(group), datum)) {
+ collection.push(group);
+ }
+ } else {
+ if (query.matcher(t, text(datum), datum)) {
+ collection.push(datum);
+ }
+ }
+ };
+
+ $(data().results).each2(function(i, datum) { process(datum, filtered.results); });
+ query.callback(filtered);
+ };
+ }
+
+ // TODO javadoc
+ function tags(data) {
+ var isFunc = $.isFunction(data);
+ return function (query) {
+ var t = query.term, filtered = {results: []};
+ $(isFunc ? data() : data).each(function () {
+ var isObject = this.text !== undefined,
+ text = isObject ? this.text : this;
+ if (t === "" || query.matcher(t, text)) {
+ filtered.results.push(isObject ? this : {id: this, text: this});
+ }
+ });
+ query.callback(filtered);
+ };
+ }
+
+ /**
+ * Checks if the formatter function should be used.
+ *
+ * Throws an error if it is not a function. Returns true if it should be used,
+ * false if no formatting should be performed.
+ *
+ * @param formatter
+ */
+ function checkFormatter(formatter, formatterName) {
+ if ($.isFunction(formatter)) return true;
+ if (!formatter) return false;
+ throw new Error(formatterName +" must be a function or a falsy value");
+ }
+
+ function evaluate(val) {
+ return $.isFunction(val) ? val() : val;
+ }
+
+ function countResults(results) {
+ var count = 0;
+ $.each(results, function(i, item) {
+ if (item.children) {
+ count += countResults(item.children);
+ } else {
+ count++;
+ }
+ });
+ return count;
+ }
+
+ /**
+ * Default tokenizer. This function uses breaks the input on substring match of any string from the
+ * opts.tokenSeparators array and uses opts.createSearchChoice to create the choice object. Both of those
+ * two options have to be defined in order for the tokenizer to work.
+ *
+ * @param input text user has typed so far or pasted into the search field
+ * @param selection currently selected choices
+ * @param selectCallback function(choice) callback tho add the choice to selection
+ * @param opts select2's opts
+ * @return undefined/null to leave the current input unchanged, or a string to change the input to the returned value
+ */
+ function defaultTokenizer(input, selection, selectCallback, opts) {
+ var original = input, // store the original so we can compare and know if we need to tell the search to update its text
+ dupe = false, // check for whether a token we extracted represents a duplicate selected choice
+ token, // token
+ index, // position at which the separator was found
+ i, l, // looping variables
+ separator; // the matched separator
+
+ if (!opts.createSearchChoice || !opts.tokenSeparators || opts.tokenSeparators.length < 1) return undefined;
+
+ while (true) {
+ index = -1;
+
+ for (i = 0, l = opts.tokenSeparators.length; i < l; i++) {
+ separator = opts.tokenSeparators[i];
+ index = input.indexOf(separator);
+ if (index >= 0) break;
+ }
+
+ if (index < 0) break; // did not find any token separator in the input string, bail
+
+ token = input.substring(0, index);
+ input = input.substring(index + separator.length);
+
+ if (token.length > 0) {
+ token = opts.createSearchChoice.call(this, token, selection);
+ if (token !== undefined && token !== null && opts.id(token) !== undefined && opts.id(token) !== null) {
+ dupe = false;
+ for (i = 0, l = selection.length; i < l; i++) {
+ if (equal(opts.id(token), opts.id(selection[i]))) {
+ dupe = true; break;
+ }
+ }
+
+ if (!dupe) selectCallback(token);
+ }
+ }
+ }
+
+ if (original!==input) return input;
+ }
+
+ /**
+ * Creates a new class
+ *
+ * @param superClass
+ * @param methods
+ */
+ function clazz(SuperClass, methods) {
+ var constructor = function () {};
+ constructor.prototype = new SuperClass;
+ constructor.prototype.constructor = constructor;
+ constructor.prototype.parent = SuperClass.prototype;
+ constructor.prototype = $.extend(constructor.prototype, methods);
+ return constructor;
+ }
+
+ AbstractSelect2 = clazz(Object, {
+
+ // abstract
+ bind: function (func) {
+ var self = this;
+ return function () {
+ func.apply(self, arguments);
+ };
+ },
+
+ // abstract
+ init: function (opts) {
+ var results, search, resultsSelector = ".select2-results";
+
+ // prepare options
+ this.opts = opts = this.prepareOpts(opts);
+
+ this.id=opts.id;
+
+ // destroy if called on an existing component
+ if (opts.element.data("select2") !== undefined &&
+ opts.element.data("select2") !== null) {
+ opts.element.data("select2").destroy();
+ }
+
+ this.container = this.createContainer();
+
+ this.containerId="s2id_"+(opts.element.attr("id") || "autogen"+nextUid());
+ this.containerSelector="#"+this.containerId.replace(/([;&,\.\+\*\~':"\!\^#$%@\[\]\(\)=>\|])/g, '\\$1');
+ this.container.attr("id", this.containerId);
+
+ // cache the body so future lookups are cheap
+ this.body = thunk(function() { return opts.element.closest("body"); });
+
+ syncCssClasses(this.container, this.opts.element, this.opts.adaptContainerCssClass);
+
+ this.container.attr("style", opts.element.attr("style"));
+ this.container.css(evaluate(opts.containerCss));
+ this.container.addClass(evaluate(opts.containerCssClass));
+
+ this.elementTabIndex = this.opts.element.attr("tabindex");
+
+ // swap container for the element
+ this.opts.element
+ .data("select2", this)
+ .attr("tabindex", "-1")
+ .before(this.container)
+ .on("click.select2", killEvent); // do not leak click events
+
+ this.container.data("select2", this);
+
+ this.dropdown = this.container.find(".select2-drop");
+
+ syncCssClasses(this.dropdown, this.opts.element, this.opts.adaptDropdownCssClass);
+
+ this.dropdown.addClass(evaluate(opts.dropdownCssClass));
+ this.dropdown.data("select2", this);
+ this.dropdown.on("click", killEvent);
+
+ this.results = results = this.container.find(resultsSelector);
+ this.search = search = this.container.find("input.select2-input");
+
+ this.queryCount = 0;
+ this.resultsPage = 0;
+ this.context = null;
+
+ // initialize the container
+ this.initContainer();
+
+ this.container.on("click", killEvent);
+
+ installFilteredMouseMove(this.results);
+ this.dropdown.on("mousemove-filtered touchstart touchmove touchend", resultsSelector, this.bind(this.highlightUnderEvent));
+
+ installDebouncedScroll(80, this.results);
+ this.dropdown.on("scroll-debounced", resultsSelector, this.bind(this.loadMoreIfNeeded));
+
+ // do not propagate change event from the search field out of the component
+ $(this.container).on("change", ".select2-input", function(e) {e.stopPropagation();});
+ $(this.dropdown).on("change", ".select2-input", function(e) {e.stopPropagation();});
+
+ // if jquery.mousewheel plugin is installed we can prevent out-of-bounds scrolling of results via mousewheel
+ if ($.fn.mousewheel) {
+ results.mousewheel(function (e, delta, deltaX, deltaY) {
+ var top = results.scrollTop();
+ if (deltaY > 0 && top - deltaY <= 0) {
+ results.scrollTop(0);
+ killEvent(e);
+ } else if (deltaY < 0 && results.get(0).scrollHeight - results.scrollTop() + deltaY <= results.height()) {
+ results.scrollTop(results.get(0).scrollHeight - results.height());
+ killEvent(e);
+ }
+ });
+ }
+
+ installKeyUpChangeEvent(search);
+ search.on("keyup-change input paste", this.bind(this.updateResults));
+ search.on("focus", function () { search.addClass("select2-focused"); });
+ search.on("blur", function () { search.removeClass("select2-focused");});
+
+ this.dropdown.on("mouseup", resultsSelector, this.bind(function (e) {
+ if ($(e.target).closest(".select2-result-selectable").length > 0) {
+ this.highlightUnderEvent(e);
+ this.selectHighlighted(e);
+ }
+ }));
+
+ // trap all mouse events from leaving the dropdown. sometimes there may be a modal that is listening
+ // for mouse events outside of itself so it can close itself. since the dropdown is now outside the select2's
+ // dom it will trigger the popup close, which is not what we want
+ this.dropdown.on("click mouseup mousedown", function (e) { e.stopPropagation(); });
+
+ if ($.isFunction(this.opts.initSelection)) {
+ // initialize selection based on the current value of the source element
+ this.initSelection();
+
+ // if the user has provided a function that can set selection based on the value of the source element
+ // we monitor the change event on the element and trigger it, allowing for two way synchronization
+ this.monitorSource();
+ }
+
+ if (opts.maximumInputLength !== null) {
+ this.search.attr("maxlength", opts.maximumInputLength);
+ }
+
+ var disabled = opts.element.prop("disabled");
+ if (disabled === undefined) disabled = false;
+ this.enable(!disabled);
+
+ var readonly = opts.element.prop("readonly");
+ if (readonly === undefined) readonly = false;
+ this.readonly(readonly);
+
+ // Calculate size of scrollbar
+ scrollBarDimensions = scrollBarDimensions || measureScrollbar();
+
+ this.autofocus = opts.element.prop("autofocus");
+ opts.element.prop("autofocus", false);
+ if (this.autofocus) this.focus();
+
+ this.nextSearchTerm = undefined;
+ },
+
+ // abstract
+ destroy: function () {
+ var element=this.opts.element, select2 = element.data("select2");
+
+ this.close();
+
+ if (this.propertyObserver) { delete this.propertyObserver; this.propertyObserver = null; }
+
+ if (select2 !== undefined) {
+ select2.container.remove();
+ select2.dropdown.remove();
+ element
+ .removeClass("select2-offscreen")
+ .removeData("select2")
+ .off(".select2")
+ .prop("autofocus", this.autofocus || false);
+ if (this.elementTabIndex) {
+ element.attr({tabindex: this.elementTabIndex});
+ } else {
+ element.removeAttr("tabindex");
+ }
+ element.show();
+ }
+ },
+
+ // abstract
+ optionToData: function(element) {
+ if (element.is("option")) {
+ return {
+ id:element.prop("value"),
+ text:element.text(),
+ element: element.get(),
+ css: element.attr("class"),
+ disabled: element.prop("disabled"),
+ locked: equal(element.attr("locked"), "locked") || equal(element.data("locked"), true)
+ };
+ } else if (element.is("optgroup")) {
+ return {
+ text:element.attr("label"),
+ children:[],
+ element: element.get(),
+ css: element.attr("class")
+ };
+ }
+ },
+
+ // abstract
+ prepareOpts: function (opts) {
+ var element, select, idKey, ajaxUrl, self = this;
+
+ element = opts.element;
+
+ if (element.get(0).tagName.toLowerCase() === "select") {
+ this.select = select = opts.element;
+ }
+
+ if (select) {
+ // these options are not allowed when attached to a select because they are picked up off the element itself
+ $.each(["id", "multiple", "ajax", "query", "createSearchChoice", "initSelection", "data", "tags"], function () {
+ if (this in opts) {
+ throw new Error("Option '" + this + "' is not allowed for Select2 when attached to a <select> element.");
+ }
+ });
+ }
+
+ opts = $.extend({}, {
+ populateResults: function(container, results, query) {
+ var populate, id=this.opts.id;
+
+ populate=function(results, container, depth) {
+
+ var i, l, result, selectable, disabled, compound, node, label, innerContainer, formatted;
+
+ results = opts.sortResults(results, container, query);
+
+ for (i = 0, l = results.length; i < l; i = i + 1) {
+
+ result=results[i];
+
+ disabled = (result.disabled === true);
+ selectable = (!disabled) && (id(result) !== undefined);
+
+ compound=result.children && result.children.length > 0;
+
+ node=$("<li></li>");
+ node.addClass("select2-results-dept-"+depth);
+ node.addClass("select2-result");
+ node.addClass(selectable ? "select2-result-selectable" : "select2-result-unselectable");
+ if (disabled) { node.addClass("select2-disabled"); }
+ if (compound) { node.addClass("select2-result-with-children"); }
+ node.addClass(self.opts.formatResultCssClass(result));
+
+ label=$(document.createElement("div"));
+ label.addClass("select2-result-label");
+
+ formatted=opts.formatResult(result, label, query, self.opts.escapeMarkup);
+ if (formatted!==undefined) {
+ label.html(formatted);
+ }
+
+ node.append(label);
+
+ if (compound) {
+
+ innerContainer=$("<ul></ul>");
+ innerContainer.addClass("select2-result-sub");
+ populate(result.children, innerContainer, depth+1);
+ node.append(innerContainer);
+ }
+
+ node.data("select2-data", result);
+ container.append(node);
+ }
+ };
+
+ populate(results, container, 0);
+ }
+ }, $.fn.select2.defaults, opts);
+
+ if (typeof(opts.id) !== "function") {
+ idKey = opts.id;
+ opts.id = function (e) { return e[idKey]; };
+ }
+
+ if ($.isArray(opts.element.data("select2Tags"))) {
+ if ("tags" in opts) {
+ throw "tags specified as both an attribute 'data-select2-tags' and in options of Select2 " + opts.element.attr("id");
+ }
+ opts.tags=opts.element.data("select2Tags");
+ }
+
+ if (select) {
+ opts.query = this.bind(function (query) {
+ var data = { results: [], more: false },
+ term = query.term,
+ children, placeholderOption, process;
+
+ process=function(element, collection) {
+ var group;
+ if (element.is("option")) {
+ if (query.matcher(term, element.text(), element)) {
+ collection.push(self.optionToData(element));
+ }
+ } else if (element.is("optgroup")) {
+ group=self.optionToData(element);
+ element.children().each2(function(i, elm) { process(elm, group.children); });
+ if (group.children.length>0) {
+ collection.push(group);
+ }
+ }
+ };
+
+ children=element.children();
+
+ // ignore the placeholder option if there is one
+ if (this.getPlaceholder() !== undefined && children.length > 0) {
+ placeholderOption = this.getPlaceholderOption();
+ if (placeholderOption) {
+ children=children.not(placeholderOption);
+ }
+ }
+
+ children.each2(function(i, elm) { process(elm, data.results); });
+
+ query.callback(data);
+ });
+ // this is needed because inside val() we construct choices from options and there id is hardcoded
+ opts.id=function(e) { return e.id; };
+ opts.formatResultCssClass = function(data) { return data.css; };
+ } else {
+ if (!("query" in opts)) {
+
+ if ("ajax" in opts) {
+ ajaxUrl = opts.element.data("ajax-url");
+ if (ajaxUrl && ajaxUrl.length > 0) {
+ opts.ajax.url = ajaxUrl;
+ }
+ opts.query = ajax.call(opts.element, opts.ajax);
+ } else if ("data" in opts) {
+ opts.query = local(opts.data);
+ } else if ("tags" in opts) {
+ opts.query = tags(opts.tags);
+ if (opts.createSearchChoice === undefined) {
+ opts.createSearchChoice = function (term) { return {id: $.trim(term), text: $.trim(term)}; };
+ }
+ if (opts.initSelection === undefined) {
+ opts.initSelection = function (element, callback) {
+ var data = [];
+ $(splitVal(element.val(), opts.separator)).each(function () {
+ var obj = { id: this, text: this },
+ tags = opts.tags;
+ if ($.isFunction(tags)) tags=tags();
+ $(tags).each(function() { if (equal(this.id, obj.id)) { obj = this; return false; } });
+ data.push(obj);
+ });
+
+ callback(data);
+ };
+ }
+ }
+ }
+ }
+ if (typeof(opts.query) !== "function") {
+ throw "query function not defined for Select2 " + opts.element.attr("id");
+ }
+
+ return opts;
+ },
+
+ /**
+ * Monitor the original element for changes and update select2 accordingly
+ */
+ // abstract
+ monitorSource: function () {
+ var el = this.opts.element, sync, observer;
+
+ el.on("change.select2", this.bind(function (e) {
+ if (this.opts.element.data("select2-change-triggered") !== true) {
+ this.initSelection();
+ }
+ }));
+
+ sync = this.bind(function () {
+
+ // sync enabled state
+ var disabled = el.prop("disabled");
+ if (disabled === undefined) disabled = false;
+ this.enable(!disabled);
+
+ var readonly = el.prop("readonly");
+ if (readonly === undefined) readonly = false;
+ this.readonly(readonly);
+
+ syncCssClasses(this.container, this.opts.element, this.opts.adaptContainerCssClass);
+ this.container.addClass(evaluate(this.opts.containerCssClass));
+
+ syncCssClasses(this.dropdown, this.opts.element, this.opts.adaptDropdownCssClass);
+ this.dropdown.addClass(evaluate(this.opts.dropdownCssClass));
+
+ });
+
+ // IE8-10
+ el.on("propertychange.select2", sync);
+
+ // hold onto a reference of the callback to work around a chromium bug
+ if (this.mutationCallback === undefined) {
+ this.mutationCallback = function (mutations) {
+ mutations.forEach(sync);
+ }
+ }
+
+ // safari, chrome, firefox, IE11
+ observer = window.MutationObserver || window.WebKitMutationObserver|| window.MozMutationObserver;
+ if (observer !== undefined) {
+ if (this.propertyObserver) { delete this.propertyObserver; this.propertyObserver = null; }
+ this.propertyObserver = new observer(this.mutationCallback);
+ this.propertyObserver.observe(el.get(0), { attributes:true, subtree:false });
+ }
+ },
+
+ // abstract
+ triggerSelect: function(data) {
+ var evt = $.Event("select2-selecting", { val: this.id(data), object: data });
+ this.opts.element.trigger(evt);
+ return !evt.isDefaultPrevented();
+ },
+
+ /**
+ * Triggers the change event on the source element
+ */
+ // abstract
+ triggerChange: function (details) {
+
+ details = details || {};
+ details= $.extend({}, details, { type: "change", val: this.val() });
+ // prevents recursive triggering
+ this.opts.element.data("select2-change-triggered", true);
+ this.opts.element.trigger(details);
+ this.opts.element.data("select2-change-triggered", false);
+
+ // some validation frameworks ignore the change event and listen instead to keyup, click for selects
+ // so here we trigger the click event manually
+ this.opts.element.click();
+
+ // ValidationEngine ignorea the change event and listens instead to blur
+ // so here we trigger the blur event manually if so desired
+ if (this.opts.blurOnChange)
+ this.opts.element.blur();
+ },
+
+ //abstract
+ isInterfaceEnabled: function()
+ {
+ return this.enabledInterface === true;
+ },
+
+ // abstract
+ enableInterface: function() {
+ var enabled = this._enabled && !this._readonly,
+ disabled = !enabled;
+
+ if (enabled === this.enabledInterface) return false;
+
+ this.container.toggleClass("select2-container-disabled", disabled);
+ this.close();
+ this.enabledInterface = enabled;
+
+ return true;
+ },
+
+ // abstract
+ enable: function(enabled) {
+ if (enabled === undefined) enabled = true;
+ if (this._enabled === enabled) return;
+ this._enabled = enabled;
+
+ this.opts.element.prop("disabled", !enabled);
+ this.enableInterface();
+ },
+
+ // abstract
+ disable: function() {
+ this.enable(false);
+ },
+
+ // abstract
+ readonly: function(enabled) {
+ if (enabled === undefined) enabled = false;
+ if (this._readonly === enabled) return false;
+ this._readonly = enabled;
+
+ this.opts.element.prop("readonly", enabled);
+ this.enableInterface();
+ return true;
+ },
+
+ // abstract
+ opened: function () {
+ return this.container.hasClass("select2-dropdown-open");
+ },
+
+ // abstract
+ positionDropdown: function() {
+ var $dropdown = this.dropdown,
+ offset = this.container.offset(),
+ height = this.container.outerHeight(false),
+ width = this.container.outerWidth(false),
+ dropHeight = $dropdown.outerHeight(false),
+ $window = $(window),
+ windowWidth = $window.width(),
+ windowHeight = $window.height(),
+ viewPortRight = $window.scrollLeft() + windowWidth,
+ viewportBottom = $window.scrollTop() + windowHeight,
+ dropTop = offset.top + height,
+ dropLeft = offset.left,
+ enoughRoomBelow = dropTop + dropHeight <= viewportBottom,
+ enoughRoomAbove = (offset.top - dropHeight) >= this.body().scrollTop(),
+ dropWidth = $dropdown.outerWidth(false),
+ enoughRoomOnRight = dropLeft + dropWidth <= viewPortRight,
+ aboveNow = $dropdown.hasClass("select2-drop-above"),
+ bodyOffset,
+ above,
+ changeDirection,
+ css,
+ resultsListNode;
+
+ // always prefer the current above/below alignment, unless there is not enough room
+ if (aboveNow) {
+ above = true;
+ if (!enoughRoomAbove && enoughRoomBelow) {
+ changeDirection = true;
+ above = false;
+ }
+ } else {
+ above = false;
+ if (!enoughRoomBelow && enoughRoomAbove) {
+ changeDirection = true;
+ above = true;
+ }
+ }
+
+ //if we are changing direction we need to get positions when dropdown is hidden;
+ if (changeDirection) {
+ $dropdown.hide();
+ offset = this.container.offset();
+ height = this.container.outerHeight(false);
+ width = this.container.outerWidth(false);
+ dropHeight = $dropdown.outerHeight(false);
+ viewPortRight = $window.scrollLeft() + windowWidth;
+ viewportBottom = $window.scrollTop() + windowHeight;
+ dropTop = offset.top + height;
+ dropLeft = offset.left;
+ dropWidth = $dropdown.outerWidth(false);
+ enoughRoomOnRight = dropLeft + dropWidth <= viewPortRight;
+ $dropdown.show();
+ }
+
+ if (this.opts.dropdownAutoWidth) {
+ resultsListNode = $('.select2-results', $dropdown)[0];
+ $dropdown.addClass('select2-drop-auto-width');
+ $dropdown.css('width', '');
+ // Add scrollbar width to dropdown if vertical scrollbar is present
+ dropWidth = $dropdown.outerWidth(false) + (resultsListNode.scrollHeight === resultsListNode.clientHeight ? 0 : scrollBarDimensions.width);
+ dropWidth > width ? width = dropWidth : dropWidth = width;
+ enoughRoomOnRight = dropLeft + dropWidth <= viewPortRight;
+ }
+ else {
+ this.container.removeClass('select2-drop-auto-width');
+ }
+
+ //console.log("below/ droptop:", dropTop, "dropHeight", dropHeight, "sum", (dropTop+dropHeight)+" viewport bottom", viewportBottom, "enough?", enoughRoomBelow);
+ //console.log("above/ offset.top", offset.top, "dropHeight", dropHeight, "top", (offset.top-dropHeight), "scrollTop", this.body().scrollTop(), "enough?", enoughRoomAbove);
+
+ // fix positioning when body has an offset and is not position: static
+ if (this.body().css('position') !== 'static') {
+ bodyOffset = this.body().offset();
+ dropTop -= bodyOffset.top;
+ dropLeft -= bodyOffset.left;
+ }
+
+ if (!enoughRoomOnRight) {
+ dropLeft = offset.left + width - dropWidth;
+ }
+
+ css = {
+ left: dropLeft,
+ width: width
+ };
+
+ if (above) {
+ css.bottom = windowHeight - offset.top;
+ css.top = 'auto';
+ this.container.addClass("select2-drop-above");
+ $dropdown.addClass("select2-drop-above");
+ }
+ else {
+ css.top = dropTop;
+ css.bottom = 'auto';
+ this.container.removeClass("select2-drop-above");
+ $dropdown.removeClass("select2-drop-above");
+ }
+ css = $.extend(css, evaluate(this.opts.dropdownCss));
+
+ $dropdown.css(css);
+ },
+
+ // abstract
+ shouldOpen: function() {
+ var event;
+
+ if (this.opened()) return false;
+
+ if (this._enabled === false || this._readonly === true) return false;
+
+ event = $.Event("select2-opening");
+ this.opts.element.trigger(event);
+ return !event.isDefaultPrevented();
+ },
+
+ // abstract
+ clearDropdownAlignmentPreference: function() {
+ // clear the classes used to figure out the preference of where the dropdown should be opened
+ this.container.removeClass("select2-drop-above");
+ this.dropdown.removeClass("select2-drop-above");
+ },
+
+ /**
+ * Opens the dropdown
+ *
+ * @return {Boolean} whether or not dropdown was opened. This method will return false if, for example,
+ * the dropdown is already open, or if the 'open' event listener on the element called preventDefault().
+ */
+ // abstract
+ open: function () {
+
+ if (!this.shouldOpen()) return false;
+
+ this.opening();
+
+ return true;
+ },
+
+ /**
+ * Performs the opening of the dropdown
+ */
+ // abstract
+ opening: function() {
+ var cid = this.containerId,
+ scroll = "scroll." + cid,
+ resize = "resize."+cid,
+ orient = "orientationchange."+cid,
+ mask;
+
+ this.container.addClass("select2-dropdown-open").addClass("select2-container-active");
+
+ this.clearDropdownAlignmentPreference();
+
+ if(this.dropdown[0] !== this.body().children().last()[0]) {
+ this.dropdown.detach().appendTo(this.body());
+ }
+
+ // create the dropdown mask if doesnt already exist
+ mask = $("#select2-drop-mask");
+ if (mask.length == 0) {
+ mask = $(document.createElement("div"));
+ mask.attr("id","select2-drop-mask").attr("class","select2-drop-mask");
+ mask.hide();
+ mask.appendTo(this.body());
+ mask.on("mousedown touchstart click", function (e) {
+ var dropdown = $("#select2-drop"), self;
+ if (dropdown.length > 0) {
+ self=dropdown.data("select2");
+ if (self.opts.selectOnBlur) {
+ self.selectHighlighted({noFocus: true});
+ }
+ self.close({focus:true});
+ e.preventDefault();
+ e.stopPropagation();
+ }
+ });
+ }
+
+ // ensure the mask is always right before the dropdown
+ if (this.dropdown.prev()[0] !== mask[0]) {
+ this.dropdown.before(mask);
+ }
+
+ // move the global id to the correct dropdown
+ $("#select2-drop").removeAttr("id");
+ this.dropdown.attr("id", "select2-drop");
+
+ // show the elements
+ mask.show();
+
+ this.positionDropdown();
+ this.dropdown.show();
+ this.positionDropdown();
+
+ this.dropdown.addClass("select2-drop-active");
+
+ // attach listeners to events that can change the position of the container and thus require
+ // the position of the dropdown to be updated as well so it does not come unglued from the container
+ var that = this;
+ this.container.parents().add(window).each(function () {
+ $(this).on(resize+" "+scroll+" "+orient, function (e) {
+ that.positionDropdown();
+ });
+ });
+
+
+ },
+
+ // abstract
+ close: function () {
+ if (!this.opened()) return;
+
+ var cid = this.containerId,
+ scroll = "scroll." + cid,
+ resize = "resize."+cid,
+ orient = "orientationchange."+cid;
+
+ // unbind event listeners
+ this.container.parents().add(window).each(function () { $(this).off(scroll).off(resize).off(orient); });
+
+ this.clearDropdownAlignmentPreference();
+
+ $("#select2-drop-mask").hide();
+ this.dropdown.removeAttr("id"); // only the active dropdown has the select2-drop id
+ this.dropdown.hide();
+ this.container.removeClass("select2-dropdown-open").removeClass("select2-container-active");
+ this.results.empty();
+
+
+ this.clearSearch();
+ this.search.removeClass("select2-active");
+ this.opts.element.trigger($.Event("select2-close"));
+ },
+
+ /**
+ * Opens control, sets input value, and updates results.
+ */
+ // abstract
+ externalSearch: function (term) {
+ this.open();
+ this.search.val(term);
+ this.updateResults(false);
+ },
+
+ // abstract
+ clearSearch: function () {
+
+ },
+
+ //abstract
+ getMaximumSelectionSize: function() {
+ return evaluate(this.opts.maximumSelectionSize);
+ },
+
+ // abstract
+ ensureHighlightVisible: function () {
+ var results = this.results, children, index, child, hb, rb, y, more;
+
+ index = this.highlight();
+
+ if (index < 0) return;
+
+ if (index == 0) {
+
+ // if the first element is highlighted scroll all the way to the top,
+ // that way any unselectable headers above it will also be scrolled
+ // into view
+
+ results.scrollTop(0);
+ return;
+ }
+
+ children = this.findHighlightableChoices().find('.select2-result-label');
+
+ child = $(children[index]);
+
+ hb = child.offset().top + child.outerHeight(true);
+
+ // if this is the last child lets also make sure select2-more-results is visible
+ if (index === children.length - 1) {
+ more = results.find("li.select2-more-results");
+ if (more.length > 0) {
+ hb = more.offset().top + more.outerHeight(true);
+ }
+ }
+
+ rb = results.offset().top + results.outerHeight(true);
+ if (hb > rb) {
+ results.scrollTop(results.scrollTop() + (hb - rb));
+ }
+ y = child.offset().top - results.offset().top;
+
+ // make sure the top of the element is visible
+ if (y < 0 && child.css('display') != 'none' ) {
+ results.scrollTop(results.scrollTop() + y); // y is negative
+ }
+ },
+
+ // abstract
+ findHighlightableChoices: function() {
+ return this.results.find(".select2-result-selectable:not(.select2-disabled, .select2-selected)");
+ },
+
+ // abstract
+ moveHighlight: function (delta) {
+ var choices = this.findHighlightableChoices(),
+ index = this.highlight();
+
+ while (index > -1 && index < choices.length) {
+ index += delta;
+ var choice = $(choices[index]);
+ if (choice.hasClass("select2-result-selectable") && !choice.hasClass("select2-disabled") && !choice.hasClass("select2-selected")) {
+ this.highlight(index);
+ break;
+ }
+ }
+ },
+
+ // abstract
+ highlight: function (index) {
+ var choices = this.findHighlightableChoices(),
+ choice,
+ data;
+
+ if (arguments.length === 0) {
+ return indexOf(choices.filter(".select2-highlighted")[0], choices.get());
+ }
+
+ if (index >= choices.length) index = choices.length - 1;
+ if (index < 0) index = 0;
+
+ this.removeHighlight();
+
+ choice = $(choices[index]);
+ choice.addClass("select2-highlighted");
+
+ this.ensureHighlightVisible();
+
+ data = choice.data("select2-data");
+ if (data) {
+ this.opts.element.trigger({ type: "select2-highlight", val: this.id(data), choice: data });
+ }
+ },
+
+ removeHighlight: function() {
+ this.results.find(".select2-highlighted").removeClass("select2-highlighted");
+ },
+
+ // abstract
+ countSelectableResults: function() {
+ return this.findHighlightableChoices().length;
+ },
+
+ // abstract
+ highlightUnderEvent: function (event) {
+ var el = $(event.target).closest(".select2-result-selectable");
+ if (el.length > 0 && !el.is(".select2-highlighted")) {
+ var choices = this.findHighlightableChoices();
+ this.highlight(choices.index(el));
+ } else if (el.length == 0) {
+ // if we are over an unselectable item remove all highlights
+ this.removeHighlight();
+ }
+ },
+
+ // abstract
+ loadMoreIfNeeded: function () {
+ var results = this.results,
+ more = results.find("li.select2-more-results"),
+ below, // pixels the element is below the scroll fold, below==0 is when the element is starting to be visible
+ page = this.resultsPage + 1,
+ self=this,
+ term=this.search.val(),
+ context=this.context;
+
+ if (more.length === 0) return;
+ below = more.offset().top - results.offset().top - results.height();
+
+ if (below <= this.opts.loadMorePadding) {
+ more.addClass("select2-active");
+ this.opts.query({
+ element: this.opts.element,
+ term: term,
+ page: page,
+ context: context,
+ matcher: this.opts.matcher,
+ callback: this.bind(function (data) {
+
+ // ignore a response if the select2 has been closed before it was received
+ if (!self.opened()) return;
+
+
+ self.opts.populateResults.call(this, results, data.results, {term: term, page: page, context:context});
+ self.postprocessResults(data, false, false);
+
+ if (data.more===true) {
+ more.detach().appendTo(results).text(self.opts.formatLoadMore(page+1));
+ window.setTimeout(function() { self.loadMoreIfNeeded(); }, 10);
+ } else {
+ more.remove();
+ }
+ self.positionDropdown();
+ self.resultsPage = page;
+ self.context = data.context;
+ this.opts.element.trigger({ type: "select2-loaded", items: data });
+ })});
+ }
+ },
+
+ /**
+ * Default tokenizer function which does nothing
+ */
+ tokenize: function() {
+
+ },
+
+ /**
+ * @param initial whether or not this is the call to this method right after the dropdown has been opened
+ */
+ // abstract
+ updateResults: function (initial) {
+ var search = this.search,
+ results = this.results,
+ opts = this.opts,
+ data,
+ self = this,
+ input,
+ term = search.val(),
+ lastTerm = $.data(this.container, "select2-last-term"),
+ // sequence number used to drop out-of-order responses
+ queryNumber;
+
+ // prevent duplicate queries against the same term
+ if (initial !== true && lastTerm && equal(term, lastTerm)) return;
+
+ $.data(this.container, "select2-last-term", term);
+
+ // if the search is currently hidden we do not alter the results
+ if (initial !== true && (this.showSearchInput === false || !this.opened())) {
+ return;
+ }
+
+ function postRender() {
+ search.removeClass("select2-active");
+ self.positionDropdown();
+ }
+
+ function render(html) {
+ results.html(html);
+ postRender();
+ }
+
+ queryNumber = ++this.queryCount;
+
+ var maxSelSize = this.getMaximumSelectionSize();
+ if (maxSelSize >=1) {
+ data = this.data();
+ if ($.isArray(data) && data.length >= maxSelSize && checkFormatter(opts.formatSelectionTooBig, "formatSelectionTooBig")) {
+ render("<li class='select2-selection-limit'>" + opts.formatSelectionTooBig(maxSelSize) + "</li>");
+ return;
+ }
+ }
+
+ if (search.val().length < opts.minimumInputLength) {
+ if (checkFormatter(opts.formatInputTooShort, "formatInputTooShort")) {
+ render("<li class='select2-no-results'>" + opts.formatInputTooShort(search.val(), opts.minimumInputLength) + "</li>");
+ } else {
+ render("");
+ }
+ if (initial && this.showSearch) this.showSearch(true);
+ return;
+ }
+
+ if (opts.maximumInputLength && search.val().length > opts.maximumInputLength) {
+ if (checkFormatter(opts.formatInputTooLong, "formatInputTooLong")) {
+ render("<li class='select2-no-results'>" + opts.formatInputTooLong(search.val(), opts.maximumInputLength) + "</li>");
+ } else {
+ render("");
+ }
+ return;
+ }
+
+ if (opts.formatSearching && this.findHighlightableChoices().length === 0) {
+ render("<li class='select2-searching'>" + opts.formatSearching() + "</li>");
+ }
+
+ search.addClass("select2-active");
+
+ this.removeHighlight();
+
+ // give the tokenizer a chance to pre-process the input
+ input = this.tokenize();
+ if (input != undefined && input != null) {
+ search.val(input);
+ }
+
+ this.resultsPage = 1;
+
+ opts.query({
+ element: opts.element,
+ term: search.val(),
+ page: this.resultsPage,
+ context: null,
+ matcher: opts.matcher,
+ callback: this.bind(function (data) {
+ var def; // default choice
+
+ // ignore old responses
+ if (queryNumber != this.queryCount) {
+ return;
+ }
+
+ // ignore a response if the select2 has been closed before it was received
+ if (!this.opened()) {
+ this.search.removeClass("select2-active");
+ return;
+ }
+
+ // save context, if any
+ this.context = (data.context===undefined) ? null : data.context;
+ // create a default choice and prepend it to the list
+ if (this.opts.createSearchChoice && search.val() !== "") {
+ def = this.opts.createSearchChoice.call(self, search.val(), data.results);
+ if (def !== undefined && def !== null && self.id(def) !== undefined && self.id(def) !== null) {
+ if ($(data.results).filter(
+ function () {
+ return equal(self.id(this), self.id(def));
+ }).length === 0) {
+ data.results.unshift(def);
+ }
+ }
+ }
+
+ if (data.results.length === 0 && checkFormatter(opts.formatNoMatches, "formatNoMatches")) {
+ render("<li class='select2-no-results'>" + opts.formatNoMatches(search.val()) + "</li>");
+ return;
+ }
+
+ results.empty();
+ self.opts.populateResults.call(this, results, data.results, {term: search.val(), page: this.resultsPage, context:null});
+
+ if (data.more === true && checkFormatter(opts.formatLoadMore, "formatLoadMore")) {
+ results.append("<li class='select2-more-results'>" + self.opts.escapeMarkup(opts.formatLoadMore(this.resultsPage)) + "</li>");
+ window.setTimeout(function() { self.loadMoreIfNeeded(); }, 10);
+ }
+
+ this.postprocessResults(data, initial);
+
+ postRender();
+
+ this.opts.element.trigger({ type: "select2-loaded", items: data });
+ })});
+ },
+
+ // abstract
+ cancel: function () {
+ this.close();
+ },
+
+ // abstract
+ blur: function () {
+ // if selectOnBlur == true, select the currently highlighted option
+ if (this.opts.selectOnBlur)
+ this.selectHighlighted({noFocus: true});
+
+ this.close();
+ this.container.removeClass("select2-container-active");
+ // synonymous to .is(':focus'), which is available in jquery >= 1.6
+ if (this.search[0] === document.activeElement) { this.search.blur(); }
+ this.clearSearch();
+ this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus");
+ },
+
+ // abstract
+ focusSearch: function () {
+ focus(this.search);
+ },
+
+ // abstract
+ selectHighlighted: function (options) {
+ var index=this.highlight(),
+ highlighted=this.results.find(".select2-highlighted"),
+ data = highlighted.closest('.select2-result').data("select2-data");
+
+ if (data) {
+ this.highlight(index);
+ this.onSelect(data, options);
+ } else if (options && options.noFocus) {
+ this.close();
+ }
+ },
+
+ // abstract
+ getPlaceholder: function () {
+ var placeholderOption;
+ return this.opts.element.attr("placeholder") ||
+ this.opts.element.attr("data-placeholder") || // jquery 1.4 compat
+ this.opts.element.data("placeholder") ||
+ this.opts.placeholder ||
+ ((placeholderOption = this.getPlaceholderOption()) !== undefined ? placeholderOption.text() : undefined);
+ },
+
+ // abstract
+ getPlaceholderOption: function() {
+ if (this.select) {
+ var firstOption = this.select.children('option').first();
+ if (this.opts.placeholderOption !== undefined ) {
+ //Determine the placeholder option based on the specified placeholderOption setting
+ return (this.opts.placeholderOption === "first" && firstOption) ||
+ (typeof this.opts.placeholderOption === "function" && this.opts.placeholderOption(this.select));
+ } else if (firstOption.text() === "" && firstOption.val() === "") {
+ //No explicit placeholder option specified, use the first if it's blank
+ return firstOption;
+ }
+ }
+ },
+
+ /**
+ * Get the desired width for the container element. This is
+ * derived first from option `width` passed to select2, then
+ * the inline 'style' on the original element, and finally
+ * falls back to the jQuery calculated element width.
+ */
+ // abstract
+ initContainerWidth: function () {
+ function resolveContainerWidth() {
+ var style, attrs, matches, i, l, attr;
+
+ if (this.opts.width === "off") {
+ return null;
+ } else if (this.opts.width === "element"){
+ return this.opts.element.outerWidth(false) === 0 ? 'auto' : this.opts.element.outerWidth(false) + 'px';
+ } else if (this.opts.width === "copy" || this.opts.width === "resolve") {
+ // check if there is inline style on the element that contains width
+ style = this.opts.element.attr('style');
+ if (style !== undefined) {
+ attrs = style.split(';');
+ for (i = 0, l = attrs.length; i < l; i = i + 1) {
+ attr = attrs[i].replace(/\s/g, '');
+ matches = attr.match(/^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i);
+ if (matches !== null && matches.length >= 1)
+ return matches[1];
+ }
+ }
+
+ if (this.opts.width === "resolve") {
+ // next check if css('width') can resolve a width that is percent based, this is sometimes possible
+ // when attached to input type=hidden or elements hidden via css
+ style = this.opts.element.css('width');
+ if (style.indexOf("%") > 0) return style;
+
+ // finally, fallback on the calculated width of the element
+ return (this.opts.element.outerWidth(false) === 0 ? 'auto' : this.opts.element.outerWidth(false) + 'px');
+ }
+
+ return null;
+ } else if ($.isFunction(this.opts.width)) {
+ return this.opts.width();
+ } else {
+ return this.opts.width;
+ }
+ };
+
+ var width = resolveContainerWidth.call(this);
+ if (width !== null) {
+ this.container.css("width", width);
+ }
+ }
+ });
+
+ SingleSelect2 = clazz(AbstractSelect2, {
+
+ // single
+
+ createContainer: function () {
+ var container = $(document.createElement("div")).attr({
+ "class": "select2-container"
+ }).html([
+ "<a href='javascript:void(0)' onclick='return false;' class='select2-choice' tabindex='-1'>",
+ " <span class='select2-chosen'> </span><abbr class='select2-search-choice-close'></abbr>",
+ " <span class='select2-arrow'><b></b></span>",
+ "</a>",
+ "<input class='select2-focusser select2-offscreen' type='text'/>",
+ "<div class='select2-drop select2-display-none'>",
+ " <div class='select2-search'>",
+ " <input type='text' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false' class='select2-input'/>",
+ " </div>",
+ " <ul class='select2-results'>",
+ " </ul>",
+ "</div>"].join(""));
+ return container;
+ },
+
+ // single
+ enableInterface: function() {
+ if (this.parent.enableInterface.apply(this, arguments)) {
+ this.focusser.prop("disabled", !this.isInterfaceEnabled());
+ }
+ },
+
+ // single
+ opening: function () {
+ var el, range, len;
+
+ if (this.opts.minimumResultsForSearch >= 0) {
+ this.showSearch(true);
+ }
+
+ this.parent.opening.apply(this, arguments);
+
+ if (this.showSearchInput !== false) {
+ // IE appends focusser.val() at the end of field :/ so we manually insert it at the beginning using a range
+ // all other browsers handle this just fine
+
+ this.search.val(this.focusser.val());
+ }
+ this.search.focus();
+ // move the cursor to the end after focussing, otherwise it will be at the beginning and
+ // new text will appear *before* focusser.val()
+ el = this.search.get(0);
+ if (el.createTextRange) {
+ range = el.createTextRange();
+ range.collapse(false);
+ range.select();
+ } else if (el.setSelectionRange) {
+ len = this.search.val().length;
+ el.setSelectionRange(len, len);
+ }
+
+ // initializes search's value with nextSearchTerm (if defined by user)
+ // ignore nextSearchTerm if the dropdown is opened by the user pressing a letter
+ if(this.search.val() === "") {
+ if(this.nextSearchTerm != undefined){
+ this.search.val(this.nextSearchTerm);
+ this.search.select();
+ }
+ }
+
+ this.focusser.prop("disabled", true).val("");
+ this.updateResults(true);
+ this.opts.element.trigger($.Event("select2-open"));
+ },
+
+ // single
+ close: function (params) {
+ if (!this.opened()) return;
+ this.parent.close.apply(this, arguments);
+
+ params = params || {focus: true};
+ this.focusser.removeAttr("disabled");
+
+ if (params.focus) {
+ this.focusser.focus();
+ }
+ },
+
+ // single
+ focus: function () {
+ if (this.opened()) {
+ this.close();
+ } else {
+ this.focusser.removeAttr("disabled");
+ this.focusser.focus();
+ }
+ },
+
+ // single
+ isFocused: function () {
+ return this.container.hasClass("select2-container-active");
+ },
+
+ // single
+ cancel: function () {
+ this.parent.cancel.apply(this, arguments);
+ this.focusser.removeAttr("disabled");
+ this.focusser.focus();
+ },
+
+ // single
+ destroy: function() {
+ $("label[for='" + this.focusser.attr('id') + "']")
+ .attr('for', this.opts.element.attr("id"));
+ this.parent.destroy.apply(this, arguments);
+ },
+
+ // single
+ initContainer: function () {
+
+ var selection,
+ container = this.container,
+ dropdown = this.dropdown;
+
+ if (this.opts.minimumResultsForSearch < 0) {
+ this.showSearch(false);
+ } else {
+ this.showSearch(true);
+ }
+
+ this.selection = selection = container.find(".select2-choice");
+
+ this.focusser = container.find(".select2-focusser");
+
+ // rewrite labels from original element to focusser
+ this.focusser.attr("id", "s2id_autogen"+nextUid());
+
+ $("label[for='" + this.opts.element.attr("id") + "']")
+ .attr('for', this.focusser.attr('id'));
+
+ this.focusser.attr("tabindex", this.elementTabIndex);
+
+ this.search.on("keydown", this.bind(function (e) {
+ if (!this.isInterfaceEnabled()) return;
+
+ if (e.which === KEY.PAGE_UP || e.which === KEY.PAGE_DOWN) {
+ // prevent the page from scrolling
+ killEvent(e);
+ return;
+ }
+
+ switch (e.which) {
+ case KEY.UP:
+ case KEY.DOWN:
+ this.moveHighlight((e.which === KEY.UP) ? -1 : 1);
+ killEvent(e);
+ return;
+ case KEY.ENTER:
+ this.selectHighlighted();
+ killEvent(e);
+ return;
+ case KEY.TAB:
+ this.selectHighlighted({noFocus: true});
+ return;
+ case KEY.ESC:
+ this.cancel(e);
+ killEvent(e);
+ return;
+ }
+ }));
+
+ this.search.on("blur", this.bind(function(e) {
+ // a workaround for chrome to keep the search field focussed when the scroll bar is used to scroll the dropdown.
+ // without this the search field loses focus which is annoying
+ if (document.activeElement === this.body().get(0)) {
+ window.setTimeout(this.bind(function() {
+ this.search.focus();
+ }), 0);
+ }
+ }));
+
+ this.focusser.on("keydown", this.bind(function (e) {
+ if (!this.isInterfaceEnabled()) return;
+
+ if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) || e.which === KEY.ESC) {
+ return;
+ }
+
+ if (this.opts.openOnEnter === false && e.which === KEY.ENTER) {
+ killEvent(e);
+ return;
+ }
+
+ if (e.which == KEY.DOWN || e.which == KEY.UP
+ || (e.which == KEY.ENTER && this.opts.openOnEnter)) {
+
+ if (e.altKey || e.ctrlKey || e.shiftKey || e.metaKey) return;
+
+ this.open();
+ killEvent(e);
+ return;
+ }
+
+ if (e.which == KEY.DELETE || e.which == KEY.BACKSPACE) {
+ if (this.opts.allowClear) {
+ this.clear();
+ }
+ killEvent(e);
+ return;
+ }
+ }));
+
+
+ installKeyUpChangeEvent(this.focusser);
+ this.focusser.on("keyup-change input", this.bind(function(e) {
+ if (this.opts.minimumResultsForSearch >= 0) {
+ e.stopPropagation();
+ if (this.opened()) return;
+ this.open();
+ }
+ }));
+
+ selection.on("mousedown", "abbr", this.bind(function (e) {
+ if (!this.isInterfaceEnabled()) return;
+ this.clear();
+ killEventImmediately(e);
+ this.close();
+ this.selection.focus();
+ }));
+
+ selection.on("mousedown", this.bind(function (e) {
+
+ if (!this.container.hasClass("select2-container-active")) {
+ this.opts.element.trigger($.Event("select2-focus"));
+ }
+
+ if (this.opened()) {
+ this.close();
+ } else if (this.isInterfaceEnabled()) {
+ this.open();
+ }
+
+ killEvent(e);
+ }));
+
+ dropdown.on("mousedown", this.bind(function() { this.search.focus(); }));
+
+ selection.on("focus", this.bind(function(e) {
+ killEvent(e);
+ }));
+
+ this.focusser.on("focus", this.bind(function(){
+ if (!this.container.hasClass("select2-container-active")) {
+ this.opts.element.trigger($.Event("select2-focus"));
+ }
+ this.container.addClass("select2-container-active");
+ })).on("blur", this.bind(function() {
+ if (!this.opened()) {
+ this.container.removeClass("select2-container-active");
+ this.opts.element.trigger($.Event("select2-blur"));
+ }
+ }));
+ this.search.on("focus", this.bind(function(){
+ if (!this.container.hasClass("select2-container-active")) {
+ this.opts.element.trigger($.Event("select2-focus"));
+ }
+ this.container.addClass("select2-container-active");
+ }));
+
+ this.initContainerWidth();
+ this.opts.element.addClass("select2-offscreen");
+ this.setPlaceholder();
+
+ },
+
+ // single
+ clear: function(triggerChange) {
+ var data=this.selection.data("select2-data");
+ if (data) { // guard against queued quick consecutive clicks
+ var evt = $.Event("select2-clearing");
+ this.opts.element.trigger(evt);
+ if (evt.isDefaultPrevented()) {
+ return;
+ }
+ var placeholderOption = this.getPlaceholderOption();
+ this.opts.element.val(placeholderOption ? placeholderOption.val() : "");
+ this.selection.find(".select2-chosen").empty();
+ this.selection.removeData("select2-data");
+ this.setPlaceholder();
+
+ if (triggerChange !== false){
+ this.opts.element.trigger({ type: "select2-removed", val: this.id(data), choice: data });
+ this.triggerChange({removed:data});
+ }
+ }
+ },
+
+ /**
+ * Sets selection based on source element's value
+ */
+ // single
+ initSelection: function () {
+ var selected;
+ if (this.isPlaceholderOptionSelected()) {
+ this.updateSelection(null);
+ this.close();
+ this.setPlaceholder();
+ } else {
+ var self = this;
+ this.opts.initSelection.call(null, this.opts.element, function(selected){
+ if (selected !== undefined && selected !== null) {
+ self.updateSelection(selected);
+ self.close();
+ self.setPlaceholder();
+ }
+ });
+ }
+ },
+
+ isPlaceholderOptionSelected: function() {
+ var placeholderOption;
+ if (!this.getPlaceholder()) return false; // no placeholder specified so no option should be considered
+ return ((placeholderOption = this.getPlaceholderOption()) !== undefined && placeholderOption.prop("selected"))
+ || (this.opts.element.val() === "")
+ || (this.opts.element.val() === undefined)
+ || (this.opts.element.val() === null);
+ },
+
+ // single
+ prepareOpts: function () {
+ var opts = this.parent.prepareOpts.apply(this, arguments),
+ self=this;
+
+ if (opts.element.get(0).tagName.toLowerCase() === "select") {
+ // install the selection initializer
+ opts.initSelection = function (element, callback) {
+ var selected = element.find("option").filter(function() { return this.selected });
+ // a single select box always has a value, no need to null check 'selected'
+ callback(self.optionToData(selected));
+ };
+ } else if ("data" in opts) {
+ // install default initSelection when applied to hidden input and data is local
+ opts.initSelection = opts.initSelection || function (element, callback) {
+ var id = element.val();
+ //search in data by id, storing the actual matching item
+ var match = null;
+ opts.query({
+ matcher: function(term, text, el){
+ var is_match = equal(id, opts.id(el));
+ if (is_match) {
+ match = el;
+ }
+ return is_match;
+ },
+ callback: !$.isFunction(callback) ? $.noop : function() {
+ callback(match);
+ }
+ });
+ };
+ }
+
+ return opts;
+ },
+
+ // single
+ getPlaceholder: function() {
+ // if a placeholder is specified on a single select without a valid placeholder option ignore it
+ if (this.select) {
+ if (this.getPlaceholderOption() === undefined) {
+ return undefined;
+ }
+ }
+
+ return this.parent.getPlaceholder.apply(this, arguments);
+ },
+
+ // single
+ setPlaceholder: function () {
+ var placeholder = this.getPlaceholder();
+
+ if (this.isPlaceholderOptionSelected() && placeholder !== undefined) {
+
+ // check for a placeholder option if attached to a select
+ if (this.select && this.getPlaceholderOption() === undefined) return;
+
+ this.selection.find(".select2-chosen").html(this.opts.escapeMarkup(placeholder));
+
+ this.selection.addClass("select2-default");
+
+ this.container.removeClass("select2-allowclear");
+ }
+ },
+
+ // single
+ postprocessResults: function (data, initial, noHighlightUpdate) {
+ var selected = 0, self = this, showSearchInput = true;
+
+ // find the selected element in the result list
+
+ this.findHighlightableChoices().each2(function (i, elm) {
+ if (equal(self.id(elm.data("select2-data")), self.opts.element.val())) {
+ selected = i;
+ return false;
+ }
+ });
+
+ // and highlight it
+ if (noHighlightUpdate !== false) {
+ if (initial === true && selected >= 0) {
+ this.highlight(selected);
+ } else {
+ this.highlight(0);
+ }
+ }
+
+ // hide the search box if this is the first we got the results and there are enough of them for search
+
+ if (initial === true) {
+ var min = this.opts.minimumResultsForSearch;
+ if (min >= 0) {
+ this.showSearch(countResults(data.results) >= min);
+ }
+ }
+ },
+
+ // single
+ showSearch: function(showSearchInput) {
+ if (this.showSearchInput === showSearchInput) return;
+
+ this.showSearchInput = showSearchInput;
+
+ this.dropdown.find(".select2-search").toggleClass("select2-search-hidden", !showSearchInput);
+ this.dropdown.find(".select2-search").toggleClass("select2-offscreen", !showSearchInput);
+ //add "select2-with-searchbox" to the container if search box is shown
+ $(this.dropdown, this.container).toggleClass("select2-with-searchbox", showSearchInput);
+ },
+
+ // single
+ onSelect: function (data, options) {
+
+ if (!this.triggerSelect(data)) { return; }
+
+ var old = this.opts.element.val(),
+ oldData = this.data();
+
+ this.opts.element.val(this.id(data));
+ this.updateSelection(data);
+
+ this.opts.element.trigger({ type: "select2-selected", val: this.id(data), choice: data });
+
+ this.nextSearchTerm = this.opts.nextSearchTerm(data, this.search.val());
+ this.close();
+
+ if (!options || !options.noFocus)
+ this.focusser.focus();
+
+ if (!equal(old, this.id(data))) { this.triggerChange({added:data,removed:oldData}); }
+ },
+
+ // single
+ updateSelection: function (data) {
+
+ var container=this.selection.find(".select2-chosen"), formatted, cssClass;
+
+ this.selection.data("select2-data", data);
+
+ container.empty();
+ if (data !== null) {
+ formatted=this.opts.formatSelection(data, container, this.opts.escapeMarkup);
+ }
+ if (formatted !== undefined) {
+ container.append(formatted);
+ }
+ cssClass=this.opts.formatSelectionCssClass(data, container);
+ if (cssClass !== undefined) {
+ container.addClass(cssClass);
+ }
+
+ this.selection.removeClass("select2-default");
+
+ if (this.opts.allowClear && this.getPlaceholder() !== undefined) {
+ this.container.addClass("select2-allowclear");
+ }
+ },
+
+ // single
+ val: function () {
+ var val,
+ triggerChange = false,
+ data = null,
+ self = this,
+ oldData = this.data();
+
+ if (arguments.length === 0) {
+ return this.opts.element.val();
+ }
+
+ val = arguments[0];
+
+ if (arguments.length > 1) {
+ triggerChange = arguments[1];
+ }
+
+ if (this.select) {
+ this.select
+ .val(val)
+ .find("option").filter(function() { return this.selected }).each2(function (i, elm) {
+ data = self.optionToData(elm);
+ return false;
+ });
+ this.updateSelection(data);
+ this.setPlaceholder();
+ if (triggerChange) {
+ this.triggerChange({added: data, removed:oldData});
+ }
+ } else {
+ // val is an id. !val is true for [undefined,null,'',0] - 0 is legal
+ if (!val && val !== 0) {
+ this.clear(triggerChange);
+ return;
+ }
+ if (this.opts.initSelection === undefined) {
+ throw new Error("cannot call val() if initSelection() is not defined");
+ }
+ this.opts.element.val(val);
+ this.opts.initSelection(this.opts.element, function(data){
+ self.opts.element.val(!data ? "" : self.id(data));
+ self.updateSelection(data);
+ self.setPlaceholder();
+ if (triggerChange) {
+ self.triggerChange({added: data, removed:oldData});
+ }
+ });
+ }
+ },
+
+ // single
+ clearSearch: function () {
+ this.search.val("");
+ this.focusser.val("");
+ },
+
+ // single
+ data: function(value) {
+ var data,
+ triggerChange = false;
+
+ if (arguments.length === 0) {
+ data = this.selection.data("select2-data");
+ if (data == undefined) data = null;
+ return data;
+ } else {
+ if (arguments.length > 1) {
+ triggerChange = arguments[1];
+ }
+ if (!value) {
+ this.clear(triggerChange);
+ } else {
+ data = this.data();
+ this.opts.element.val(!value ? "" : this.id(value));
+ this.updateSelection(value);
+ if (triggerChange) {
+ this.triggerChange({added: value, removed:data});
+ }
+ }
+ }
+ }
+ });
+
+ MultiSelect2 = clazz(AbstractSelect2, {
+
+ // multi
+ createContainer: function () {
+ var container = $(document.createElement("div")).attr({
+ "class": "select2-container select2-container-multi"
+ }).html([
+ "<ul class='select2-choices'>",
+ " <li class='select2-search-field'>",
+ " <input type='text' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false' class='select2-input'>",
+ " </li>",
+ "</ul>",
+ "<div class='select2-drop select2-drop-multi select2-display-none'>",
+ " <ul class='select2-results'>",
+ " </ul>",
+ "</div>"].join(""));
+ return container;
+ },
+
+ // multi
+ prepareOpts: function () {
+ var opts = this.parent.prepareOpts.apply(this, arguments),
+ self=this;
+
+ // TODO validate placeholder is a string if specified
+
+ if (opts.element.get(0).tagName.toLowerCase() === "select") {
+ // install sthe selection initializer
+ opts.initSelection = function (element, callback) {
+
+ var data = [];
+
+ element.find("option").filter(function() { return this.selected }).each2(function (i, elm) {
+ data.push(self.optionToData(elm));
+ });
+ callback(data);
+ };
+ } else if ("data" in opts) {
+ // install default initSelection when applied to hidden input and data is local
+ opts.initSelection = opts.initSelection || function (element, callback) {
+ var ids = splitVal(element.val(), opts.separator);
+ //search in data by array of ids, storing matching items in a list
+ var matches = [];
+ opts.query({
+ matcher: function(term, text, el){
+ var is_match = $.grep(ids, function(id) {
+ return equal(id, opts.id(el));
+ }).length;
+ if (is_match) {
+ matches.push(el);
+ }
+ return is_match;
+ },
+ callback: !$.isFunction(callback) ? $.noop : function() {
+ // reorder matches based on the order they appear in the ids array because right now
+ // they are in the order in which they appear in data array
+ var ordered = [];
+ for (var i = 0; i < ids.length; i++) {
+ var id = ids[i];
+ for (var j = 0; j < matches.length; j++) {
+ var match = matches[j];
+ if (equal(id, opts.id(match))) {
+ ordered.push(match);
+ matches.splice(j, 1);
+ break;
+ }
+ }
+ }
+ callback(ordered);
+ }
+ });
+ };
+ }
+
+ return opts;
+ },
+
+ // multi
+ selectChoice: function (choice) {
+
+ var selected = this.container.find(".select2-search-choice-focus");
+ if (selected.length && choice && choice[0] == selected[0]) {
+
+ } else {
+ if (selected.length) {
+ this.opts.element.trigger("choice-deselected", selected);
+ }
+ selected.removeClass("select2-search-choice-focus");
+ if (choice && choice.length) {
+ this.close();
+ choice.addClass("select2-search-choice-focus");
+ this.opts.element.trigger("choice-selected", choice);
+ }
+ }
+ },
+
+ // multi
+ destroy: function() {
+ $("label[for='" + this.search.attr('id') + "']")
+ .attr('for', this.opts.element.attr("id"));
+ this.parent.destroy.apply(this, arguments);
+ },
+
+ // multi
+ initContainer: function () {
+
+ var selector = ".select2-choices", selection;
+
+ this.searchContainer = this.container.find(".select2-search-field");
+ this.selection = selection = this.container.find(selector);
+
+ var _this = this;
+ this.selection.on("click", ".select2-search-choice:not(.select2-locked)", function (e) {
+ //killEvent(e);
+ _this.search[0].focus();
+ _this.selectChoice($(this));
+ });
+
+ // rewrite labels from original element to focusser
+ this.search.attr("id", "s2id_autogen"+nextUid());
+ $("label[for='" + this.opts.element.attr("id") + "']")
+ .attr('for', this.search.attr('id'));
+
+ this.search.on("input paste", this.bind(function() {
+ if (!this.isInterfaceEnabled()) return;
+ if (!this.opened()) {
+ this.open();
+ }
+ }));
+
+ this.search.attr("tabindex", this.elementTabIndex);
+
+ this.keydowns = 0;
+ this.search.on("keydown", this.bind(function (e) {
+ if (!this.isInterfaceEnabled()) return;
+
+ ++this.keydowns;
+ var selected = selection.find(".select2-search-choice-focus");
+ var prev = selected.prev(".select2-search-choice:not(.select2-locked)");
+ var next = selected.next(".select2-search-choice:not(.select2-locked)");
+ var pos = getCursorInfo(this.search);
+
+ if (selected.length &&
+ (e.which == KEY.LEFT || e.which == KEY.RIGHT || e.which == KEY.BACKSPACE || e.which == KEY.DELETE || e.which == KEY.ENTER)) {
+ var selectedChoice = selected;
+ if (e.which == KEY.LEFT && prev.length) {
+ selectedChoice = prev;
+ }
+ else if (e.which == KEY.RIGHT) {
+ selectedChoice = next.length ? next : null;
+ }
+ else if (e.which === KEY.BACKSPACE) {
+ this.unselect(selected.first());
+ this.search.width(10);
+ selectedChoice = prev.length ? prev : next;
+ } else if (e.which == KEY.DELETE) {
+ this.unselect(selected.first());
+ this.search.width(10);
+ selectedChoice = next.length ? next : null;
+ } else if (e.which == KEY.ENTER) {
+ selectedChoice = null;
+ }
+
+ this.selectChoice(selectedChoice);
+ killEvent(e);
+ if (!selectedChoice || !selectedChoice.length) {
+ this.open();
+ }
+ return;
+ } else if (((e.which === KEY.BACKSPACE && this.keydowns == 1)
+ || e.which == KEY.LEFT) && (pos.offset == 0 && !pos.length)) {
+
+ this.selectChoice(selection.find(".select2-search-choice:not(.select2-locked)").last());
+ killEvent(e);
+ return;
+ } else {
+ this.selectChoice(null);
+ }
+
+ if (this.opened()) {
+ switch (e.which) {
+ case KEY.UP:
+ case KEY.DOWN:
+ this.moveHighlight((e.which === KEY.UP) ? -1 : 1);
+ killEvent(e);
+ return;
+ case KEY.ENTER:
+ this.selectHighlighted();
+ killEvent(e);
+ return;
+ case KEY.TAB:
+ this.selectHighlighted({noFocus:true});
+ this.close();
+ return;
+ case KEY.ESC:
+ this.cancel(e);
+ killEvent(e);
+ return;
+ }
+ }
+
+ if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e)
+ || e.which === KEY.BACKSPACE || e.which === KEY.ESC) {
+ return;
+ }
+
+ if (e.which === KEY.ENTER) {
+ if (this.opts.openOnEnter === false) {
+ return;
+ } else if (e.altKey || e.ctrlKey || e.shiftKey || e.metaKey) {
+ return;
+ }
+ }
+
+ this.open();
+
+ if (e.which === KEY.PAGE_UP || e.which === KEY.PAGE_DOWN) {
+ // prevent the page from scrolling
+ killEvent(e);
+ }
+
+ if (e.which === KEY.ENTER) {
+ // prevent form from being submitted
+ killEvent(e);
+ }
+
+ }));
+
+ this.search.on("keyup", this.bind(function (e) {
+ this.keydowns = 0;
+ this.resizeSearch();
+ })
+ );
+
+ this.search.on("blur", this.bind(function(e) {
+ this.container.removeClass("select2-container-active");
+ this.search.removeClass("select2-focused");
+ this.selectChoice(null);
+ if (!this.opened()) this.clearSearch();
+ e.stopImmediatePropagation();
+ this.opts.element.trigger($.Event("select2-blur"));
+ }));
+
+ this.container.on("click", selector, this.bind(function (e) {
+ if (!this.isInterfaceEnabled()) return;
+ if ($(e.target).closest(".select2-search-choice").length > 0) {
+ // clicked inside a select2 search choice, do not open
+ return;
+ }
+ this.selectChoice(null);
+ this.clearPlaceholder();
+ if (!this.container.hasClass("select2-container-active")) {
+ this.opts.element.trigger($.Event("select2-focus"));
+ }
+ this.open();
+ this.focusSearch();
+ e.preventDefault();
+ }));
+
+ this.container.on("focus", selector, this.bind(function () {
+ if (!this.isInterfaceEnabled()) return;
+ if (!this.container.hasClass("select2-container-active")) {
+ this.opts.element.trigger($.Event("select2-focus"));
+ }
+ this.container.addClass("select2-container-active");
+ this.dropdown.addClass("select2-drop-active");
+ this.clearPlaceholder();
+ }));
+
+ this.initContainerWidth();
+ this.opts.element.addClass("select2-offscreen");
+
+ // set the placeholder if necessary
+ this.clearSearch();
+ },
+
+ // multi
+ enableInterface: function() {
+ if (this.parent.enableInterface.apply(this, arguments)) {
+ this.search.prop("disabled", !this.isInterfaceEnabled());
+ }
+ },
+
+ // multi
+ initSelection: function () {
+ var data;
+ if (this.opts.element.val() === "" && this.opts.element.text() === "") {
+ this.updateSelection([]);
+ this.close();
+ // set the placeholder if necessary
+ this.clearSearch();
+ }
+ if (this.select || this.opts.element.val() !== "") {
+ var self = this;
+ this.opts.initSelection.call(null, this.opts.element, function(data){
+ if (data !== undefined && data !== null) {
+ self.updateSelection(data);
+ self.close();
+ // set the placeholder if necessary
+ self.clearSearch();
+ }
+ });
+ }
+ },
+
+ // multi
+ clearSearch: function () {
+ var placeholder = this.getPlaceholder(),
+ maxWidth = this.getMaxSearchWidth();
+
+ if (placeholder !== undefined && this.getVal().length === 0 && this.search.hasClass("select2-focused") === false) {
+ this.search.val(placeholder).addClass("select2-default");
+ // stretch the search box to full width of the container so as much of the placeholder is visible as possible
+ // we could call this.resizeSearch(), but we do not because that requires a sizer and we do not want to create one so early because of a firefox bug, see #944
+ this.search.width(maxWidth > 0 ? maxWidth : this.container.css("width"));
+ } else {
+ this.search.val("").width(10);
+ }
+ },
+
+ // multi
+ clearPlaceholder: function () {
+ if (this.search.hasClass("select2-default")) {
+ this.search.val("").removeClass("select2-default");
+ }
+ },
+
+ // multi
+ opening: function () {
+ this.clearPlaceholder(); // should be done before super so placeholder is not used to search
+ this.resizeSearch();
+
+ this.parent.opening.apply(this, arguments);
+
+ this.focusSearch();
+
+ this.updateResults(true);
+ this.search.focus();
+ this.opts.element.trigger($.Event("select2-open"));
+ },
+
+ // multi
+ close: function () {
+ if (!this.opened()) return;
+ this.parent.close.apply(this, arguments);
+ },
+
+ // multi
+ focus: function () {
+ this.close();
+ this.search.focus();
+ },
+
+ // multi
+ isFocused: function () {
+ return this.search.hasClass("select2-focused");
+ },
+
+ // multi
+ updateSelection: function (data) {
+ var ids = [], filtered = [], self = this;
+
+ // filter out duplicates
+ $(data).each(function () {
+ if (indexOf(self.id(this), ids) < 0) {
+ ids.push(self.id(this));
+ filtered.push(this);
+ }
+ });
+ data = filtered;
+
+ this.selection.find(".select2-search-choice").remove();
+ $(data).each(function () {
+ self.addSelectedChoice(this);
+ });
+ self.postprocessResults();
+ },
+
+ // multi
+ tokenize: function() {
+ var input = this.search.val();
+ input = this.opts.tokenizer.call(this, input, this.data(), this.bind(this.onSelect), this.opts);
+ if (input != null && input != undefined) {
+ this.search.val(input);
+ if (input.length > 0) {
+ this.open();
+ }
+ }
+
+ },
+
+ // multi
+ onSelect: function (data, options) {
+
+ if (!this.triggerSelect(data)) { return; }
+
+ this.addSelectedChoice(data);
+
+ this.opts.element.trigger({ type: "selected", val: this.id(data), choice: data });
+
+ if (this.select || !this.opts.closeOnSelect) this.postprocessResults(data, false, this.opts.closeOnSelect===true);
+
+ if (this.opts.closeOnSelect) {
+ this.close();
+ this.search.width(10);
+ } else {
+ if (this.countSelectableResults()>0) {
+ this.search.width(10);
+ this.resizeSearch();
+ if (this.getMaximumSelectionSize() > 0 && this.val().length >= this.getMaximumSelectionSize()) {
+ // if we reached max selection size repaint the results so choices
+ // are replaced with the max selection reached message
+ this.updateResults(true);
+ }
+ this.positionDropdown();
+ } else {
+ // if nothing left to select close
+ this.close();
+ this.search.width(10);
+ }
+ }
+
+ // since its not possible to select an element that has already been
+ // added we do not need to check if this is a new element before firing change
+ this.triggerChange({ added: data });
+
+ if (!options || !options.noFocus)
+ this.focusSearch();
+ },
+
+ // multi
+ cancel: function () {
+ this.close();
+ this.focusSearch();
+ },
+
+ addSelectedChoice: function (data) {
+ var enableChoice = !data.locked,
+ enabledItem = $(
+ "<li class='select2-search-choice'>" +
+ " <div></div>" +
+ " <a href='#' onclick='return false;' class='select2-search-choice-close' tabindex='-1'></a>" +
+ "</li>"),
+ disabledItem = $(
+ "<li class='select2-search-choice select2-locked'>" +
+ "<div></div>" +
+ "</li>");
+ var choice = enableChoice ? enabledItem : disabledItem,
+ id = this.id(data),
+ val = this.getVal(),
+ formatted,
+ cssClass;
+
+ formatted=this.opts.formatSelection(data, choice.find("div"), this.opts.escapeMarkup);
+ if (formatted != undefined) {
+ choice.find("div").replaceWith("<div>"+formatted+"</div>");
+ }
+ cssClass=this.opts.formatSelectionCssClass(data, choice.find("div"));
+ if (cssClass != undefined) {
+ choice.addClass(cssClass);
+ }
+
+ if(enableChoice){
+ choice.find(".select2-search-choice-close")
+ .on("mousedown", killEvent)
+ .on("click dblclick", this.bind(function (e) {
+ if (!this.isInterfaceEnabled()) return;
+
+ $(e.target).closest(".select2-search-choice").fadeOut('fast', this.bind(function(){
+ this.unselect($(e.target));
+ this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus");
+ this.close();
+ this.focusSearch();
+ })).dequeue();
+ killEvent(e);
+ })).on("focus", this.bind(function () {
+ if (!this.isInterfaceEnabled()) return;
+ this.container.addClass("select2-container-active");
+ this.dropdown.addClass("select2-drop-active");
+ }));
+ }
+
+ choice.data("select2-data", data);
+ choice.insertBefore(this.searchContainer);
+
+ val.push(id);
+ this.setVal(val);
+ },
+
+ // multi
+ unselect: function (selected) {
+ var val = this.getVal(),
+ data,
+ index;
+ selected = selected.closest(".select2-search-choice");
+
+ if (selected.length === 0) {
+ throw "Invalid argument: " + selected + ". Must be .select2-search-choice";
+ }
+
+ data = selected.data("select2-data");
+
+ if (!data) {
+ // prevent a race condition when the 'x' is clicked really fast repeatedly the event can be queued
+ // and invoked on an element already removed
+ return;
+ }
+
+ while((index = indexOf(this.id(data), val)) >= 0) {
+ val.splice(index, 1);
+ this.setVal(val);
+ if (this.select) this.postprocessResults();
+ }
+
+ var evt = $.Event("select2-removing");
+ evt.val = this.id(data);
+ evt.choice = data;
+ this.opts.element.trigger(evt);
+
+ if (evt.isDefaultPrevented()) {
+ return;
+ }
+
+ selected.remove();
+
+ this.opts.element.trigger({ type: "select2-removed", val: this.id(data), choice: data });
+ this.triggerChange({ removed: data });
+ },
+
+ // multi
+ postprocessResults: function (data, initial, noHighlightUpdate) {
+ var val = this.getVal(),
+ choices = this.results.find(".select2-result"),
+ compound = this.results.find(".select2-result-with-children"),
+ self = this;
+
+ choices.each2(function (i, choice) {
+ var id = self.id(choice.data("select2-data"));
+ if (indexOf(id, val) >= 0) {
+ choice.addClass("select2-selected");
+ // mark all children of the selected parent as selected
+ choice.find(".select2-result-selectable").addClass("select2-selected");
+ }
+ });
+
+ compound.each2(function(i, choice) {
+ // hide an optgroup if it doesnt have any selectable children
+ if (!choice.is('.select2-result-selectable')
+ && choice.find(".select2-result-selectable:not(.select2-selected)").length === 0) {
+ choice.addClass("select2-selected");
+ }
+ });
+
+ if (this.highlight() == -1 && noHighlightUpdate !== false){
+ self.highlight(0);
+ }
+
+ //If all results are chosen render formatNoMAtches
+ if(!this.opts.createSearchChoice && !choices.filter('.select2-result:not(.select2-selected)').length > 0){
+ if(!data || data && !data.more && this.results.find(".select2-no-results").length === 0) {
+ if (checkFormatter(self.opts.formatNoMatches, "formatNoMatches")) {
+ this.results.append("<li class='select2-no-results'>" + self.opts.formatNoMatches(self.search.val()) + "</li>");
+ }
+ }
+ }
+
+ },
+
+ // multi
+ getMaxSearchWidth: function() {
+ return this.selection.width() - getSideBorderPadding(this.search);
+ },
+
+ // multi
+ resizeSearch: function () {
+ var minimumWidth, left, maxWidth, containerLeft, searchWidth,
+ sideBorderPadding = getSideBorderPadding(this.search);
+
+ minimumWidth = measureTextWidth(this.search) + 10;
+
+ left = this.search.offset().left;
+
+ maxWidth = this.selection.width();
+ containerLeft = this.selection.offset().left;
+
+ searchWidth = maxWidth - (left - containerLeft) - sideBorderPadding;
+
+ if (searchWidth < minimumWidth) {
+ searchWidth = maxWidth - sideBorderPadding;
+ }
+
+ if (searchWidth < 40) {
+ searchWidth = maxWidth - sideBorderPadding;
+ }
+
+ if (searchWidth <= 0) {
+ searchWidth = minimumWidth;
+ }
+
+ this.search.width(Math.floor(searchWidth));
+ },
+
+ // multi
+ getVal: function () {
+ var val;
+ if (this.select) {
+ val = this.select.val();
+ return val === null ? [] : val;
+ } else {
+ val = this.opts.element.val();
+ return splitVal(val, this.opts.separator);
+ }
+ },
+
+ // multi
+ setVal: function (val) {
+ var unique;
+ if (this.select) {
+ this.select.val(val);
+ } else {
+ unique = [];
+ // filter out duplicates
+ $(val).each(function () {
+ if (indexOf(this, unique) < 0) unique.push(this);
+ });
+ this.opts.element.val(unique.length === 0 ? "" : unique.join(this.opts.separator));
+ }
+ },
+
+ // multi
+ buildChangeDetails: function (old, current) {
+ var current = current.slice(0),
+ old = old.slice(0);
+
+ // remove intersection from each array
+ for (var i = 0; i < current.length; i++) {
+ for (var j = 0; j < old.length; j++) {
+ if (equal(this.opts.id(current[i]), this.opts.id(old[j]))) {
+ current.splice(i, 1);
+ if(i>0){
+ i--;
+ }
+ old.splice(j, 1);
+ j--;
+ }
+ }
+ }
+
+ return {added: current, removed: old};
+ },
+
+
+ // multi
+ val: function (val, triggerChange) {
+ var oldData, self=this;
+
+ if (arguments.length === 0) {
+ return this.getVal();
+ }
+
+ oldData=this.data();
+ if (!oldData.length) oldData=[];
+
+ // val is an id. !val is true for [undefined,null,'',0] - 0 is legal
+ if (!val && val !== 0) {
+ this.opts.element.val("");
+ this.updateSelection([]);
+ this.clearSearch();
+ if (triggerChange) {
+ this.triggerChange({added: this.data(), removed: oldData});
+ }
+ return;
+ }
+
+ // val is a list of ids
+ this.setVal(val);
+
+ if (this.select) {
+ this.opts.initSelection(this.select, this.bind(this.updateSelection));
+ if (triggerChange) {
+ this.triggerChange(this.buildChangeDetails(oldData, this.data()));
+ }
+ } else {
+ if (this.opts.initSelection === undefined) {
+ throw new Error("val() cannot be called if initSelection() is not defined");
+ }
+
+ this.opts.initSelection(this.opts.element, function(data){
+ var ids=$.map(data, self.id);
+ self.setVal(ids);
+ self.updateSelection(data);
+ self.clearSearch();
+ if (triggerChange) {
+ self.triggerChange(self.buildChangeDetails(oldData, self.data()));
+ }
+ });
+ }
+ this.clearSearch();
+ },
+
+ // multi
+ onSortStart: function() {
+ if (this.select) {
+ throw new Error("Sorting of elements is not supported when attached to <select>. Attach to <input type='hidden'/> instead.");
+ }
+
+ // collapse search field into 0 width so its container can be collapsed as well
+ this.search.width(0);
+ // hide the container
+ this.searchContainer.hide();
+ },
+
+ // multi
+ onSortEnd:function() {
+
+ var val=[], self=this;
+
+ // show search and move it to the end of the list
+ this.searchContainer.show();
+ // make sure the search container is the last item in the list
+ this.searchContainer.appendTo(this.searchContainer.parent());
+ // since we collapsed the width in dragStarted, we resize it here
+ this.resizeSearch();
+
+ // update selection
+ this.selection.find(".select2-search-choice").each(function() {
+ val.push(self.opts.id($(this).data("select2-data")));
+ });
+ this.setVal(val);
+ this.triggerChange();
+ },
+
+ // multi
+ data: function(values, triggerChange) {
+ var self=this, ids, old;
+ if (arguments.length === 0) {
+ return this.selection
+ .find(".select2-search-choice")
+ .map(function() { return $(this).data("select2-data"); })
+ .get();
+ } else {
+ old = this.data();
+ if (!values) { values = []; }
+ ids = $.map(values, function(e) { return self.opts.id(e); });
+ this.setVal(ids);
+ this.updateSelection(values);
+ this.clearSearch();
+ if (triggerChange) {
+ this.triggerChange(this.buildChangeDetails(old, this.data()));
+ }
+ }
+ }
+ });
+
+ $.fn.select2 = function () {
+
+ var args = Array.prototype.slice.call(arguments, 0),
+ opts,
+ select2,
+ method, value, multiple,
+ allowedMethods = ["val", "destroy", "opened", "open", "close", "focus", "isFocused", "container", "dropdown", "onSortStart", "onSortEnd", "enable", "disable", "readonly", "positionDropdown", "data", "search"],
+ valueMethods = ["opened", "isFocused", "container", "dropdown"],
+ propertyMethods = ["val", "data"],
+ methodsMap = { search: "externalSearch" };
+
+ this.each(function () {
+ if (args.length === 0 || typeof(args[0]) === "object") {
+ opts = args.length === 0 ? {} : $.extend({}, args[0]);
+ opts.element = $(this);
+
+ if (opts.element.get(0).tagName.toLowerCase() === "select") {
+ multiple = opts.element.prop("multiple");
+ } else {
+ multiple = opts.multiple || false;
+ if ("tags" in opts) {opts.multiple = multiple = true;}
+ }
+
+ select2 = multiple ? new MultiSelect2() : new SingleSelect2();
+ select2.init(opts);
+ } else if (typeof(args[0]) === "string") {
+
+ if (indexOf(args[0], allowedMethods) < 0) {
+ throw "Unknown method: " + args[0];
+ }
+
+ value = undefined;
+ select2 = $(this).data("select2");
+ if (select2 === undefined) return;
+
+ method=args[0];
+
+ if (method === "container") {
+ value = select2.container;
+ } else if (method === "dropdown") {
+ value = select2.dropdown;
+ } else {
+ if (methodsMap[method]) method = methodsMap[method];
+
+ value = select2[method].apply(select2, args.slice(1));
+ }
+ if (indexOf(args[0], valueMethods) >= 0
+ || (indexOf(args[0], propertyMethods) && args.length == 1)) {
+ return false; // abort the iteration, ready to return first matched value
+ }
+ } else {
+ throw "Invalid arguments to select2 plugin: " + args;
+ }
+ });
+ return (value === undefined) ? this : value;
+ };
+
+ // plugin defaults, accessible to users
+ $.fn.select2.defaults = {
+ width: "copy",
+ loadMorePadding: 0,
+ closeOnSelect: true,
+ openOnEnter: true,
+ containerCss: {},
+ dropdownCss: {},
+ containerCssClass: "",
+ dropdownCssClass: "",
+ formatResult: function(result, container, query, escapeMarkup) {
+ var markup=[];
+ markMatch(result.text, query.term, markup, escapeMarkup);
+ return markup.join("");
+ },
+ formatSelection: function (data, container, escapeMarkup) {
+ return data ? escapeMarkup(data.text) : undefined;
+ },
+ sortResults: function (results, container, query) {
+ return results;
+ },
+ formatResultCssClass: function(data) {return undefined;},
+ formatSelectionCssClass: function(data, container) {return undefined;},
+ formatNoMatches: function () { return "No matches found"; },
+ formatInputTooShort: function (input, min) { var n = min - input.length; return "Please enter " + n + " more character" + (n == 1? "" : "s"); },
+ formatInputTooLong: function (input, max) { var n = input.length - max; return "Please delete " + n + " character" + (n == 1? "" : "s"); },
+ formatSelectionTooBig: function (limit) { return "You can only select " + limit + " item" + (limit == 1 ? "" : "s"); },
+ formatLoadMore: function (pageNumber) { return "Loading more results..."; },
+ formatSearching: function () { return "Searching..."; },
+ minimumResultsForSearch: 0,
+ minimumInputLength: 0,
+ maximumInputLength: null,
+ maximumSelectionSize: 0,
+ id: function (e) { return e.id; },
+ matcher: function(term, text) {
+ return stripDiacritics(''+text).toUpperCase().indexOf(stripDiacritics(''+term).toUpperCase()) >= 0;
+ },
+ separator: ",",
+ tokenSeparators: [],
+ tokenizer: defaultTokenizer,
+ escapeMarkup: defaultEscapeMarkup,
+ blurOnChange: false,
+ selectOnBlur: false,
+ adaptContainerCssClass: function(c) { return c; },
+ adaptDropdownCssClass: function(c) { return null; },
+ nextSearchTerm: function(selectedObject, currentSearchTerm) { return undefined; }
+ };
+
+ $.fn.select2.ajaxDefaults = {
+ transport: $.ajax,
+ params: {
+ type: "GET",
+ cache: false,
+ dataType: "json"
+ }
+ };
+
+ // exports
+ window.Select2 = {
+ query: {
+ ajax: ajax,
+ local: local,
+ tags: tags
+ }, util: {
+ debounce: debounce,
+ markMatch: markMatch,
+ escapeMarkup: defaultEscapeMarkup,
+ stripDiacritics: stripDiacritics
+ }, "class": {
+ "abstract": AbstractSelect2,
+ "single": SingleSelect2,
+ "multi": MultiSelect2
+ }
+ };
+
+}(jQuery));
Added: trunk/wao-web/src/main/webapp/js/select2-3.4.5/select2.min.js
===================================================================
--- trunk/wao-web/src/main/webapp/js/select2-3.4.5/select2.min.js (rev 0)
+++ trunk/wao-web/src/main/webapp/js/select2-3.4.5/select2.min.js 2014-03-19 15:11:43 UTC (rev 1728)
@@ -0,0 +1,22 @@
+/*
+Copyright 2012 Igor Vaynberg
+
+Version: 3.4.5 Timestamp: Mon Nov 4 08:22:42 PST 2013
+
+This software is licensed under the Apache License, Version 2.0 (the "Apache License") or the GNU
+General Public License version 2 (the "GPL License"). You may choose either license to govern your
+use of this software only upon the condition that you accept all of the terms of either the Apache
+License or the GPL License.
+
+You may obtain a copy of the Apache License and the GPL License at:
+
+http://www.apache.org/licenses/LICENSE-2.0
+http://www.gnu.org/licenses/gpl-2.0.html
+
+Unless required by applicable law or agreed to in writing, software distributed under the Apache License
+or the GPL Licesnse is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+either express or implied. See the Apache License and the GPL License for the specific language governing
+permissions and limitations under the Apache License and the GPL License.
+*/
+!function(a){"undefined"==typeof a.fn.each2&&a.extend(a.fn,{each2:function(b){for(var c=a([0]),d=-1,e=this.length;++d<e&&(c.context=c[0]=this[d])&&b.call(c[0],d,c)!==!1;);return this}})}(jQuery),function(a,b){"use strict";function n(a){var b,c,d,e;if(!a||a.length<1)return a;for(b="",c=0,d=a.length;d>c;c++)e=a.charAt(c),b+=m[e]||e;return b}function o(a,b){for(var c=0,d=b.length;d>c;c+=1)if(q(a,b[c]))return c;return-1}function p(){var b=a(l);b.appendTo("body");var c={width:b.width()-b[0].clientWidth,height:b.height()-b[0].clientHeight};return b.remove(),c}function q(a,c){return a===c?!0:a===b||c===b?!1:null===a||null===c?!1:a.constructor===String?a+""==c+"":c.constructor===String?c+""==a+"":!1}function r(b,c){var d,e,f;if(null===b||b.length<1)return[];for(d=b.split(c),e=0,f=d.length;f>e;e+=1)d[e]=a.trim(d[e]);return d}function s(a){return a.outerWidth(!1)-a.width()}function t(c){var d="keyup-change-value";c.on("keydown",function(){a.data(c,d)===b&&a.data(c,d,c.val())}),c.on("keyup",function(){var e=a.data(c,d);e!==b&&c.val()!==e&&(a.removeData(c,d),c.trigger("keyup-change"))})}function u(c){c.on("mousemove",function(c){var d=i;(d===b||d.x!==c.pageX||d.y!==c.pageY)&&a(c.target).trigger("mousemove-filtered",c)})}function v(a,c,d){d=d||b;var e;return function(){var b=arguments;window.clearTimeout(e),e=window.setTimeout(function(){c.apply(d,b)},a)}}function w(a){var c,b=!1;return function(){return b===!1&&(c=a(),b=!0),c}}function x(a,b){var c=v(a,function(a){b.trigger("scroll-debounced",a)});b.on("scroll",function(a){o(a.target,b.get())>=0&&c(a)})}function y(a){a[0]!==document.activeElement&&window.setTimeout(function(){var d,b=a[0],c=a.val().length;a.focus(),a.is(":visible")&&b===document.activeElement&&(b.setSelectionRange?b.setSelectionRange(c,c):b.createTextRange&&(d=b.createTextRange(),d.collapse(!1),d.select()))},0)}function z(b){b=a(b)[0];var c=0,d=0;if("selectionStart"in b)c=b.selectionStart,d=b.selectionEnd-c;else if("selection"in document){b.focus();var e=document.selection.createRange();d=document.selection.createRange().text.length,e.moveStart("character",-b.value.length),c=e.text.length-d}return{offset:c,length:d}}function A(a){a.preventDefault(),a.stopPropagation()}function B(a){a.preventDefault(),a.stopImmediatePropagation()}function C(b){if(!h){var c=b[0].currentStyle||window.getComputedStyle(b[0],null);h=a(document.createElement("div")).css({position:"absolute",left:"-10000px",top:"-10000px",display:"none",fontSize:c.fontSize,fontFamily:c.fontFamily,fontStyle:c.fontStyle,fontWeight:c.fontWeight,letterSpacing:c.letterSpacing,textTransform:c.textTransform,whiteSpace:"nowrap"}),h.attr("class","select2-sizer"),a("body").append(h)}return h.text(b.val()),h.width()}function D(b,c,d){var e,g,f=[];e=b.attr("class"),e&&(e=""+e,a(e.split(" ")).each2(function(){0===this.indexOf("select2-")&&f.push(this)})),e=c.attr("class"),e&&(e=""+e,a(e.split(" ")).each2(function(){0!==this.indexOf("select2-")&&(g=d(this),g&&f.push(g))})),b.attr("class",f.join(" "))}function E(a,b,c,d){var e=n(a.toUpperCase()).indexOf(n(b.toUpperCase())),f=b.length;return 0>e?(c.push(d(a)),void 0):(c.push(d(a.substring(0,e))),c.push("<span class='select2-match'>"),c.push(d(a.substring(e,e+f))),c.push("</span>"),c.push(d(a.substring(e+f,a.length))),void 0)}function F(a){var b={"\\":"\","&":"&","<":"<",">":">",'"':""","'":"'","/":"/"};return String(a).replace(/[&<>"'\/\\]/g,function(a){return b[a]})}function G(c){var d,e=null,f=c.quietMillis||100,g=c.url,h=this;return function(i){window.clearTimeout(d),d=window.setTimeout(function(){var d=c.data,f=g,j=c.transport||a.fn.select2.ajaxDefaults.transport,k={type:c.type||"GET",cache:c.cache||!1,jsonpCallback:c.jsonpCallback||b,dataType:c.dataType||"json"},l=a.extend({},a.fn.select2.ajaxDefaults.params,k);d=d?d.call(h,i.term,i.page,i.context):null,f="function"==typeof f?f.call(h,i.term,i.page,i.context):f,e&&e.abort(),c.params&&(a.isFunction(c.params)?a.extend(l,c.params.call(h)):a.extend(l,c.params)),a.extend(l,{url:f,dataType:c.dataType,data:d,success:function(a){var b=c.results(a,i.page);i.callback(b)}}),e=j.call(h,l)},f)}}function H(b){var d,e,c=b,f=function(a){return""+a.text};a.isArray(c)&&(e=c,c={results:e}),a.isFunction(c)===!1&&(e=c,c=function(){return e});var g=c();return g.text&&(f=g.text,a.isFunction(f)||(d=g.text,f=function(a){return a[d]})),function(b){var g,d=b.term,e={results:[]};return""===d?(b.callback(c()),void 0):(g=function(c,e){var h,i;if(c=c[0],c.children){h={};for(i in c)c.hasOwnProperty(i)&&(h[i]=c[i]);h.children=[],a(c.children).each2(function(a,b){g(b,h.children)}),(h.children.length||b.matcher(d,f(h),c))&&e.push(h)}else b.matcher(d,f(c),c)&&e.push(c)},a(c().results).each2(function(a,b){g(b,e.results)}),b.callback(e),void 0)}}function I(c){var d=a.isFunction(c);return function(e){var f=e.term,g={results:[]};a(d?c():c).each(function(){var a=this.text!==b,c=a?this.text:this;(""===f||e.matcher(f,c))&&g.results.push(a?this:{id:this,text:this})}),e.callback(g)}}function J(b,c){if(a.isFunction(b))return!0;if(!b)return!1;throw new Error(c+" must be a function or a falsy value")}function K(b){return a.isFunction(b)?b():b}function L(b){var c=0;return a.each(b,function(a,b){b.children?c+=L(b.children):c++}),c}function M(a,c,d,e){var h,i,j,k,l,f=a,g=!1;if(!e.createSearchChoice||!e.tokenSeparators||e.tokenSeparators.length<1)return b;for(;;){for(i=-1,j=0,k=e.tokenSeparators.length;k>j&&(l=e.tokenSeparators[j],i=a.indexOf(l),!(i>=0));j++);if(0>i)break;if(h=a.substring(0,i),a=a.substring(i+l.length),h.length>0&&(h=e.createSearchChoice.call(this,h,c),h!==b&&null!==h&&e.id(h)!==b&&null!==e.id(h))){for(g=!1,j=0,k=c.length;k>j;j++)if(q(e.id(h),e.id(c[j]))){g=!0;break}g||d(h)}}return f!==a?a:void 0}function N(b,c){var d=function(){};return d.prototype=new b,d.prototype.constructor=d,d.prototype.parent=b.prototype,d.prototype=a.extend(d.prototype,c),d}if(window.Select2===b){var c,d,e,f,g,h,j,k,i={x:0,y:0},c={TAB:9,ENTER:13,ESC:27,SPACE:32,LEFT:37,UP:38,RIGHT:39,DOWN:40,SHIFT:16,CTRL:17,ALT:18,PAGE_UP:33,PAGE_DOWN:34,HOME:36,END:35,BACKSPACE:8,DELETE:46,isArrow:function(a){switch(a=a.which?a.which:a){case c.LEFT:case c.RIGHT:case c.UP:case c.DOWN:return!0}return!1},isControl:function(a){var b=a.which;switch(b){case c.SHIFT:case c.CTRL:case c.ALT:return!0}return a.metaKey?!0:!1},isFunctionKey:function(a){return a=a.which?a.which:a,a>=112&&123>=a}},l="<div class='select2-measure-scrollbar'></div>",m={"\u24b6":"A","\uff21":"A","\xc0":"A","\xc1":"A","\xc2":"A","\u1ea6":"A","\u1ea4":"A","\u1eaa":"A","\u1ea8":"A","\xc3":"A","\u0100":"A","\u0102":"A","\u1eb0":"A","\u1eae":"A","\u1eb4":"A","\u1eb2":"A","\u0226":"A","\u01e0":"A","\xc4":"A","\u01de":"A","\u1ea2":"A","\xc5":"A","\u01fa":"A","\u01cd":"A","\u0200":"A","\u0202":"A","\u1ea0":"A","\u1eac":"A","\u1eb6":"A","\u1e00":"A","\u0104":"A","\u023a":"A","\u2c6f":"A","\ua732":"AA","\xc6":"AE","\u01fc":"AE","\u01e2":"AE","\ua734":"AO","\ua736":"AU","\ua738":"AV","\ua73a":"AV","\ua73c":"AY","\u24b7":"B","\uff22":"B","\u1e02":"B","\u1e04":"B","\u1e06":"B","\u0243":"B","\u0182":"B","\u0181":"B","\u24b8":"C","\uff23":"C","\u0106":"C","\u0108":"C","\u010a":"C","\u010c":"C","\xc7":"C","\u1e08":"C","\u0187":"C","\u023b":"C","\ua73e":"C","\u24b9":"D","\uff24":"D","\u1e0a":"D","\u010e":"D","\u1e0c":"D","\u1e10":"D","\u1e12":"D","\u1e0e":"D","\u0110":"D","\u018b":"D","\u018a":"D","\u0189":"D","\ua779":"D","\u01f1":"DZ","\u01c4":"DZ","\u01f2":"Dz","\u01c5":"Dz","\u24ba":"E","\uff25":"E","\xc8":"E","\xc9":"E","\xca":"E","\u1ec0":"E","\u1ebe":"E","\u1ec4":"E","\u1ec2":"E","\u1ebc":"E","\u0112":"E","\u1e14":"E","\u1e16":"E","\u0114":"E","\u0116":"E","\xcb":"E","\u1eba":"E","\u011a":"E","\u0204":"E","\u0206":"E","\u1eb8":"E","\u1ec6":"E","\u0228":"E","\u1e1c":"E","\u0118":"E","\u1e18":"E","\u1e1a":"E","\u0190":"E","\u018e":"E","\u24bb":"F","\uff26":"F","\u1e1e":"F","\u0191":"F","\ua77b":"F","\u24bc":"G","\uff27":"G","\u01f4":"G","\u011c":"G","\u1e20":"G","\u011e":"G","\u0120":"G","\u01e6":"G","\u0122":"G","\u01e4":"G","\u0193":"G","\ua7a0":"G","\ua77d":"G","\ua77e":"G","\u24bd":"H","\uff28":"H","\u0124":"H","\u1e22":"H","\u1e26":"H","\u021e":"H","\u1e24":"H","\u1e28":"H","\u1e2a":"H","\u0126":"H","\u2c67":"H","\u2c75":"H","\ua78d":"H","\u24be":"I","\uff29":"I","\xcc":"I","\xcd":"I","\xce":"I","\u0128":"I","\u012a":"I","\u012c":"I","\u0130":"I","\xcf":"I","\u1e2e":"I","\u1ec8":"I","\u01cf":"I","\u0208":"I","\u020a":"I","\u1eca":"I","\u012e":"I","\u1e2c":"I","\u0197":"I","\u24bf":"J","\uff2a":"J","\u0134":"J","\u0248":"J","\u24c0":"K","\uff2b":"K","\u1e30":"K","\u01e8":"K","\u1e32":"K","\u0136":"K","\u1e34":"K","\u0198":"K","\u2c69":"K","\ua740":"K","\ua742":"K","\ua744":"K","\ua7a2":"K","\u24c1":"L","\uff2c":"L","\u013f":"L","\u0139":"L","\u013d":"L","\u1e36":"L","\u1e38":"L","\u013b":"L","\u1e3c":"L","\u1e3a":"L","\u0141":"L","\u023d":"L","\u2c62":"L","\u2c60":"L","\ua748":"L","\ua746":"L","\ua780":"L","\u01c7":"LJ","\u01c8":"Lj","\u24c2":"M","\uff2d":"M","\u1e3e":"M","\u1e40":"M","\u1e42":"M","\u2c6e":"M","\u019c":"M","\u24c3":"N","\uff2e":"N","\u01f8":"N","\u0143":"N","\xd1":"N","\u1e44":"N","\u0147":"N","\u1e46":"N","\u0145":"N","\u1e4a":"N","\u1e48":"N","\u0220":"N","\u019d":"N","\ua790":"N","\ua7a4":"N","\u01ca":"NJ","\u01cb":"Nj","\u24c4":"O","\uff2f":"O","\xd2":"O","\xd3":"O","\xd4":"O","\u1ed2":"O","\u1ed0":"O","\u1ed6":"O","\u1ed4":"O","\xd5":"O","\u1e4c":"O","\u022c":"O","\u1e4e":"O","\u014c":"O","\u1e50":"O","\u1e52":"O","\u014e":"O","\u022e":"O","\u0230":"O","\xd6":"O","\u022a":"O","\u1ece":"O","\u0150":"O","\u01d1":"O","\u020c":"O","\u020e":"O","\u01a0":"O","\u1edc":"O","\u1eda":"O","\u1ee0":"O","\u1ede":"O","\u1ee2":"O","\u1ecc":"O","\u1ed8":"O","\u01ea":"O","\u01ec":"O","\xd8":"O","\u01fe":"O","\u0186":"O","\u019f":"O","\ua74a":"O","\ua74c":"O","\u01a2":"OI","\ua74e":"OO","\u0222":"OU","\u24c5":"P","\uff30":"P","\u1e54":"P","\u1e56":"P","\u01a4":"P","\u2c63":"P","\ua750":"P","\ua752":"P","\ua754":"P","\u24c6":"Q","\uff31":"Q","\ua756":"Q","\ua758":"Q","\u024a":"Q","\u24c7":"R","\uff32":"R","\u0154":"R","\u1e58":"R","\u0158":"R","\u0210":"R","\u0212":"R","\u1e5a":"R","\u1e5c":"R","\u0156":"R","\u1e5e":"R","\u024c":"R","\u2c64":"R","\ua75a":"R","\ua7a6":"R","\ua782":"R","\u24c8":"S","\uff33":"S","\u1e9e":"S","\u015a":"S","\u1e64":"S","\u015c":"S","\u1e60":"S","\u0160":"S","\u1e66":"S","\u1e62":"S","\u1e68":"S","\u0218":"S","\u015e":"S","\u2c7e":"S","\ua7a8":"S","\ua784":"S","\u24c9":"T","\uff34":"T","\u1e6a":"T","\u0164":"T","\u1e6c":"T","\u021a":"T","\u0162":"T","\u1e70":"T","\u1e6e":"T","\u0166":"T","\u01ac":"T","\u01ae":"T","\u023e":"T","\ua786":"T","\ua728":"TZ","\u24ca":"U","\uff35":"U","\xd9":"U","\xda":"U","\xdb":"U","\u0168":"U","\u1e78":"U","\u016a":"U","\u1e7a":"U","\u016c":"U","\xdc":"U","\u01db":"U","\u01d7":"U","\u01d5":"U","\u01d9":"U","\u1ee6":"U","\u016e":"U","\u0170":"U","\u01d3":"U","\u0214":"U","\u0216":"U","\u01af":"U","\u1eea":"U","\u1ee8":"U","\u1eee":"U","\u1eec":"U","\u1ef0":"U","\u1ee4":"U","\u1e72":"U","\u0172":"U","\u1e76":"U","\u1e74":"U","\u0244":"U","\u24cb":"V","\uff36":"V","\u1e7c":"V","\u1e7e":"V","\u01b2":"V","\ua75e":"V","\u0245":"V","\ua760":"VY","\u24cc":"W","\uff37":"W","\u1e80":"W","\u1e82":"W","\u0174":"W","\u1e86":"W","\u1e84":"W","\u1e88":"W","\u2c72":"W","\u24cd":"X","\uff38":"X","\u1e8a":"X","\u1e8c":"X","\u24ce":"Y","\uff39":"Y","\u1ef2":"Y","\xdd":"Y","\u0176":"Y","\u1ef8":"Y","\u0232":"Y","\u1e8e":"Y","\u0178":"Y","\u1ef6":"Y","\u1ef4":"Y","\u01b3":"Y","\u024e":"Y","\u1efe":"Y","\u24cf":"Z","\uff3a":"Z","\u0179":"Z","\u1e90":"Z","\u017b":"Z","\u017d":"Z","\u1e92":"Z","\u1e94":"Z","\u01b5":"Z","\u0224":"Z","\u2c7f":"Z","\u2c6b":"Z","\ua762":"Z","\u24d0":"a","\uff41":"a","\u1e9a":"a","\xe0":"a","\xe1":"a","\xe2":"a","\u1ea7":"a","\u1ea5":"a","\u1eab":"a","\u1ea9":"a","\xe3":"a","\u0101":"a","\u0103":"a","\u1eb1":"a","\u1eaf":"a","\u1eb5":"a","\u1eb3":"a","\u0227":"a","\u01e1":"a","\xe4":"a","\u01df":"a","\u1ea3":"a","\xe5":"a","\u01fb":"a","\u01ce":"a","\u0201":"a","\u0203":"a","\u1ea1":"a","\u1ead":"a","\u1eb7":"a","\u1e01":"a","\u0105":"a","\u2c65":"a","\u0250":"a","\ua733":"aa","\xe6":"ae","\u01fd":"ae","\u01e3":"ae","\ua735":"ao","\ua737":"au","\ua739":"av","\ua73b":"av","\ua73d":"ay","\u24d1":"b","\uff42":"b","\u1e03":"b","\u1e05":"b","\u1e07":"b","\u0180":"b","\u0183":"b","\u0253":"b","\u24d2":"c","\uff43":"c","\u0107":"c","\u0109":"c","\u010b":"c","\u010d":"c","\xe7":"c","\u1e09":"c","\u0188":"c","\u023c":"c","\ua73f":"c","\u2184":"c","\u24d3":"d","\uff44":"d","\u1e0b":"d","\u010f":"d","\u1e0d":"d","\u1e11":"d","\u1e13":"d","\u1e0f":"d","\u0111":"d","\u018c":"d","\u0256":"d","\u0257":"d","\ua77a":"d","\u01f3":"dz","\u01c6":"dz","\u24d4":"e","\uff45":"e","\xe8":"e","\xe9":"e","\xea":"e","\u1ec1":"e","\u1ebf":"e","\u1ec5":"e","\u1ec3":"e","\u1ebd":"e","\u0113":"e","\u1e15":"e","\u1e17":"e","\u0115":"e","\u0117":"e","\xeb":"e","\u1ebb":"e","\u011b":"e","\u0205":"e","\u0207":"e","\u1eb9":"e","\u1ec7":"e","\u0229":"e","\u1e1d":"e","\u0119":"e","\u1e19":"e","\u1e1b":"e","\u0247":"e","\u025b":"e","\u01dd":"e","\u24d5":"f","\uff46":"f","\u1e1f":"f","\u0192":"f","\ua77c":"f","\u24d6":"g","\uff47":"g","\u01f5":"g","\u011d":"g","\u1e21":"g","\u011f":"g","\u0121":"g","\u01e7":"g","\u0123":"g","\u01e5":"g","\u0260":"g","\ua7a1":"g","\u1d79":"g","\ua77f":"g","\u24d7":"h","\uff48":"h","\u0125":"h","\u1e23":"h","\u1e27":"h","\u021f":"h","\u1e25":"h","\u1e29":"h","\u1e2b":"h","\u1e96":"h","\u0127":"h","\u2c68":"h","\u2c76":"h","\u0265":"h","\u0195":"hv","\u24d8":"i","\uff49":"i","\xec":"i","\xed":"i","\xee":"i","\u0129":"i","\u012b":"i","\u012d":"i","\xef":"i","\u1e2f":"i","\u1ec9":"i","\u01d0":"i","\u0209":"i","\u020b":"i","\u1ecb":"i","\u012f":"i","\u1e2d":"i","\u0268":"i","\u0131":"i","\u24d9":"j","\uff4a":"j","\u0135":"j","\u01f0":"j","\u0249":"j","\u24da":"k","\uff4b":"k","\u1e31":"k","\u01e9":"k","\u1e33":"k","\u0137":"k","\u1e35":"k","\u0199":"k","\u2c6a":"k","\ua741":"k","\ua743":"k","\ua745":"k","\ua7a3":"k","\u24db":"l","\uff4c":"l","\u0140":"l","\u013a":"l","\u013e":"l","\u1e37":"l","\u1e39":"l","\u013c":"l","\u1e3d":"l","\u1e3b":"l","\u017f":"l","\u0142":"l","\u019a":"l","\u026b":"l","\u2c61":"l","\ua749":"l","\ua781":"l","\ua747":"l","\u01c9":"lj","\u24dc":"m","\uff4d":"m","\u1e3f":"m","\u1e41":"m","\u1e43":"m","\u0271":"m","\u026f":"m","\u24dd":"n","\uff4e":"n","\u01f9":"n","\u0144":"n","\xf1":"n","\u1e45":"n","\u0148":"n","\u1e47":"n","\u0146":"n","\u1e4b":"n","\u1e49":"n","\u019e":"n","\u0272":"n","\u0149":"n","\ua791":"n","\ua7a5":"n","\u01cc":"nj","\u24de":"o","\uff4f":"o","\xf2":"o","\xf3":"o","\xf4":"o","\u1ed3":"o","\u1ed1":"o","\u1ed7":"o","\u1ed5":"o","\xf5":"o","\u1e4d":"o","\u022d":"o","\u1e4f":"o","\u014d":"o","\u1e51":"o","\u1e53":"o","\u014f":"o","\u022f":"o","\u0231":"o","\xf6":"o","\u022b":"o","\u1ecf":"o","\u0151":"o","\u01d2":"o","\u020d":"o","\u020f":"o","\u01a1":"o","\u1edd":"o","\u1edb":"o","\u1ee1":"o","\u1edf":"o","\u1ee3":"o","\u1ecd":"o","\u1ed9":"o","\u01eb":"o","\u01ed":"o","\xf8":"o","\u01ff":"o","\u0254":"o","\ua74b":"o","\ua74d":"o","\u0275":"o","\u01a3":"oi","\u0223":"ou","\ua74f":"oo","\u24df":"p","\uff50":"p","\u1e55":"p","\u1e57":"p","\u01a5":"p","\u1d7d":"p","\ua751":"p","\ua753":"p","\ua755":"p","\u24e0":"q","\uff51":"q","\u024b":"q","\ua757":"q","\ua759":"q","\u24e1":"r","\uff52":"r","\u0155":"r","\u1e59":"r","\u0159":"r","\u0211":"r","\u0213":"r","\u1e5b":"r","\u1e5d":"r","\u0157":"r","\u1e5f":"r","\u024d":"r","\u027d":"r","\ua75b":"r","\ua7a7":"r","\ua783":"r","\u24e2":"s","\uff53":"s","\xdf":"s","\u015b":"s","\u1e65":"s","\u015d":"s","\u1e61":"s","\u0161":"s","\u1e67":"s","\u1e63":"s","\u1e69":"s","\u0219":"s","\u015f":"s","\u023f":"s","\ua7a9":"s","\ua785":"s","\u1e9b":"s","\u24e3":"t","\uff54":"t","\u1e6b":"t","\u1e97":"t","\u0165":"t","\u1e6d":"t","\u021b":"t","\u0163":"t","\u1e71":"t","\u1e6f":"t","\u0167":"t","\u01ad":"t","\u0288":"t","\u2c66":"t","\ua787":"t","\ua729":"tz","\u24e4":"u","\uff55":"u","\xf9":"u","\xfa":"u","\xfb":"u","\u0169":"u","\u1e79":"u","\u016b":"u","\u1e7b":"u","\u016d":"u","\xfc":"u","\u01dc":"u","\u01d8":"u","\u01d6":"u","\u01da":"u","\u1ee7":"u","\u016f":"u","\u0171":"u","\u01d4":"u","\u0215":"u","\u0217":"u","\u01b0":"u","\u1eeb":"u","\u1ee9":"u","\u1eef":"u","\u1eed":"u","\u1ef1":"u","\u1ee5":"u","\u1e73":"u","\u0173":"u","\u1e77":"u","\u1e75":"u","\u0289":"u","\u24e5":"v","\uff56":"v","\u1e7d":"v","\u1e7f":"v","\u028b":"v","\ua75f":"v","\u028c":"v","\ua761":"vy","\u24e6":"w","\uff57":"w","\u1e81":"w","\u1e83":"w","\u0175":"w","\u1e87":"w","\u1e85":"w","\u1e98":"w","\u1e89":"w","\u2c73":"w","\u24e7":"x","\uff58":"x","\u1e8b":"x","\u1e8d":"x","\u24e8":"y","\uff59":"y","\u1ef3":"y","\xfd":"y","\u0177":"y","\u1ef9":"y","\u0233":"y","\u1e8f":"y","\xff":"y","\u1ef7":"y","\u1e99":"y","\u1ef5":"y","\u01b4":"y","\u024f":"y","\u1eff":"y","\u24e9":"z","\uff5a":"z","\u017a":"z","\u1e91":"z","\u017c":"z","\u017e":"z","\u1e93":"z","\u1e95":"z","\u01b6":"z","\u0225":"z","\u0240":"z","\u2c6c":"z","\ua763":"z"};j=a(document),g=function(){var a=1;return function(){return a++}}(),j.on("mousemove",function(a){i.x=a.pageX,i.y=a.pageY}),d=N(Object,{bind:function(a){var b=this;return function(){a.apply(b,arguments)}},init:function(c){var d,e,f=".select2-results";this.opts=c=this.prepareOpts(c),this.id=c.id,c.element.data("select2")!==b&&null!==c.element.data("select2")&&c.element.data("select2").destroy(),this.container=this.createContainer(),this.containerId="s2id_"+(c.element.attr("id")||"autogen"+g()),this.containerSelector="#"+this.containerId.replace(/([;&,\.\+\*\~':"\!\^#$%@\[\]\(\)=>\|])/g,"\\$1"),this.container.attr("id",this.containerId),this.body=w(function(){return c.element.closest("body")}),D(this.container,this.opts.element,this.opts.adaptContainerCssClass),this.container.attr("style",c.element.attr("style")),this.container.css(K(c.containerCss)),this.container.addClass(K(c.containerCssClass)),this.elementTabIndex=this.opts.element.attr("tabindex"),this.opts.element.data("select2",this).attr("tabindex","-1").before(this.container).on("click.select2",A),this.container.data("select2",this),this.dropdown=this.container.find(".select2-drop"),D(this.dropdown,this.opts.element,this.opts.adaptDropdownCssClass),this.dropdown.addClass(K(c.dropdownCssClass)),this.dropdown.data("select2",this),this.dropdown.on("click",A),this.results=d=this.container.find(f),this.search=e=this.container.find("input.select2-input"),this.queryCount=0,this.resultsPage=0,this.context=null,this.initContainer(),this.container.on("click",A),u(this.results),this.dropdown.on("mousemove-filtered touchstart touchmove touchend",f,this.bind(this.highlightUnderEvent)),x(80,this.results),this.dropdown.on("scroll-debounced",f,this.bind(this.loadMoreIfNeeded)),a(this.container).on("change",".select2-input",function(a){a.stopPropagation()}),a(this.dropdown).on("change",".select2-input",function(a){a.stopPropagation()}),a.fn.mousewheel&&d.mousewheel(function(a,b,c,e){var f=d.scrollTop();e>0&&0>=f-e?(d.scrollTop(0),A(a)):0>e&&d.get(0).scrollHeight-d.scrollTop()+e<=d.height()&&(d.scrollTop(d.get(0).scrollHeight-d.height()),A(a))}),t(e),e.on("keyup-change input paste",this.bind(this.updateResults)),e.on("focus",function(){e.addClass("select2-focused")}),e.on("blur",function(){e.removeClass("select2-focused")}),this.dropdown.on("mouseup",f,this.bind(function(b){a(b.target).closest(".select2-result-selectable").length>0&&(this.highlightUnderEvent(b),this.selectHighlighted(b))})),this.dropdown.on("click mouseup mousedown",function(a){a.stopPropagation()}),a.isFunction(this.opts.initSelection)&&(this.initSelection(),this.monitorSource()),null!==c.maximumInputLength&&this.search.attr("maxlength",c.maximumInputLength);var h=c.element.prop("disabled");h===b&&(h=!1),this.enable(!h);var i=c.element.prop("readonly");i===b&&(i=!1),this.readonly(i),k=k||p(),this.autofocus=c.element.prop("autofocus"),c.element.prop("autofocus",!1),this.autofocus&&this.focus(),this.nextSearchTerm=b},destroy:function(){var a=this.opts.element,c=a.data("select2");this.close(),this.propertyObserver&&(delete this.propertyObserver,this.propertyObserver=null),c!==b&&(c.container.remove(),c.dropdown.remove(),a.removeClass("select2-offscreen").removeData("select2").off(".select2").prop("autofocus",this.autofocus||!1),this.elementTabIndex?a.attr({tabindex:this.elementTabIndex}):a.removeAttr("tabindex"),a.show())},optionToData:function(a){return a.is("option")?{id:a.prop("value"),text:a.text(),element:a.get(),css:a.attr("class"),disabled:a.prop("disabled"),locked:q(a.attr("locked"),"locked")||q(a.data("locked"),!0)}:a.is("optgroup")?{text:a.attr("label"),children:[],element:a.get(),css:a.attr("class")}:void 0},prepareOpts:function(c){var d,e,f,g,h=this;if(d=c.element,"select"===d.get(0).tagName.toLowerCase()&&(this.select=e=c.element),e&&a.each(["id","multiple","ajax","query","createSearchChoice","initSelection","data","tags"],function(){if(this in c)throw new Error("Option '"+this+"' is not allowed for Select2 when attached to a <select> element.")}),c=a.extend({},{populateResults:function(d,e,f){var g,i=this.opts.id;g=function(d,e,j){var k,l,m,n,o,p,q,r,s,t;for(d=c.sortResults(d,e,f),k=0,l=d.length;l>k;k+=1)m=d[k],o=m.disabled===!0,n=!o&&i(m)!==b,p=m.children&&m.children.length>0,q=a("<li></li>"),q.addClass("select2-results-dept-"+j),q.addClass("select2-result"),q.addClass(n?"select2-result-selectable":"select2-result-unselectable"),o&&q.addClass("select2-disabled"),p&&q.addClass("select2-result-with-children"),q.addClass(h.opts.formatResultCssClass(m)),r=a(document.createElement("div")),r.addClass("select2-result-label"),t=c.formatResult(m,r,f,h.opts.escapeMarkup),t!==b&&r.html(t),q.append(r),p&&(s=a("<ul></ul>"),s.addClass("select2-result-sub"),g(m.children,s,j+1),q.append(s)),q.data("select2-data",m),e.append(q)},g(e,d,0)}},a.fn.select2.defaults,c),"function"!=typeof c.id&&(f=c.id,c.id=function(a){return a[f]}),a.isArray(c.element.data("select2Tags"))){if("tags"in c)throw"tags specified as both an attribute 'data-select2-tags' and in options of Select2 "+c.element.attr("id");c.tags=c.element.data("select2Tags")}if(e?(c.query=this.bind(function(a){var f,g,i,c={results:[],more:!1},e=a.term;i=function(b,c){var d;b.is("option")?a.matcher(e,b.text(),b)&&c.push(h.optionToData(b)):b.is("optgroup")&&(d=h.optionToData(b),b.children().each2(function(a,b){i(b,d.children)}),d.children.length>0&&c.push(d))},f=d.children(),this.getPlaceholder()!==b&&f.length>0&&(g=this.getPlaceholderOption(),g&&(f=f.not(g))),f.each2(function(a,b){i(b,c.results)}),a.callback(c)}),c.id=function(a){return a.id},c.formatResultCssClass=function(a){return a.css}):"query"in c||("ajax"in c?(g=c.element.data("ajax-url"),g&&g.length>0&&(c.ajax.url=g),c.query=G.call(c.element,c.ajax)):"data"in c?c.query=H(c.data):"tags"in c&&(c.query=I(c.tags),c.createSearchChoice===b&&(c.createSearchChoice=function(b){return{id:a.trim(b),text:a.trim(b)}}),c.initSelection===b&&(c.initSelection=function(b,d){var e=[];a(r(b.val(),c.separator)).each(function(){var b={id:this,text:this},d=c.tags;a.isFunction(d)&&(d=d()),a(d).each(function(){return q(this.id,b.id)?(b=this,!1):void 0}),e.push(b)}),d(e)}))),"function"!=typeof c.query)throw"query function not defined for Select2 "+c.element.attr("id");return c},monitorSource:function(){var c,d,a=this.opts.element;a.on("change.select2",this.bind(function(){this.opts.element.data("select2-change-triggered")!==!0&&this.initSelection()})),c=this.bind(function(){var c=a.prop("disabled");c===b&&(c=!1),this.enable(!c);var d=a.prop("readonly");d===b&&(d=!1),this.readonly(d),D(this.container,this.opts.element,this.opts.adaptContainerCssClass),this.container.addClass(K(this.opts.containerCssClass)),D(this.dropdown,this.opts.element,this.opts.adaptDropdownCssClass),this.dropdown.addClass(K(this.opts.dropdownCssClass))}),a.on("propertychange.select2",c),this.mutationCallback===b&&(this.mutationCallback=function(a){a.forEach(c)}),d=window.MutationObserver||window.WebKitMutationObserver||window.MozMutationObserver,d!==b&&(this.propertyObserver&&(delete this.propertyObserver,this.propertyObserver=null),this.propertyObserver=new d(this.mutationCallback),this.propertyObserver.observe(a.get(0),{attributes:!0,subtree:!1}))},triggerSelect:function(b){var c=a.Event("select2-selecting",{val:this.id(b),object:b});return this.opts.element.trigger(c),!c.isDefaultPrevented()},triggerChange:function(b){b=b||{},b=a.extend({},b,{type:"change",val:this.val()}),this.opts.element.data("select2-change-triggered",!0),this.opts.element.trigger(b),this.opts.element.data("select2-change-triggered",!1),this.opts.element.click(),this.opts.blurOnChange&&this.opts.element.blur()},isInterfaceEnabled:function(){return this.enabledInterface===!0},enableInterface:function(){var a=this._enabled&&!this._readonly,b=!a;return a===this.enabledInterface?!1:(this.container.toggleClass("select2-container-disabled",b),this.close(),this.enabledInterface=a,!0)},enable:function(a){a===b&&(a=!0),this._enabled!==a&&(this._enabled=a,this.opts.element.prop("disabled",!a),this.enableInterface())},disable:function(){this.enable(!1)},readonly:function(a){return a===b&&(a=!1),this._readonly===a?!1:(this._readonly=a,this.opts.element.prop("readonly",a),this.enableInterface(),!0)},opened:function(){return this.container.hasClass("select2-dropdown-open")},positionDropdown:function(){var t,u,v,w,x,b=this.dropdown,c=this.container.offset(),d=this.container.outerHeight(!1),e=this.container.outerWidth(!1),f=b.outerHeight(!1),g=a(window),h=g.width(),i=g.height(),j=g.scrollLeft()+h,l=g.scrollTop()+i,m=c.top+d,n=c.left,o=l>=m+f,p=c.top-f>=this.body().scrollTop(),q=b.outerWidth(!1),r=j>=n+q,s=b.hasClass("select2-drop-above");s?(u=!0,!p&&o&&(v=!0,u=!1)):(u=!1,!o&&p&&(v=!0,u=!0)),v&&(b.hide(),c=this.container.offset(),d=this.container.outerHeight(!1),e=this.container.outerWidth(!1),f=b.outerHeight(!1),j=g.scrollLeft()+h,l=g.scrollTop()+i,m=c.top+d,n=c.left,q=b.outerWidth(!1),r=j>=n+q,b.show()),this.opts.dropdownAutoWidth?(x=a(".select2-results",b)[0],b.addClass("select2-drop-auto-width"),b.css("width",""),q=b.outerWidth(!1)+(x.scrollHeight===x.clientHeight?0:k.width),q>e?e=q:q=e,r=j>=n+q):this.container.removeClass("select2-drop-auto-width"),"static"!==this.body().css("position")&&(t=this.body().offset(),m-=t.top,n-=t.left),r||(n=c.left+e-q),w={left:n,width:e},u?(w.bottom=i-c.top,w.top="auto",this.container.addClass("select2-drop-above"),b.addClass("select2-drop-above")):(w.top=m,w.bottom="auto",this.container.removeClass("select2-drop-above"),b.removeClass("select2-drop-above")),w=a.extend(w,K(this.opts.dropdownCss)),b.css(w)},shouldOpen:function(){var b;return this.opened()?!1:this._enabled===!1||this._readonly===!0?!1:(b=a.Event("select2-opening"),this.opts.element.trigger(b),!b.isDefaultPrevented())},clearDropdownAlignmentPreference:function(){this.container.removeClass("select2-drop-above"),this.dropdown.removeClass("select2-drop-above")},open:function(){return this.shouldOpen()?(this.opening(),!0):!1},opening:function(){var f,b=this.containerId,c="scroll."+b,d="resize."+b,e="orientationchange."+b;this.container.addClass("select2-dropdown-open").addClass("select2-container-active"),this.clearDropdownAlignmentPreference(),this.dropdown[0]!==this.body().children().last()[0]&&this.dropdown.detach().appendTo(this.body()),f=a("#select2-drop-mask"),0==f.length&&(f=a(document.createElement("div")),f.attr("id","select2-drop-mask").attr("class","select2-drop-mask"),f.hide(),f.appendTo(this.body()),f.on("mousedown touchstart click",function(b){var d,c=a("#select2-drop");c.length>0&&(d=c.data("select2"),d.opts.selectOnBlur&&d.selectHighlighted({noFocus:!0}),d.close({focus:!0}),b.preventDefault(),b.stopPropagation())})),this.dropdown.prev()[0]!==f[0]&&this.dropdown.before(f),a("#select2-drop").removeAttr("id"),this.dropdown.attr("id","select2-drop"),f.show(),this.positionDropdown(),this.dropdown.show(),this.positionDropdown(),this.dropdown.addClass("select2-drop-active");var g=this;this.container.parents().add(window).each(function(){a(this).on(d+" "+c+" "+e,function(){g.positionDropdown()})})},close:function(){if(this.opened()){var b=this.containerId,c="scroll."+b,d="resize."+b,e="orientationchange."+b;this.container.parents().add(window).each(function(){a(this).off(c).off(d).off(e)}),this.clearDropdownAlignmentPreference(),a("#select2-drop-mask").hide(),this.dropdown.removeAttr("id"),this.dropdown.hide(),this.container.removeClass("select2-dropdown-open").removeClass("select2-container-active"),this.results.empty(),this.clearSearch(),this.search.removeClass("select2-active"),this.opts.element.trigger(a.Event("select2-close"))}},externalSearch:function(a){this.open(),this.search.val(a),this.updateResults(!1)},clearSearch:function(){},getMaximumSelectionSize:function(){return K(this.opts.maximumSelectionSize)},ensureHighlightVisible:function(){var c,d,e,f,g,h,i,b=this.results;if(d=this.highlight(),!(0>d)){if(0==d)return b.scrollTop(0),void 0;c=this.findHighlightableChoices().find(".select2-result-label"),e=a(c[d]),f=e.offset().top+e.outerHeight(!0),d===c.length-1&&(i=b.find("li.select2-more-results"),i.length>0&&(f=i.offset().top+i.outerHeight(!0))),g=b.offset().top+b.outerHeight(!0),f>g&&b.scrollTop(b.scrollTop()+(f-g)),h=e.offset().top-b.offset().top,0>h&&"none"!=e.css("display")&&b.scrollTop(b.scrollTop()+h)}},findHighlightableChoices:function(){return this.results.find(".select2-result-selectable:not(.select2-disabled, .select2-selected)")},moveHighlight:function(b){for(var c=this.findHighlightableChoices(),d=this.highlight();d>-1&&d<c.length;){d+=b;var e=a(c[d]);if(e.hasClass("select2-result-selectable")&&!e.hasClass("select2-disabled")&&!e.hasClass("select2-selected")){this.highlight(d);break}}},highlight:function(b){var d,e,c=this.findHighlightableChoices();return 0===arguments.length?o(c.filter(".select2-highlighted")[0],c.get()):(b>=c.length&&(b=c.length-1),0>b&&(b=0),this.removeHighlight(),d=a(c[b]),d.addClass("select2-highlighted"),this.ensureHighlightVisible(),e=d.data("select2-data"),e&&this.opts.element.trigger({type:"select2-highlight",val:this.id(e),choice:e}),void 0)},removeHighlight:function(){this.results.find(".select2-highlighted").removeClass("select2-highlighted")},countSelectableResults:function(){return this.findHighlightableChoices().length},highlightUnderEvent:function(b){var c=a(b.target).closest(".select2-result-selectable");if(c.length>0&&!c.is(".select2-highlighted")){var d=this.findHighlightableChoices();this.highlight(d.index(c))}else 0==c.length&&this.removeHighlight()},loadMoreIfNeeded:function(){var c,a=this.results,b=a.find("li.select2-more-results"),d=this.resultsPage+1,e=this,f=this.search.val(),g=this.context;0!==b.length&&(c=b.offset().top-a.offset().top-a.height(),c<=this.opts.loadMorePadding&&(b.addClass("select2-active"),this.opts.query({element:this.opts.element,term:f,page:d,context:g,matcher:this.opts.matcher,callback:this.bind(function(c){e.opened()&&(e.opts.populateResults.call(this,a,c.results,{term:f,page:d,context:g}),e.postprocessResults(c,!1,!1),c.more===!0?(b.detach().appendTo(a).text(e.opts.formatLoadMore(d+1)),window.setTimeout(function(){e.loadMoreIfNeeded()},10)):b.remove(),e.positionDropdown(),e.resultsPage=d,e.context=c.context,this.opts.element.trigger({type:"select2-loaded",items:c}))})})))},tokenize:function(){},updateResults:function(c){function m(){d.removeClass("select2-active"),h.positionDropdown()}function n(a){e.html(a),m()}var g,i,l,d=this.search,e=this.results,f=this.opts,h=this,j=d.val(),k=a.data(this.container,"select2-last-term");if((c===!0||!k||!q(j,k))&&(a.data(this.container,"select2-last-term",j),c===!0||this.showSearchInput!==!1&&this.opened())){l=++this.queryCount;var o=this.getMaximumSelectionSize();if(o>=1&&(g=this.data(),a.isArray(g)&&g.length>=o&&J(f.formatSelectionTooBig,"formatSelectionTooBig")))return n("<li class='select2-selection-limit'>"+f.formatSelectionTooBig(o)+"</li>"),void 0;if(d.val().length<f.minimumInputLength)return J(f.formatInputTooShort,"formatInputTooShort")?n("<li class='select2-no-results'>"+f.formatInputTooShort(d.val(),f.minimumInputLength)+"</li>"):n(""),c&&this.showSearch&&this.showSearch(!0),void 0;
+if(f.maximumInputLength&&d.val().length>f.maximumInputLength)return J(f.formatInputTooLong,"formatInputTooLong")?n("<li class='select2-no-results'>"+f.formatInputTooLong(d.val(),f.maximumInputLength)+"</li>"):n(""),void 0;f.formatSearching&&0===this.findHighlightableChoices().length&&n("<li class='select2-searching'>"+f.formatSearching()+"</li>"),d.addClass("select2-active"),this.removeHighlight(),i=this.tokenize(),i!=b&&null!=i&&d.val(i),this.resultsPage=1,f.query({element:f.element,term:d.val(),page:this.resultsPage,context:null,matcher:f.matcher,callback:this.bind(function(g){var i;if(l==this.queryCount){if(!this.opened())return this.search.removeClass("select2-active"),void 0;if(this.context=g.context===b?null:g.context,this.opts.createSearchChoice&&""!==d.val()&&(i=this.opts.createSearchChoice.call(h,d.val(),g.results),i!==b&&null!==i&&h.id(i)!==b&&null!==h.id(i)&&0===a(g.results).filter(function(){return q(h.id(this),h.id(i))}).length&&g.results.unshift(i)),0===g.results.length&&J(f.formatNoMatches,"formatNoMatches"))return n("<li class='select2-no-results'>"+f.formatNoMatches(d.val())+"</li>"),void 0;e.empty(),h.opts.populateResults.call(this,e,g.results,{term:d.val(),page:this.resultsPage,context:null}),g.more===!0&&J(f.formatLoadMore,"formatLoadMore")&&(e.append("<li class='select2-more-results'>"+h.opts.escapeMarkup(f.formatLoadMore(this.resultsPage))+"</li>"),window.setTimeout(function(){h.loadMoreIfNeeded()},10)),this.postprocessResults(g,c),m(),this.opts.element.trigger({type:"select2-loaded",items:g})}})})}},cancel:function(){this.close()},blur:function(){this.opts.selectOnBlur&&this.selectHighlighted({noFocus:!0}),this.close(),this.container.removeClass("select2-container-active"),this.search[0]===document.activeElement&&this.search.blur(),this.clearSearch(),this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus")},focusSearch:function(){y(this.search)},selectHighlighted:function(a){var b=this.highlight(),c=this.results.find(".select2-highlighted"),d=c.closest(".select2-result").data("select2-data");d?(this.highlight(b),this.onSelect(d,a)):a&&a.noFocus&&this.close()},getPlaceholder:function(){var a;return this.opts.element.attr("placeholder")||this.opts.element.attr("data-placeholder")||this.opts.element.data("placeholder")||this.opts.placeholder||((a=this.getPlaceholderOption())!==b?a.text():b)},getPlaceholderOption:function(){if(this.select){var a=this.select.children("option").first();if(this.opts.placeholderOption!==b)return"first"===this.opts.placeholderOption&&a||"function"==typeof this.opts.placeholderOption&&this.opts.placeholderOption(this.select);if(""===a.text()&&""===a.val())return a}},initContainerWidth:function(){function c(){var c,d,e,f,g,h;if("off"===this.opts.width)return null;if("element"===this.opts.width)return 0===this.opts.element.outerWidth(!1)?"auto":this.opts.element.outerWidth(!1)+"px";if("copy"===this.opts.width||"resolve"===this.opts.width){if(c=this.opts.element.attr("style"),c!==b)for(d=c.split(";"),f=0,g=d.length;g>f;f+=1)if(h=d[f].replace(/\s/g,""),e=h.match(/^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i),null!==e&&e.length>=1)return e[1];return"resolve"===this.opts.width?(c=this.opts.element.css("width"),c.indexOf("%")>0?c:0===this.opts.element.outerWidth(!1)?"auto":this.opts.element.outerWidth(!1)+"px"):null}return a.isFunction(this.opts.width)?this.opts.width():this.opts.width}var d=c.call(this);null!==d&&this.container.css("width",d)}}),e=N(d,{createContainer:function(){var b=a(document.createElement("div")).attr({"class":"select2-container"}).html(["<a href='javascript:void(0)' onclick='return false;' class='select2-choice' tabindex='-1'>"," <span class='select2-chosen'> </span><abbr class='select2-search-choice-close'></abbr>"," <span class='select2-arrow'><b></b></span>","</a>","<input class='select2-focusser select2-offscreen' type='text'/>","<div class='select2-drop select2-display-none'>"," <div class='select2-search'>"," <input type='text' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false' class='select2-input'/>"," </div>"," <ul class='select2-results'>"," </ul>","</div>"].join(""));return b},enableInterface:function(){this.parent.enableInterface.apply(this,arguments)&&this.focusser.prop("disabled",!this.isInterfaceEnabled())},opening:function(){var c,d,e;this.opts.minimumResultsForSearch>=0&&this.showSearch(!0),this.parent.opening.apply(this,arguments),this.showSearchInput!==!1&&this.search.val(this.focusser.val()),this.search.focus(),c=this.search.get(0),c.createTextRange?(d=c.createTextRange(),d.collapse(!1),d.select()):c.setSelectionRange&&(e=this.search.val().length,c.setSelectionRange(e,e)),""===this.search.val()&&this.nextSearchTerm!=b&&(this.search.val(this.nextSearchTerm),this.search.select()),this.focusser.prop("disabled",!0).val(""),this.updateResults(!0),this.opts.element.trigger(a.Event("select2-open"))},close:function(a){this.opened()&&(this.parent.close.apply(this,arguments),a=a||{focus:!0},this.focusser.removeAttr("disabled"),a.focus&&this.focusser.focus())},focus:function(){this.opened()?this.close():(this.focusser.removeAttr("disabled"),this.focusser.focus())},isFocused:function(){return this.container.hasClass("select2-container-active")},cancel:function(){this.parent.cancel.apply(this,arguments),this.focusser.removeAttr("disabled"),this.focusser.focus()},destroy:function(){a("label[for='"+this.focusser.attr("id")+"']").attr("for",this.opts.element.attr("id")),this.parent.destroy.apply(this,arguments)},initContainer:function(){var b,d=this.container,e=this.dropdown;this.opts.minimumResultsForSearch<0?this.showSearch(!1):this.showSearch(!0),this.selection=b=d.find(".select2-choice"),this.focusser=d.find(".select2-focusser"),this.focusser.attr("id","s2id_autogen"+g()),a("label[for='"+this.opts.element.attr("id")+"']").attr("for",this.focusser.attr("id")),this.focusser.attr("tabindex",this.elementTabIndex),this.search.on("keydown",this.bind(function(a){if(this.isInterfaceEnabled()){if(a.which===c.PAGE_UP||a.which===c.PAGE_DOWN)return A(a),void 0;switch(a.which){case c.UP:case c.DOWN:return this.moveHighlight(a.which===c.UP?-1:1),A(a),void 0;case c.ENTER:return this.selectHighlighted(),A(a),void 0;case c.TAB:return this.selectHighlighted({noFocus:!0}),void 0;case c.ESC:return this.cancel(a),A(a),void 0}}})),this.search.on("blur",this.bind(function(){document.activeElement===this.body().get(0)&&window.setTimeout(this.bind(function(){this.search.focus()}),0)})),this.focusser.on("keydown",this.bind(function(a){if(this.isInterfaceEnabled()&&a.which!==c.TAB&&!c.isControl(a)&&!c.isFunctionKey(a)&&a.which!==c.ESC){if(this.opts.openOnEnter===!1&&a.which===c.ENTER)return A(a),void 0;if(a.which==c.DOWN||a.which==c.UP||a.which==c.ENTER&&this.opts.openOnEnter){if(a.altKey||a.ctrlKey||a.shiftKey||a.metaKey)return;return this.open(),A(a),void 0}return a.which==c.DELETE||a.which==c.BACKSPACE?(this.opts.allowClear&&this.clear(),A(a),void 0):void 0}})),t(this.focusser),this.focusser.on("keyup-change input",this.bind(function(a){if(this.opts.minimumResultsForSearch>=0){if(a.stopPropagation(),this.opened())return;this.open()}})),b.on("mousedown","abbr",this.bind(function(a){this.isInterfaceEnabled()&&(this.clear(),B(a),this.close(),this.selection.focus())})),b.on("mousedown",this.bind(function(b){this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.opened()?this.close():this.isInterfaceEnabled()&&this.open(),A(b)})),e.on("mousedown",this.bind(function(){this.search.focus()})),b.on("focus",this.bind(function(a){A(a)})),this.focusser.on("focus",this.bind(function(){this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.container.addClass("select2-container-active")})).on("blur",this.bind(function(){this.opened()||(this.container.removeClass("select2-container-active"),this.opts.element.trigger(a.Event("select2-blur")))})),this.search.on("focus",this.bind(function(){this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.container.addClass("select2-container-active")})),this.initContainerWidth(),this.opts.element.addClass("select2-offscreen"),this.setPlaceholder()},clear:function(b){var c=this.selection.data("select2-data");if(c){var d=a.Event("select2-clearing");if(this.opts.element.trigger(d),d.isDefaultPrevented())return;var e=this.getPlaceholderOption();this.opts.element.val(e?e.val():""),this.selection.find(".select2-chosen").empty(),this.selection.removeData("select2-data"),this.setPlaceholder(),b!==!1&&(this.opts.element.trigger({type:"select2-removed",val:this.id(c),choice:c}),this.triggerChange({removed:c}))}},initSelection:function(){if(this.isPlaceholderOptionSelected())this.updateSelection(null),this.close(),this.setPlaceholder();else{var c=this;this.opts.initSelection.call(null,this.opts.element,function(a){a!==b&&null!==a&&(c.updateSelection(a),c.close(),c.setPlaceholder())})}},isPlaceholderOptionSelected:function(){var a;return this.getPlaceholder()?(a=this.getPlaceholderOption())!==b&&a.prop("selected")||""===this.opts.element.val()||this.opts.element.val()===b||null===this.opts.element.val():!1},prepareOpts:function(){var b=this.parent.prepareOpts.apply(this,arguments),c=this;return"select"===b.element.get(0).tagName.toLowerCase()?b.initSelection=function(a,b){var d=a.find("option").filter(function(){return this.selected});b(c.optionToData(d))}:"data"in b&&(b.initSelection=b.initSelection||function(c,d){var e=c.val(),f=null;b.query({matcher:function(a,c,d){var g=q(e,b.id(d));return g&&(f=d),g},callback:a.isFunction(d)?function(){d(f)}:a.noop})}),b},getPlaceholder:function(){return this.select&&this.getPlaceholderOption()===b?b:this.parent.getPlaceholder.apply(this,arguments)},setPlaceholder:function(){var a=this.getPlaceholder();if(this.isPlaceholderOptionSelected()&&a!==b){if(this.select&&this.getPlaceholderOption()===b)return;this.selection.find(".select2-chosen").html(this.opts.escapeMarkup(a)),this.selection.addClass("select2-default"),this.container.removeClass("select2-allowclear")}},postprocessResults:function(a,b,c){var d=0,e=this;if(this.findHighlightableChoices().each2(function(a,b){return q(e.id(b.data("select2-data")),e.opts.element.val())?(d=a,!1):void 0}),c!==!1&&(b===!0&&d>=0?this.highlight(d):this.highlight(0)),b===!0){var g=this.opts.minimumResultsForSearch;g>=0&&this.showSearch(L(a.results)>=g)}},showSearch:function(b){this.showSearchInput!==b&&(this.showSearchInput=b,this.dropdown.find(".select2-search").toggleClass("select2-search-hidden",!b),this.dropdown.find(".select2-search").toggleClass("select2-offscreen",!b),a(this.dropdown,this.container).toggleClass("select2-with-searchbox",b))},onSelect:function(a,b){if(this.triggerSelect(a)){var c=this.opts.element.val(),d=this.data();this.opts.element.val(this.id(a)),this.updateSelection(a),this.opts.element.trigger({type:"select2-selected",val:this.id(a),choice:a}),this.nextSearchTerm=this.opts.nextSearchTerm(a,this.search.val()),this.close(),b&&b.noFocus||this.focusser.focus(),q(c,this.id(a))||this.triggerChange({added:a,removed:d})}},updateSelection:function(a){var d,e,c=this.selection.find(".select2-chosen");this.selection.data("select2-data",a),c.empty(),null!==a&&(d=this.opts.formatSelection(a,c,this.opts.escapeMarkup)),d!==b&&c.append(d),e=this.opts.formatSelectionCssClass(a,c),e!==b&&c.addClass(e),this.selection.removeClass("select2-default"),this.opts.allowClear&&this.getPlaceholder()!==b&&this.container.addClass("select2-allowclear")},val:function(){var a,c=!1,d=null,e=this,f=this.data();if(0===arguments.length)return this.opts.element.val();if(a=arguments[0],arguments.length>1&&(c=arguments[1]),this.select)this.select.val(a).find("option").filter(function(){return this.selected}).each2(function(a,b){return d=e.optionToData(b),!1}),this.updateSelection(d),this.setPlaceholder(),c&&this.triggerChange({added:d,removed:f});else{if(!a&&0!==a)return this.clear(c),void 0;if(this.opts.initSelection===b)throw new Error("cannot call val() if initSelection() is not defined");this.opts.element.val(a),this.opts.initSelection(this.opts.element,function(a){e.opts.element.val(a?e.id(a):""),e.updateSelection(a),e.setPlaceholder(),c&&e.triggerChange({added:a,removed:f})})}},clearSearch:function(){this.search.val(""),this.focusser.val("")},data:function(a){var c,d=!1;return 0===arguments.length?(c=this.selection.data("select2-data"),c==b&&(c=null),c):(arguments.length>1&&(d=arguments[1]),a?(c=this.data(),this.opts.element.val(a?this.id(a):""),this.updateSelection(a),d&&this.triggerChange({added:a,removed:c})):this.clear(d),void 0)}}),f=N(d,{createContainer:function(){var b=a(document.createElement("div")).attr({"class":"select2-container select2-container-multi"}).html(["<ul class='select2-choices'>"," <li class='select2-search-field'>"," <input type='text' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false' class='select2-input'>"," </li>","</ul>","<div class='select2-drop select2-drop-multi select2-display-none'>"," <ul class='select2-results'>"," </ul>","</div>"].join(""));return b},prepareOpts:function(){var b=this.parent.prepareOpts.apply(this,arguments),c=this;return"select"===b.element.get(0).tagName.toLowerCase()?b.initSelection=function(a,b){var d=[];a.find("option").filter(function(){return this.selected}).each2(function(a,b){d.push(c.optionToData(b))}),b(d)}:"data"in b&&(b.initSelection=b.initSelection||function(c,d){var e=r(c.val(),b.separator),f=[];b.query({matcher:function(c,d,g){var h=a.grep(e,function(a){return q(a,b.id(g))}).length;return h&&f.push(g),h},callback:a.isFunction(d)?function(){for(var a=[],c=0;c<e.length;c++)for(var g=e[c],h=0;h<f.length;h++){var i=f[h];if(q(g,b.id(i))){a.push(i),f.splice(h,1);break}}d(a)}:a.noop})}),b},selectChoice:function(a){var b=this.container.find(".select2-search-choice-focus");b.length&&a&&a[0]==b[0]||(b.length&&this.opts.element.trigger("choice-deselected",b),b.removeClass("select2-search-choice-focus"),a&&a.length&&(this.close(),a.addClass("select2-search-choice-focus"),this.opts.element.trigger("choice-selected",a)))},destroy:function(){a("label[for='"+this.search.attr("id")+"']").attr("for",this.opts.element.attr("id")),this.parent.destroy.apply(this,arguments)},initContainer:function(){var d,b=".select2-choices";this.searchContainer=this.container.find(".select2-search-field"),this.selection=d=this.container.find(b);var e=this;this.selection.on("click",".select2-search-choice:not(.select2-locked)",function(){e.search[0].focus(),e.selectChoice(a(this))}),this.search.attr("id","s2id_autogen"+g()),a("label[for='"+this.opts.element.attr("id")+"']").attr("for",this.search.attr("id")),this.search.on("input paste",this.bind(function(){this.isInterfaceEnabled()&&(this.opened()||this.open())})),this.search.attr("tabindex",this.elementTabIndex),this.keydowns=0,this.search.on("keydown",this.bind(function(a){if(this.isInterfaceEnabled()){++this.keydowns;var b=d.find(".select2-search-choice-focus"),e=b.prev(".select2-search-choice:not(.select2-locked)"),f=b.next(".select2-search-choice:not(.select2-locked)"),g=z(this.search);if(b.length&&(a.which==c.LEFT||a.which==c.RIGHT||a.which==c.BACKSPACE||a.which==c.DELETE||a.which==c.ENTER)){var h=b;return a.which==c.LEFT&&e.length?h=e:a.which==c.RIGHT?h=f.length?f:null:a.which===c.BACKSPACE?(this.unselect(b.first()),this.search.width(10),h=e.length?e:f):a.which==c.DELETE?(this.unselect(b.first()),this.search.width(10),h=f.length?f:null):a.which==c.ENTER&&(h=null),this.selectChoice(h),A(a),h&&h.length||this.open(),void 0}if((a.which===c.BACKSPACE&&1==this.keydowns||a.which==c.LEFT)&&0==g.offset&&!g.length)return this.selectChoice(d.find(".select2-search-choice:not(.select2-locked)").last()),A(a),void 0;if(this.selectChoice(null),this.opened())switch(a.which){case c.UP:case c.DOWN:return this.moveHighlight(a.which===c.UP?-1:1),A(a),void 0;case c.ENTER:return this.selectHighlighted(),A(a),void 0;case c.TAB:return this.selectHighlighted({noFocus:!0}),this.close(),void 0;case c.ESC:return this.cancel(a),A(a),void 0}if(a.which!==c.TAB&&!c.isControl(a)&&!c.isFunctionKey(a)&&a.which!==c.BACKSPACE&&a.which!==c.ESC){if(a.which===c.ENTER){if(this.opts.openOnEnter===!1)return;if(a.altKey||a.ctrlKey||a.shiftKey||a.metaKey)return}this.open(),(a.which===c.PAGE_UP||a.which===c.PAGE_DOWN)&&A(a),a.which===c.ENTER&&A(a)}}})),this.search.on("keyup",this.bind(function(){this.keydowns=0,this.resizeSearch()})),this.search.on("blur",this.bind(function(b){this.container.removeClass("select2-container-active"),this.search.removeClass("select2-focused"),this.selectChoice(null),this.opened()||this.clearSearch(),b.stopImmediatePropagation(),this.opts.element.trigger(a.Event("select2-blur"))})),this.container.on("click",b,this.bind(function(b){this.isInterfaceEnabled()&&(a(b.target).closest(".select2-search-choice").length>0||(this.selectChoice(null),this.clearPlaceholder(),this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.open(),this.focusSearch(),b.preventDefault()))})),this.container.on("focus",b,this.bind(function(){this.isInterfaceEnabled()&&(this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.container.addClass("select2-container-active"),this.dropdown.addClass("select2-drop-active"),this.clearPlaceholder())})),this.initContainerWidth(),this.opts.element.addClass("select2-offscreen"),this.clearSearch()},enableInterface:function(){this.parent.enableInterface.apply(this,arguments)&&this.search.prop("disabled",!this.isInterfaceEnabled())},initSelection:function(){if(""===this.opts.element.val()&&""===this.opts.element.text()&&(this.updateSelection([]),this.close(),this.clearSearch()),this.select||""!==this.opts.element.val()){var c=this;this.opts.initSelection.call(null,this.opts.element,function(a){a!==b&&null!==a&&(c.updateSelection(a),c.close(),c.clearSearch())})}},clearSearch:function(){var a=this.getPlaceholder(),c=this.getMaxSearchWidth();a!==b&&0===this.getVal().length&&this.search.hasClass("select2-focused")===!1?(this.search.val(a).addClass("select2-default"),this.search.width(c>0?c:this.container.css("width"))):this.search.val("").width(10)},clearPlaceholder:function(){this.search.hasClass("select2-default")&&this.search.val("").removeClass("select2-default")},opening:function(){this.clearPlaceholder(),this.resizeSearch(),this.parent.opening.apply(this,arguments),this.focusSearch(),this.updateResults(!0),this.search.focus(),this.opts.element.trigger(a.Event("select2-open"))},close:function(){this.opened()&&this.parent.close.apply(this,arguments)},focus:function(){this.close(),this.search.focus()},isFocused:function(){return this.search.hasClass("select2-focused")},updateSelection:function(b){var c=[],d=[],e=this;a(b).each(function(){o(e.id(this),c)<0&&(c.push(e.id(this)),d.push(this))}),b=d,this.selection.find(".select2-search-choice").remove(),a(b).each(function(){e.addSelectedChoice(this)}),e.postprocessResults()},tokenize:function(){var a=this.search.val();a=this.opts.tokenizer.call(this,a,this.data(),this.bind(this.onSelect),this.opts),null!=a&&a!=b&&(this.search.val(a),a.length>0&&this.open())},onSelect:function(a,b){this.triggerSelect(a)&&(this.addSelectedChoice(a),this.opts.element.trigger({type:"selected",val:this.id(a),choice:a}),(this.select||!this.opts.closeOnSelect)&&this.postprocessResults(a,!1,this.opts.closeOnSelect===!0),this.opts.closeOnSelect?(this.close(),this.search.width(10)):this.countSelectableResults()>0?(this.search.width(10),this.resizeSearch(),this.getMaximumSelectionSize()>0&&this.val().length>=this.getMaximumSelectionSize()&&this.updateResults(!0),this.positionDropdown()):(this.close(),this.search.width(10)),this.triggerChange({added:a}),b&&b.noFocus||this.focusSearch())},cancel:function(){this.close(),this.focusSearch()},addSelectedChoice:function(c){var j,k,d=!c.locked,e=a("<li class='select2-search-choice'> <div></div> <a href='#' onclick='return false;' class='select2-search-choice-close' tabindex='-1'></a></li>"),f=a("<li class='select2-search-choice select2-locked'><div></div></li>"),g=d?e:f,h=this.id(c),i=this.getVal();j=this.opts.formatSelection(c,g.find("div"),this.opts.escapeMarkup),j!=b&&g.find("div").replaceWith("<div>"+j+"</div>"),k=this.opts.formatSelectionCssClass(c,g.find("div")),k!=b&&g.addClass(k),d&&g.find(".select2-search-choice-close").on("mousedown",A).on("click dblclick",this.bind(function(b){this.isInterfaceEnabled()&&(a(b.target).closest(".select2-search-choice").fadeOut("fast",this.bind(function(){this.unselect(a(b.target)),this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus"),this.close(),this.focusSearch()})).dequeue(),A(b))})).on("focus",this.bind(function(){this.isInterfaceEnabled()&&(this.container.addClass("select2-container-active"),this.dropdown.addClass("select2-drop-active"))})),g.data("select2-data",c),g.insertBefore(this.searchContainer),i.push(h),this.setVal(i)},unselect:function(b){var d,e,c=this.getVal();if(b=b.closest(".select2-search-choice"),0===b.length)throw"Invalid argument: "+b+". Must be .select2-search-choice";if(d=b.data("select2-data")){for(;(e=o(this.id(d),c))>=0;)c.splice(e,1),this.setVal(c),this.select&&this.postprocessResults();var f=a.Event("select2-removing");f.val=this.id(d),f.choice=d,this.opts.element.trigger(f),f.isDefaultPrevented()||(b.remove(),this.opts.element.trigger({type:"select2-removed",val:this.id(d),choice:d}),this.triggerChange({removed:d}))}},postprocessResults:function(a,b,c){var d=this.getVal(),e=this.results.find(".select2-result"),f=this.results.find(".select2-result-with-children"),g=this;e.each2(function(a,b){var c=g.id(b.data("select2-data"));o(c,d)>=0&&(b.addClass("select2-selected"),b.find(".select2-result-selectable").addClass("select2-selected"))}),f.each2(function(a,b){b.is(".select2-result-selectable")||0!==b.find(".select2-result-selectable:not(.select2-selected)").length||b.addClass("select2-selected")}),-1==this.highlight()&&c!==!1&&g.highlight(0),!this.opts.createSearchChoice&&!e.filter(".select2-result:not(.select2-selected)").length>0&&(!a||a&&!a.more&&0===this.results.find(".select2-no-results").length)&&J(g.opts.formatNoMatches,"formatNoMatches")&&this.results.append("<li class='select2-no-results'>"+g.opts.formatNoMatches(g.search.val())+"</li>")},getMaxSearchWidth:function(){return this.selection.width()-s(this.search)},resizeSearch:function(){var a,b,c,d,e,f=s(this.search);a=C(this.search)+10,b=this.search.offset().left,c=this.selection.width(),d=this.selection.offset().left,e=c-(b-d)-f,a>e&&(e=c-f),40>e&&(e=c-f),0>=e&&(e=a),this.search.width(Math.floor(e))},getVal:function(){var a;return this.select?(a=this.select.val(),null===a?[]:a):(a=this.opts.element.val(),r(a,this.opts.separator))},setVal:function(b){var c;this.select?this.select.val(b):(c=[],a(b).each(function(){o(this,c)<0&&c.push(this)}),this.opts.element.val(0===c.length?"":c.join(this.opts.separator)))},buildChangeDetails:function(a,b){for(var b=b.slice(0),a=a.slice(0),c=0;c<b.length;c++)for(var d=0;d<a.length;d++)q(this.opts.id(b[c]),this.opts.id(a[d]))&&(b.splice(c,1),c>0&&c--,a.splice(d,1),d--);return{added:b,removed:a}},val:function(c,d){var e,f=this;if(0===arguments.length)return this.getVal();if(e=this.data(),e.length||(e=[]),!c&&0!==c)return this.opts.element.val(""),this.updateSelection([]),this.clearSearch(),d&&this.triggerChange({added:this.data(),removed:e}),void 0;if(this.setVal(c),this.select)this.opts.initSelection(this.select,this.bind(this.updateSelection)),d&&this.triggerChange(this.buildChangeDetails(e,this.data()));else{if(this.opts.initSelection===b)throw new Error("val() cannot be called if initSelection() is not defined");this.opts.initSelection(this.opts.element,function(b){var c=a.map(b,f.id);f.setVal(c),f.updateSelection(b),f.clearSearch(),d&&f.triggerChange(f.buildChangeDetails(e,f.data()))})}this.clearSearch()},onSortStart:function(){if(this.select)throw new Error("Sorting of elements is not supported when attached to <select>. Attach to <input type='hidden'/> instead.");this.search.width(0),this.searchContainer.hide()},onSortEnd:function(){var b=[],c=this;this.searchContainer.show(),this.searchContainer.appendTo(this.searchContainer.parent()),this.resizeSearch(),this.selection.find(".select2-search-choice").each(function(){b.push(c.opts.id(a(this).data("select2-data")))}),this.setVal(b),this.triggerChange()},data:function(b,c){var e,f,d=this;return 0===arguments.length?this.selection.find(".select2-search-choice").map(function(){return a(this).data("select2-data")}).get():(f=this.data(),b||(b=[]),e=a.map(b,function(a){return d.opts.id(a)}),this.setVal(e),this.updateSelection(b),this.clearSearch(),c&&this.triggerChange(this.buildChangeDetails(f,this.data())),void 0)}}),a.fn.select2=function(){var d,g,h,i,j,c=Array.prototype.slice.call(arguments,0),k=["val","destroy","opened","open","close","focus","isFocused","container","dropdown","onSortStart","onSortEnd","enable","disable","readonly","positionDropdown","data","search"],l=["opened","isFocused","container","dropdown"],m=["val","data"],n={search:"externalSearch"};return this.each(function(){if(0===c.length||"object"==typeof c[0])d=0===c.length?{}:a.extend({},c[0]),d.element=a(this),"select"===d.element.get(0).tagName.toLowerCase()?j=d.element.prop("multiple"):(j=d.multiple||!1,"tags"in d&&(d.multiple=j=!0)),g=j?new f:new e,g.init(d);else{if("string"!=typeof c[0])throw"Invalid arguments to select2 plugin: "+c;if(o(c[0],k)<0)throw"Unknown method: "+c[0];if(i=b,g=a(this).data("select2"),g===b)return;if(h=c[0],"container"===h?i=g.container:"dropdown"===h?i=g.dropdown:(n[h]&&(h=n[h]),i=g[h].apply(g,c.slice(1))),o(c[0],l)>=0||o(c[0],m)&&1==c.length)return!1}}),i===b?this:i},a.fn.select2.defaults={width:"copy",loadMorePadding:0,closeOnSelect:!0,openOnEnter:!0,containerCss:{},dropdownCss:{},containerCssClass:"",dropdownCssClass:"",formatResult:function(a,b,c,d){var e=[];return E(a.text,c.term,e,d),e.join("")},formatSelection:function(a,c,d){return a?d(a.text):b},sortResults:function(a){return a},formatResultCssClass:function(){return b},formatSelectionCssClass:function(){return b},formatNoMatches:function(){return"No matches found"},formatInputTooShort:function(a,b){var c=b-a.length;return"Please enter "+c+" more character"+(1==c?"":"s")},formatInputTooLong:function(a,b){var c=a.length-b;return"Please delete "+c+" character"+(1==c?"":"s")},formatSelectionTooBig:function(a){return"You can only select "+a+" item"+(1==a?"":"s")},formatLoadMore:function(){return"Loading more results..."},formatSearching:function(){return"Searching..."},minimumResultsForSearch:0,minimumInputLength:0,maximumInputLength:null,maximumSelectionSize:0,id:function(a){return a.id},matcher:function(a,b){return n(""+b).toUpperCase().indexOf(n(""+a).toUpperCase())>=0},separator:",",tokenSeparators:[],tokenizer:M,escapeMarkup:F,blurOnChange:!1,selectOnBlur:!1,adaptContainerCssClass:function(a){return a},adaptDropdownCssClass:function(){return null},nextSearchTerm:function(){return b}},a.fn.select2.ajaxDefaults={transport:a.ajax,params:{type:"GET",cache:!1,dataType:"json"}},window.Select2={query:{ajax:G,local:H,tags:I},util:{debounce:v,markMatch:E,escapeMarkup:F,stripDiacritics:n},"class":{"abstract":d,single:e,multi:f}}}}(jQuery);
\ No newline at end of file
Added: trunk/wao-web/src/main/webapp/js/select2-3.4.5/select2.png
===================================================================
(Binary files differ)
Property changes on: trunk/wao-web/src/main/webapp/js/select2-3.4.5/select2.png
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: trunk/wao-web/src/main/webapp/js/select2-3.4.5/select2_locale_fr.js
===================================================================
--- trunk/wao-web/src/main/webapp/js/select2-3.4.5/select2_locale_fr.js (rev 0)
+++ trunk/wao-web/src/main/webapp/js/select2-3.4.5/select2_locale_fr.js 2014-03-19 15:11:43 UTC (rev 1728)
@@ -0,0 +1,15 @@
+/**
+ * Select2 French translation
+ */
+(function ($) {
+ "use strict";
+
+ $.extend($.fn.select2.defaults, {
+ formatNoMatches: function () { return "Aucun résultat trouvé"; },
+ formatInputTooShort: function (input, min) { var n = min - input.length; return "Merci de saisir " + n + " caractère" + (n == 1? "" : "s") + " de plus"; },
+ formatInputTooLong: function (input, max) { var n = input.length - max; return "Merci de supprimer " + n + " caractère" + (n == 1? "" : "s"); },
+ formatSelectionTooBig: function (limit) { return "Vous pouvez seulement sélectionner " + limit + " élément" + (limit == 1 ? "" : "s"); },
+ formatLoadMore: function (pageNumber) { return "Chargement de résultats supplémentaires..."; },
+ formatSearching: function () { return "Recherche en cours..."; }
+ });
+})(jQuery);
Added: trunk/wao-web/src/main/webapp/js/select2-3.4.5/select2x2.png
===================================================================
(Binary files differ)
Property changes on: trunk/wao-web/src/main/webapp/js/select2-3.4.5/select2x2.png
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
1
0