Project

General

Profile

« Previous | Next » 

Revision 45235

codebase used to migrate to java8 the production system

View differences:

modules/dnet-modular-oai-explorer-ui/trunk/deploy.info
1
{"type_source": "SVN", "goal": "package -U -T 4C source:jar", "url": "http://svn-public.driver.research-infrastructures.eu/driver/dnet40/modules/dnet-modular-oai-explorer-ui/trunk/", "deploy_repository": "dnet4-snapshots", "version": "4", "mail": "sandro.labruzzo@isti.cnr.it,michele.artini@isti.cnr.it, claudio.atzori@isti.cnr.it, alessia.bardi@isti.cnr.it", "deploy_repository_url": "http://maven.research-infrastructures.eu/nexus/content/repositories/dnet4-snapshots", "name": "dnet-modular-oai-explorer-ui"}
modules/dnet-modular-oai-explorer-ui/trunk/src/main/java/eu/dnetlib/functionality/modular/ui/oai/OaiExplorerEntryPointController.java
1
package eu.dnetlib.functionality.modular.ui.oai;
2

  
3
import javax.servlet.http.HttpServletRequest;
4
import javax.servlet.http.HttpServletResponse;
5

  
6
import org.springframework.ui.ModelMap;
7

  
8
import eu.dnetlib.functionality.modular.ui.ModuleEntryPoint;
9

  
10
public class OaiExplorerEntryPointController extends ModuleEntryPoint {
11

  
12
	@Override
13
	protected void initialize(final ModelMap map, final HttpServletRequest request,
14
			final HttpServletResponse response) throws Exception {
15
		if (request.getParameterMap().containsKey("oaiBaseUrl")) {
16
			map.addAttribute("oaiBaseUrl", request.getParameter("oaiBaseUrl"));
17
		}
18
	}
19

  
20
}
modules/dnet-modular-oai-explorer-ui/trunk/src/main/java/eu/dnetlib/functionality/modular/ui/oai/objects/OaiRequest.java
1
package eu.dnetlib.functionality.modular.ui.oai.objects;
2

  
3
import java.util.List;
4

  
5
import org.apache.commons.httpclient.NameValuePair;
6

  
7
import com.google.common.collect.Lists;
8

  
9
public class OaiRequest {
10
	
11
	private String baseUrl; 
12
	private String verb;
13
	private String mdf;
14
	private String set;
15
	private String id;
16
	private String token;
17
	
18
	public String getBaseUrl() {
19
		return baseUrl;
20
	}
21
	
22
	public void setBaseUrl(String baseUrl) {
23
		this.baseUrl = baseUrl;
24
	}
25
	
26
	public String getVerb() {
27
		return verb;
28
	}
29
	
30
	public void setVerb(String verb) {
31
		this.verb = verb;
32
	}
33
	
34
	public String getMdf() {
35
		return mdf;
36
	}
37
	
38
	public void setMdf(String mdf) {
39
		this.mdf = mdf;
40
	}
41
	
42
	public String getSet() {
43
		return set;
44
	}
45
	
46
	public void setSet(String set) {
47
		this.set = set;
48
	}
49
	
50
	public String getId() {
51
		return id;
52
	}
53
	
54
	public void setId(String id) {
55
		this.id = id;
56
	}
57
	
58
	public String getToken() {
59
		return token;
60
	}
61
	
62
	public void setToken(String token) {
63
		this.token = token;
64
	}
65

  
66
	public NameValuePair[] toQueryParams() {
67
		final List<NameValuePair> params = Lists.newArrayList();
68
		
69
		if (verb != null && !verb.isEmpty()) {
70
			params.add(new NameValuePair("verb", verb));
71
		}
72
		if (mdf != null && !mdf.isEmpty()) {
73
			params.add(new NameValuePair("metadataPrefix", mdf));
74
		}
75
		if (set != null && !set.isEmpty()) {
76
			params.add(new NameValuePair("set", set));
77
		}
78
		if (id != null && !id.isEmpty()) {
79
			params.add(new NameValuePair("identifier", id));
80
		}
81
		if (token != null && !token.isEmpty()) {
82
			params.add(new NameValuePair("resumptionToken", token)); 
83
		}
84
		
85
		return params.toArray(new NameValuePair[params.size()]);
86
	}
87
}
modules/dnet-modular-oai-explorer-ui/trunk/src/main/java/eu/dnetlib/functionality/modular/ui/oai/objects/ResponseDetails.java
1
package eu.dnetlib.functionality.modular.ui.oai.objects;
2

  
3
public class ResponseDetails {
4
	private String verb;
5
	private long time;
6
	private int httpCode;
7
	private boolean valid;
8
	private String error;
9
	private int size;
10
	private int cursor;
11
	private int total;
12
	private OaiRequest nextCall;
13
		
14
	public String getVerb() {
15
		return verb;
16
	}
17
	public void setVerb(String verb) {
18
		this.verb = verb;
19
	}
20
	public long getTime() {
21
		return time;
22
	}
23
	public void setTime(long time) {
24
		this.time = time;
25
	}
26
	public int getHttpCode() {
27
		return httpCode;
28
	}
29
	public void setHttpCode(int httpCode) {
30
		this.httpCode = httpCode;
31
	}
32
	public boolean isValid() {
33
		return valid;
34
	}
35
	public void setValid(boolean valid) {
36
		this.valid = valid;
37
	}
38
	public String getError() {
39
		return error;
40
	}
41
	public void setError(String error) {
42
		this.error = error;
43
	}
44
	public int getTotal() {
45
		return total;
46
	}
47
	public void setTotal(int total) {
48
		this.total = total;
49
	}
50
	public OaiRequest getNextCall() {
51
		return nextCall;
52
	}
53
	public void setNextCall(OaiRequest nextCall) {
54
		this.nextCall = nextCall;
55
	}
56
	public int getCursor() {
57
		return cursor;
58
	}
59
	public void setCursor(int cursor) {
60
		this.cursor = cursor;
61
	}
62
	public int getSize() {
63
		return size;
64
	}
65
	public void setSize(int size) {
66
		this.size = size;
67
	}
68
	
69
}
modules/dnet-modular-oai-explorer-ui/trunk/src/main/java/eu/dnetlib/functionality/modular/ui/oai/OaiExplorerInternalController.java
1
package eu.dnetlib.functionality.modular.ui.oai;
2

  
3
import java.io.InputStream;
4
import java.io.StringWriter;
5

  
6
import javax.xml.transform.Transformer;
7
import javax.xml.transform.TransformerFactory;
8
import javax.xml.transform.stream.StreamResult;
9
import javax.xml.transform.stream.StreamSource;
10

  
11
import org.apache.commons.httpclient.HttpClient;
12
import org.apache.commons.httpclient.HttpStatus;
13
import org.apache.commons.httpclient.methods.GetMethod;
14
import org.apache.commons.lang.math.NumberUtils;
15
import org.apache.commons.logging.Log;
16
import org.apache.commons.logging.LogFactory;
17
import org.dom4j.Document;
18
import org.dom4j.Node;
19
import org.dom4j.io.SAXReader;
20
import org.springframework.core.io.ClassPathResource;
21
import org.springframework.core.io.Resource;
22
import org.springframework.stereotype.Controller;
23
import org.springframework.web.bind.annotation.RequestBody;
24
import org.springframework.web.bind.annotation.RequestMapping;
25
import org.springframework.web.bind.annotation.ResponseBody;
26

  
27
import eu.dnetlib.functionality.modular.ui.oai.objects.OaiRequest;
28
import eu.dnetlib.functionality.modular.ui.oai.objects.ResponseDetails;
29
import eu.dnetlib.miscutils.datetime.DateUtils;
30

  
31
@Controller
32
public class OaiExplorerInternalController {
33
	
34
	private final static Resource oaiXslt = new ClassPathResource("/eu/dnetlib/functionality/modular/ui/xslt/oai.xslt");
35
	
36
	private static final Log log = LogFactory.getLog(OaiExplorerInternalController.class);
37
	
38
	@RequestMapping("/ui/oai_verb")
39
	public @ResponseBody String oaiVerb(@RequestBody(required=true) OaiRequest req) throws Exception {
40
		return applyXslt(callOaiVerb(req));
41
	} 
42
		
43
	@RequestMapping("/ui/test_oai_verb")
44
	public @ResponseBody ResponseDetails testOaiVerb(@RequestBody final OaiRequest req) throws Exception {
45
		final ResponseDetails response = new ResponseDetails();
46
		
47
		final Document doc = callOaiVerb(req, response);
48
		
49
		if (response.isValid() && doc != null) {
50
			final OaiRequest nextCall = new OaiRequest();
51
			nextCall.setBaseUrl(req.getBaseUrl());
52
			
53
			if ("Identify".equals(req.getVerb())) {
54
				nextCall.setVerb("ListSets");
55
			} else if ("ListSets".equals(req.getVerb())) {
56
				nextCall.setVerb("ListMetadataFormats");
57
			} else if ("ListMetadataFormats".equals(req.getVerb())) {
58
				nextCall.setVerb("ListRecords");
59
				if (doc.selectSingleNode("//*[local-name()='metadataPrefix' and text()='oai_dc']") != null) {
60
					nextCall.setMdf("oai_dc");
61
				} else {
62
					nextCall.setMdf(doc.selectSingleNode("//*[local-name()='metadataPrefix']").getText());
63
				}
64
			} else if ("ListRecords".equals(req.getVerb())) {
65
				nextCall.setVerb("ListIdentifiers");
66
				nextCall.setMdf(req.getMdf());
67
			} else if ("ListIdentifiers".equals(req.getVerb())) {
68
				nextCall.setVerb("GetRecord");
69
				nextCall.setMdf(req.getMdf());
70
				nextCall.setId(doc.selectSingleNode("//*[local-name()='identifier']").getText());
71
			} else if ("GetRecord".equals(req.getVerb())) {
72
				// NOTHING
73
			}
74
			response.setNextCall(nextCall);
75
		}
76
		return response;
77
	}
78
	
79
	@RequestMapping("/ui/test_harvesting")
80
	public @ResponseBody ResponseDetails testHarvesting(@RequestBody final OaiRequest req) throws Exception {
81
		final ResponseDetails response = new ResponseDetails();
82
		
83
		final Document doc = callOaiVerb(req, response);
84
		
85
		if (response.isValid() && doc != null) {
86
			
87
			final Node node = doc.selectSingleNode("//*[local-name() = 'resumptionToken']");
88
			
89
			if (node != null) {
90
				response.setSize(doc.selectNodes("//*[local-name()='" + req.getVerb() + "']/*[local-name() != 'resumptionToken']").size());
91
				response.setCursor(NumberUtils.toInt(node.valueOf("@cursor"), -1));
92
				response.setTotal(NumberUtils.toInt(node.valueOf("@completeListSize"), -1));
93
				
94
				final OaiRequest nextCall = new OaiRequest();
95
				nextCall.setBaseUrl(req.getBaseUrl());
96
				nextCall.setVerb(req.getVerb());
97
				nextCall.setToken(node.getText());
98
				response.setNextCall(nextCall);
99
			}
100
		}
101
		return response;
102
	}
103
	
104
	private InputStream callOaiVerb(final OaiRequest req) throws Exception {
105
		final GetMethod method = new GetMethod(req.getBaseUrl());
106
		method.setRequestHeader("Content-type", "text/xml; charset=UTF-8");
107
		method.setQueryString(req.toQueryParams());
108
		
109
		int responseCode = (new HttpClient()).executeMethod(method);
110

  
111
		if (HttpStatus.SC_OK != responseCode) {
112
			log.error("Error downloading from baseUrl: " + req.getBaseUrl());
113
			throw new RuntimeException("Error: " + responseCode);
114
		}
115

  
116
		return method.getResponseBodyAsStream();
117

  
118
	}
119
	
120
	private Document callOaiVerb(final OaiRequest req, final ResponseDetails details) {
121
		final GetMethod method = new GetMethod(req.getBaseUrl());
122
		method.setRequestHeader("Content-type", "text/xml; charset=UTF-8");
123
		method.setQueryString(req.toQueryParams());
124
		
125
		Document doc = null;
126

  
127
		final long start = DateUtils.now();
128

  
129
		
130
		try {
131
			int responseCode = (new HttpClient()).executeMethod(method);
132
	
133
			details.setHttpCode(responseCode);
134
			details.setValid(HttpStatus.SC_OK == responseCode);
135
			
136
			if (HttpStatus.SC_OK == responseCode) {
137
				try {
138
					doc = new SAXReader().read(method.getResponseBodyAsStream());
139
				} catch (Exception e) {
140
					details.setValid(false);
141
					details.setError(e.getMessage());
142
				}
143
			}
144
		} catch (Exception e) {
145
			details.setValid(false);
146
			details.setError(e.getMessage());
147
		}
148
				
149
		details.setTime(DateUtils.now() - start);
150
		details.setVerb(req.getVerb());
151
		
152
		return doc;
153
	}
154
	
155
	
156
	private String applyXslt(final InputStream input) throws Exception {
157
		final TransformerFactory tfactory = TransformerFactory.newInstance();
158
		
159
		final Transformer transformer = tfactory.newTransformer(new StreamSource(oaiXslt.getInputStream()));
160
		final StringWriter output = new StringWriter();
161
		transformer.transform(new StreamSource(input), new StreamResult(output));
162
		
163
		return output.toString();
164
	}
165
}
modules/dnet-modular-oai-explorer-ui/trunk/src/main/resources/eu/dnetlib/functionality/modular/ui/oai/applicationContext-dnet-modular-oai-explorer-ui.xml
1
<?xml version="1.0" encoding="UTF-8"?>
2
<beans xmlns="http://www.springframework.org/schema/beans"
3
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
4
	xmlns:util="http://www.springframework.org/schema/util"
5
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
6
                        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
7

  
8
</beans>
modules/dnet-modular-oai-explorer-ui/trunk/src/main/resources/eu/dnetlib/functionality/modular/ui/oai/webContext-dnet-modular-oai-explorer-ui.xml
1
<beans xmlns="http://www.springframework.org/schema/beans"
2
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
3
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
4

  
5
	<bean name="/ui/oaiExplorer.do"
6
		class="eu.dnetlib.functionality.modular.ui.oai.OaiExplorerEntryPointController"
7
		p:menu="Oai explorer" p:title="Oai explorer"
8
		p:description="It is used to test the an OAI repository" p:group="DataSource Management"
9
		p:order="30"
10
		p:groupOrder="10">
11
		<property name="permissionLevels">
12
			<set>
13
				<value>DS_ADMIN</value>
14
			</set>
15
		</property>
16
	</bean>
17

  
18
</beans>
modules/dnet-modular-oai-explorer-ui/trunk/src/main/resources/eu/dnetlib/functionality/modular/ui/xslt/oai.xslt
1
<?xml version="1.0" encoding="utf-8"?>
2

  
3
<xsl:stylesheet version="1.0"
4
	xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:oai="http://www.openarchives.org/OAI/2.0/"
5
	xmlns:oai_dc="http://www.openarchives.org/OAI/2.0/oai_dc/"
6
	xmlns:dc="http://purl.org/dc/doc:elements/1.1/"
7
	exclude-result-prefixes="oai oai_dc dc">
8

  
9
	<xsl:output method="html" omit-xml-declaration="yes" encoding="UTF-8" standalone="no" />
10

  
11
	<xsl:template match="/">
12
		<xsl:apply-templates select="oai:OAI-PMH/oai:error" />
13
		<xsl:apply-templates select="oai:OAI-PMH/oai:Identify" />
14
		<xsl:apply-templates select="oai:OAI-PMH/oai:ListSets" />
15
		<xsl:apply-templates select="oai:OAI-PMH/oai:ListRecords" />
16
		<xsl:apply-templates select="oai:OAI-PMH/oai:ListIdentifiers" />
17
		<xsl:apply-templates select="oai:OAI-PMH/oai:ListMetadataFormats" />
18
		<xsl:apply-templates select="oai:OAI-PMH/oai:GetRecord" />
19
	</xsl:template>
20

  
21
	<xsl:template match="oai:OAI-PMH/oai:error">
22
		<div class="alert alert-danger">
23
			<h4>Error</h4>
24
			<p>
25
				<xsl:value-of select="text()"></xsl:value-of>
26
			</p>
27
		</div>
28
	</xsl:template>
29

  
30
	<xsl:template match="oai:OAI-PMH/oai:Identify">
31
		<xsl:call-template name="verbTitle">
32
			<xsl:with-param name="title" select="string('Repository Information')"/>
33
		</xsl:call-template>
34
	
35
		<table class="table table-striped table-bordered">
36
			<tr>
37
				<td>
38
					<b>Repository Name</b>
39
				</td>
40
				<td>
41
					<xsl:value-of select="oai:repositoryName/text()" />
42
				</td>
43
			</tr>
44
			<xsl:for-each select="oai:adminEmail">
45
				<tr>
46
					<td>
47
						<b>E-Mail Contact</b>
48
					</td>
49
					<td>
50
						<a href="{concat('mailto:', text())}">
51
							<xsl:value-of select="text()" />
52
						</a>
53
					</td>
54
				</tr>
55
			</xsl:for-each>
56
			<tr>
57
				<td>
58
					<b>Description</b>
59
				</td>
60
				<td>
61
					<xsl:value-of select="oai:description/node()/text()" />
62
				</td>
63

  
64
			</tr>
65
			<tr>
66
				<td>
67
					<b>Protocol Version</b>
68
				</td>
69
				<td>
70
					<xsl:value-of select="oai:protocolVersion/text()" />
71
				</td>
72

  
73
			</tr>
74
			<tr>
75
				<td>
76
					<b>Earliest Registered Date</b>
77
				</td>
78
				<td>
79
					<xsl:value-of select="translate(oai:earliestDatestamp/text(), 'TZ' ,' ')" />
80
				</td>
81

  
82
			</tr>
83
			<tr>
84
				<td>
85
					<b>Date Granularity</b>
86
				</td>
87
				<td>
88
					<xsl:value-of select="translate(oai:granularity/text(), 'TZ', ' ')" />
89
				</td>
90

  
91
			</tr>
92
			<tr>
93
				<td>
94
					<b>Deletion Mode</b>
95
				</td>
96
				<td>
97
					<xsl:value-of select="oai:deletedRecord/text()" />
98
				</td>
99

  
100
			</tr>
101
		</table>
102
	</xsl:template>
103

  
104
	<xsl:template match="oai:OAI-PMH/oai:ListSets">
105
		<xsl:call-template name="verbTitle">
106
			<xsl:with-param name="title" select="string('Available Sets')"/>
107
			<xsl:with-param name="countPath" select="oai:set" />
108
		</xsl:call-template>
109
	
110
		<div class="list-group">
111
			<xsl:for-each select="oai:set">
112
				<div class="list-group-item">
113
					<h5 class="list-group-item-heading">
114
						<xsl:choose>
115
							<xsl:when test="string-length(oai:setName/text()) &gt; 83">
116
								<xsl:value-of select="substring(oai:setName/text(),0, 80 )" />
117
								...
118
							</xsl:when>
119
							<xsl:otherwise>
120
								<xsl:value-of select="oai:setName/text()" />
121
							</xsl:otherwise>
122
						</xsl:choose>
123
						<small>
124
							[
125
							<xsl:value-of select="oai:setSpec/text()" />
126
							]
127
						</small>
128
					</h5>
129
					<div class="spec">
130
						<div class="btn-group">
131
							<button type="button" class="btn btn-default btn-sm" ng-click="listRecords('oai_dc', '{oai:setSpec/text()}')">Records</button>
132
							<button type="button" class="btn btn-default btn-sm" ng-click="listIdentifiers('oai_dc', '{oai:setSpec/text()}')">Identifiers</button>
133
						</div>
134
					</div>
135
				</div>
136
			</xsl:for-each>
137
		</div>
138

  
139
		<xsl:apply-templates select="oai:resumptionToken" />
140
	</xsl:template>
141

  
142
	<xsl:template match="oai:OAI-PMH/oai:ListRecords|oai:OAI-PMH/oai:GetRecord">
143
		
144
		<xsl:choose>
145
			<xsl:when test="local-name() = 'GetRecord'">
146
				<xsl:call-template name="verbTitle">
147
					<xsl:with-param name="title" select="string('Record Details')"/>
148
					<xsl:with-param name="countPath" select="oai:record" />
149
				</xsl:call-template>
150
			</xsl:when>
151
			<xsl:otherwise>
152
				<xsl:call-template name="verbTitle">
153
					<xsl:with-param name="title" select="string('List of Records')"/>
154
					<xsl:with-param name="countPath" select="oai:record" />
155
				</xsl:call-template>
156
			</xsl:otherwise>
157
		</xsl:choose>
158
		
159
		<xsl:apply-templates select="oai:resumptionToken" />
160
		
161
		<xsl:for-each select="oai:record">
162
			<div class="panel panel-default">
163
				<div class="panel-body">
164
					<table class="table">
165
						<tr>
166
							<th>Identifier</th>
167
							<td><xsl:value-of select="oai:header/oai:identifier/text()" /></td>
168
						</tr>
169
						<tr>
170
							<th>Last Modfied</th>
171
							<td><xsl:value-of select="translate(oai:header/oai:datestamp/text(), 'TZ', ' ')"></xsl:value-of></td>
172
						</tr>
173
						<tr>
174
							<th>Sets</th>
175
							<td>
176
								<xsl:for-each select="oai:header/oai:setSpec">
177
									<xsl:if test="position() &gt; 1">, </xsl:if>
178
									<a href="javascript:void(0)" ng-click="listRecords('oai_dc', '{text()}')">
179
										<xsl:value-of select="text()" />
180
									</a>
181
								</xsl:for-each>
182
							</td>
183
						</tr>
184
						<tr>
185
							<th>Record</th>
186
							<td>
187
								<xsl:choose>
188
									<xsl:when test="count(oai:metadata/*) &gt; 0">
189
										<xsl:for-each select="oai:metadata/*">
190
											<xsl:call-template name="showRecord" />
191
										</xsl:for-each>
192
									</xsl:when>
193
									<xsl:otherwise>
194
										<span class="label label-warning">Missing Metadata</span>										
195
									</xsl:otherwise>
196
								</xsl:choose>
197
							</td>
198
						</tr>
199
					</table>
200
					<!-- <button class="btn btn-default btn-sm pull-right" ng-click="getRecord('{oai:header/oai:identifier/text()}', 'oai_dc')">View Details</button> -->
201
				</div>
202
			</div>
203
		</xsl:for-each>
204

  
205
		<xsl:apply-templates select="oai:resumptionToken" />
206
	</xsl:template>
207

  
208

  
209
	<xsl:template name="showRecord">
210
		<xsl:param name="indent" select="string('')" />
211
		<xsl:value-of select="$indent" />
212
		<strong><xsl:value-of select="local-name()"/>:	</strong><xsl:value-of select="text()"/>
213
		<xsl:if test="count(@*) &gt; 0">
214
			[<xsl:for-each select="@*">
215
				<xsl:if test="position() &gt; 1">, </xsl:if>
216
				<xsl:value-of select="local-name()" />: <xsl:value-of select="." />
217
			</xsl:for-each>]
218
		</xsl:if>
219
		<br />
220
		<xsl:for-each select="*">
221
			<xsl:call-template name="showRecord">
222
				<xsl:with-param name="indent" select="concat('&#160;&#160;&#160;&#160;', $indent)" />
223
			</xsl:call-template>
224
		</xsl:for-each>
225
	</xsl:template>
226

  
227
	<xsl:template match="oai:OAI-PMH/oai:ListIdentifiers">
228
		<xsl:call-template name="verbTitle">
229
			<xsl:with-param name="title" select="string('List of Identifiers')"/>
230
			<xsl:with-param name="countPath" select="oai:header" />
231
		</xsl:call-template>
232

  
233
		<xsl:apply-templates select="oai:resumptionToken" />
234
		
235
		<xsl:for-each select="oai:header">
236
			<div class="panel panel-default">
237
				<div class="panel-body">
238
					<table class="table">
239
						<tr>
240
							<th>Identifier</th>
241
							<td><xsl:value-of select="oai:identifier/text()" /></td>
242
						</tr>
243
						<tr>
244
							<th>Last Modfied</th>
245
							<td><xsl:value-of select="translate(oai:datestamp/text(), 'TZ', ' ')"></xsl:value-of></td>
246
						</tr>
247
						<tr>
248
							<th>Sets</th>
249
							<td>
250
								<xsl:for-each select="oai:setSpec">
251
									<xsl:if test="position() &gt; 1">, </xsl:if>
252
									<a href="javascript:void(0)" ng-click="listRecords('oai_dc', '{text()}')">
253
										<xsl:value-of select="text()" />
254
									</a>
255
								</xsl:for-each>
256
							</td>
257
						</tr>
258
					</table>
259
					<button class="btn btn-default btn-sm pull-right" ng-click="getRecord('{oai:identifier/text()}', 'oai_dc')">View Details</button>
260
				</div>
261
			</div>
262
		</xsl:for-each>
263

  
264
		<xsl:apply-templates select="oai:resumptionToken" />
265
	</xsl:template>
266

  
267
	<xsl:template match="oai:OAI-PMH/oai:ListMetadataFormats">
268
		<xsl:call-template name="verbTitle">
269
			<xsl:with-param name="title" select="string('List of Metadata Formats')"/>
270
			<xsl:with-param name="countPath" select="oai:metadataFormat" />
271
		</xsl:call-template>
272
		
273
		<xsl:for-each select="oai:metadataFormat">
274
			<div class="panel panel-default">
275
				<div class="panel-heading">
276
					<div class="row">
277
						<div class="col-lg-9">
278
							<h5>
279
								<xsl:value-of select="oai:metadataPrefix/text()"></xsl:value-of>
280
							</h5>
281
						</div>
282
						<div class="col-lg-3">
283
							<button class="btn btn-default btn-sm pull-right" ng-click="listRecords('{oai:metadataPrefix/text()}', null)">
284
								List Records
285
							</button>
286
						</div>
287
					</div>
288
				</div>
289
				<div class="panel-body">
290
					<div class="row">
291
						<div class="col-lg-9">
292
							<h5>
293
								<strong>Namespace: </strong><xsl:value-of select="oai:metadataNamespace/text()" />
294
							</h5>
295
							<h5>
296
								<strong>Schema: </strong><xsl:value-of select="oai:schema/text()"/>
297
							</h5>
298
						</div>
299
					</div>
300
				</div>
301
			</div>
302
		</xsl:for-each>
303
	</xsl:template>
304

  
305
	<xsl:template match="oai:resumptionToken">
306
		<xsl:if test="text() != ''">
307
			<div class="text-center">
308
				<button class="btn btn-primary btn-sm" ng-click="nextPage('{text()}')">Show More</button>
309
			</div>
310
			<br />
311
		</xsl:if>
312
	</xsl:template>
313

  
314
	<xsl:template name="result-count">
315
		<xsl:param name="path" />
316
		<xsl:variable name="cursor" select="$path/../oai:resumptionToken/@cursor" />
317
		<xsl:variable name="total" select="$path/../oai:resumptionToken/@completeListSize" />
318
		<xsl:variable name="count" select="count($path)" />
319
		<xsl:choose>
320
			<xsl:when test="$cursor">
321
				<xsl:choose>
322
					<xsl:when test="normalize-space($path/../oai:resumptionToken/text()) = ''">
323
						<xsl:value-of select="$total - $count" />
324
						-
325
						<xsl:value-of select="$total" />
326
					</xsl:when>
327
					<xsl:otherwise>
328
						<xsl:value-of select="$cursor+1" />
329
						-
330
						<xsl:value-of select="$cursor + $count" />
331
					</xsl:otherwise>
332
				</xsl:choose>
333
			</xsl:when>
334
			<xsl:otherwise>
335
				<xsl:value-of select="$count" />
336
			</xsl:otherwise>
337
		</xsl:choose>
338
		<xsl:if test="$total">
339
			of
340
			<xsl:value-of select="$total" />
341
		</xsl:if>
342
	</xsl:template>
343

  
344
	<xsl:template name="verbTitle">
345
		<xsl:param name="title" />
346
		<xsl:param name="count" select="string('')"/>
347
		<xsl:param name="countPath" select="string('')"/>
348
		
349
		<h2><xsl:value-of select="$title"></xsl:value-of></h2>
350
		<h5><strong>Response Date: </strong><xsl:value-of select="translate(/oai:OAI-PMH/oai:responseDate/text(), 'TZ', ' ')" /></h5>
351
		<xsl:if test="$count">
352
			<h5><strong>Number of results: </strong><xsl:value-of select="$count" /></h5>
353
		</xsl:if>	
354
		<xsl:if test="$countPath">
355
			<h5>
356
				<strong>Number of entries: </strong>
357
				<xsl:call-template name="result-count">
358
					<xsl:with-param name="path" select="$countPath" />
359
				</xsl:call-template>
360
			</h5>
361
		</xsl:if>	
362
		<br />	
363
	</xsl:template>
364

  
365
</xsl:stylesheet>
modules/dnet-modular-oai-explorer-ui/trunk/src/main/resources/eu/dnetlib/functionality/modular/ui/views/ui/oaiExplorer.st
1
$common/master( header={
2
	<script type="text/javascript" src="../resources/js/angular.min.js" ></script>
3
	<script type="text/javascript" src="../resources/js/ng-grid-2.0.7.min.js"></script>
4
	<script type="text/javascript" src="../resources/js/dnet_oai_explorer.js"></script>
5
	<script type="text/javascript" src="../resources/js/jquery.flot.js"></script>
6
	
7
	<link rel="stylesheet" type="text/css" href="../resources/css/ng-grid.min.css" />
8
	<script type="text/javascript">
9
		function getInitialBaseUrl() {
10
			return $if(oaiBaseUrl)$'$oaiBaseUrl$'$else$''$endif$;
11
		}
12
	</script>
13
}, body={
14
	<div ng-app="oaiExplorerUI" ng-controller="oaiExplorerCtrl">
15
		<div class="row">
16
			<div class="form-inline col-xs-12 col-md-6">
17
				<form role="form">
18
					<div class="form-group has-feedback" ng-class="{ 'has-error' : !isValidUrl(tmpBaseUrl), 'has-success' : isValidUrl(tmpBaseUrl) }">
19
						<label for="inputBaseUrl" class="control-label">Base URL</label>
20
   						<input type="text" style="width: 400px" class="form-control" id="inputBaseUrl" placeholder="Enter base url" ng-model="tmpBaseUrl" />
21
						<span class="glyphicon form-control-feedback" ng-class="{ 'glyphicon-warning-sign' : !isValidUrl(tmpBaseUrl),  'glyphicon-ok' : isValidUrl(tmpBaseUrl) }"></span>
22
					</div>
23
					<button type="button" class="btn btn-primary" ng-click="verifyBaseUrl(tmpBaseUrl)" ng-disabled="!isValidUrl(tmpBaseUrl)">update</button>
24
				</form>
25
			</div>
26
			<div class="col-xs-12 col-md-6">
27
				<div class="well well-sm pull-right" style="top: 4px"><a href="{{oaiUrl}}" target="_blank">{{oaiUrl}}</a></div>
28
			</div>
29
		</div>
30
		<div class="row" ng-show="baseUrl.length > 0">
31
			<div class="col-xs-12 col-sm-12 col-md-4 col-lg-3">
32
				<div class="panel panel-default">
33
					<div class="panel-heading">Oai verbs</div>
34
					<div class="panel-body">
35
						<ul class="nav nav-pills nav-stacked">
36
							<li ng-class="{'active' : currentAction == 'Identify' }"><a href="javascript:void(0)" ng-click="identify()">Identify</a></li>
37
							<li ng-class="{'active' : currentAction == 'ListMetadataFormats' }"><a href="javascript:void(0)" ng-click="listMetadataFormats()">ListMetadataFormats</a></li>
38
							<li ng-class="{'active' : currentAction == 'ListSets' }"><a href="javascript:void(0)" ng-click="listSets()">ListSets</a></li>
39
							<li ng-class="{'active' : currentAction == 'ListRecords' }"><a href="javascript:void(0)" ng-click="listRecords('oai_dc')">ListRecords</a></li>
40
							<li ng-class="{'active' : currentAction == 'ListIdentifiers' }"><a href="javascript:void(0)" ng-click="listIdentifiers('oai_dc')">ListIdentifiers</a></li>
41
							<li ng-class="{'active' : currentAction == 'GetRecord' }"><a href="javascript:void(0)" ng-click="getRecord()">GetRecord</a></li>
42
						</ul>
43
					</div>
44
				</div>
45
				
46
				<div class="panel panel-default">
47
					<div class="panel-heading">Oai Tests</div>
48
					<div class="panel-body">
49
						<ul class="nav nav-pills nav-stacked">
50
							<li ng-class="{'active' : currentAction == 'testAllVerbs' }"><a href="javascript:void(0)" ng-click="testAllVerbs()">Test all verbs</a></li>
51
							<li ng-class="{'active' : currentAction == 'testHarvesting' }"><a href="javascript:void(0)" ng-click="testHarvesting()">Test harvesting</a></li>
52
						</ul>
53
					</div>
54
				</div>
55
			</div>
56
			<div class="col-xs-12 col-sm-12 col-md-8 col-lg-9">
57
				<div class="well">
58
					<div ng-show="oaiDataHTML" ng-bind-html="oaiDataHTML" compile-template></div>
59
					<div ng-show="currentAction == 'testAllVerbs'">
60
						<h2>Test of all OAI verbs</h2>
61
						<table class="table">
62
							<thead>
63
								<tr>
64
									<th>verb</th>
65
									<th class="text-center col-xs-2">http code</th>
66
									<th class="text-center col-xs-2">is valid</th>
67
									<th class="text-right col-xs-2">time</th>
68
								</tr>
69
							</thead>
70
							<tbody>
71
								<tr ng-repeat="r in testAllVerbsData" ng-class="{'success' : r.valid, 'danger' : !r.valid}">
72
									<th>{{r.verb}}</th>
73
									<td class="text-center">{{r.httpCode}}</td>
74
									<td class="text-center">
75
										<span ng-show="r.valid" class="glyphicon glyphicon-ok" title="Good"></span>
76
										<span ng-hide="r.valid" class="glyphicon glyphicon-warning-sign" title="{{r.error}}"></span>
77
									</td>
78
									<td class="text-right">{{r.time / 1000}} sec.</td>
79
								</tr>
80
							</tbody>						
81
						</table>
82
						<p ng-show="continueIteration">Running...</p>
83
						<p ng-hide="continueIteration">Completed !</p>
84
					</div>
85
					<div ng-show="currentAction == 'testHarvesting'">
86
						<h2>Test Harvesting</h2>
87
						<p>
88
							<form class="form-inline">
89
								<button ng-hide="continueIteration" class="btn btn-primary btn-sm" ng-click="startTestHarvesting()">start harvesting</button>
90
								<button ng-show="continueIteration" class="btn btn-primary btn-sm" ng-click="stopTestHarvesting()">stop harvesting</button>
91
								<button ng-hide="continueIteration || testHarvestingData.length == 0" class="btn btn-primary btn-sm" ng-click="updateGraph(testHarvestingData, 'time')" data-toggle="modal" data-target="#harvestingGraphModal">show time graph</button>
92
								<span ng-show="continueIteration">still running...</span>
93
							</form>
94
						</p>
95
						<div style="height: 400px; overflow-y:scroll">
96
							<table class="table" ng-show="testHarvestingData.length > 0">
97
								<thead>
98
									<tr>
99
										<th></th>
100
										<th class="text-right col-xs-1">size</th>
101
										<th class="text-right col-xs-1">cursor</th>
102
										<th class="text-right col-xs-1">total</th>
103
										<th class="text-center col-xs-1">http code</th>
104
										<th class="text-center col-xs-1">is valid</th>
105
										<th class="text-right col-xs-1">time</th>
106
									</tr>
107
								</thead>
108
								<tbody>
109
									<tr ng-repeat="r in testHarvestingData" ng-class="{'success' : r.valid, 'danger' : !r.valid}">
110
										<th>{{r.verb}} - call {{\$index + 1}}</th>
111
										<td class="text-right">{{r.size   >= 0 ? r.size : '-'}}</td>
112
										<td class="text-right">{{r.cursor >= 0 ? r.cursor : '-'}}</td>
113
										<td class="text-right">{{r.total  >= 0 ? r.total : '-'}}</td>
114
										<td class="text-center">{{r.httpCode}}</td>
115
										<td class="text-center">
116
											<span ng-show="r.valid" class="glyphicon glyphicon-ok" title="Good"></span>
117
											<span ng-hide="r.valid" class="glyphicon glyphicon-warning-sign" title="{{r.error}}"></span>
118
										</td>
119
										<td class="text-right">{{r.time / 1000}} sec.</td>
120
									</tr>
121
								</tbody>						
122
							</table>
123
							
124
							
125
							<br />
126
							<div id="endPage"></div>
127
						</div>
128
						<table class="table table condensed">
129
							<tr>
130
								<th class="col-xs-1">Min</th>
131
								<td class="col-xs-1">{{time_min.toFixed(3)}} sec.</td>
132
								<th class="col-xs-1">Max</th>
133
								<td class="col-xs-1">{{time_max.toFixed(3)}} sec.</td>
134
								<th class="col-xs-1">Avg</th>
135
								<td class="col-xs-1">{{time_avg.toFixed(3)}} sec.</td>
136
								<th class="col-xs-1">Std Dev</th>
137
								<td class="col-xs-1">{{time_stddev.toFixed(3)}} sec.</td>
138
							</tr>
139
						</table>
140
					</div>
141
				</div>
142
			</div>
143
		</div>
144
		
145
		<div class="modal fade" id="harvestingGraphModal" tabindex="-1" role="dialog">
146
			<div class="modal-dialog modal-lg">
147
				<div class="modal-content">
148
					<div class="modal-header">
149
						<button type="button" class="close" data-dismiss="modal">&times;</button>
150
						<h4 class="modal-title">Harvesting Graph</h4>
151
					</div>
152
					<div class="modal-body">
153
						<div class="row">
154
							<div id="harvestingGraph" class="col-xs-12" style="height: 400px; width: 800px"></div>	
155
						</div>
156
					</div>
157
					<div class="modal-footer">
158
						<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
159
					</div>
160
				</div>
161
			</div>
162
		</div>
163

  
164

  
165
	</div>
166
} )$
modules/dnet-modular-oai-explorer-ui/trunk/src/main/resources/eu/dnetlib/web/resources/js/dnet_oai_explorer.js
1
var module = angular.module('oaiExplorerUI', ['ngGrid']);
2

  
3

  
4
module.directive('compileTemplate', function($compile, $parse){
5
	return {
6
		link: function(scope, element, attr){
7
			var parsed = $parse(attr.ngBindHtml);
8
            
9
			function getStringValue() { return (parsed(scope) || '').toString(); }
10

  
11
			//Recompile if the template changes
12
			scope.$watch(getStringValue, function() {
13
                $compile(element, null, -9999)(scope);  //The -9999 makes it skip directives so that we do not recompile ourselves
14
			});
15
		}         
16
	}
17
});
18

  
19
function oaiExplorerCtrl($scope, $http, $sce) {
20
	$scope.tmpBaseUrl = getInitialBaseUrl();
21
	$scope.baseUrl = "";
22
	$scope.currentAction = "";
23
	$scope.oaiUrl = "";
24
	$scope.testAllVerbsData = [];
25
	$scope.testHarvestingData = [];
26
	$scope.continueIteration = false;
27
	
28
	$scope.identifyData = "";
29
	
30
	$scope.isValidUrl = function(url) {
31
		return (/^http/).test(url);
32
	}
33
		
34
	$scope.verifyBaseUrl = function(url) {
35
		$scope.baseUrl = "";
36
		$scope.currentAction = "";
37
		if ($scope.isValidUrl(url)) {
38
			$scope.baseUrl = url;
39
			$scope.identify();
40
		}
41
	}
42
	
43
	initSpinner();
44
	$scope.showError        = function(error)   { show_notification("error", error); }
45
	$scope.showNotification = function(message) { show_notification("info", message); }
46
	$scope.showSpinner      = function()        { showSpinner(); }
47
	$scope.hideSpinner      = function()        { hideSpinner(); }
48

  
49
	
50
	$scope.identify = function() {
51
		$scope.oaiUrl = $scope.baseUrl + "?verb=Identify";
52
		
53
		$scope.callRemoteMethod('Identify', {
54
			'baseUrl' : $scope.baseUrl,
55
			'verb'    : 'Identify' 
56
        });
57
	}
58
	
59
	$scope.listMetadataFormats = function() {
60
		$scope.oaiUrl = $scope.baseUrl + "?verb=ListMetadataFormats";
61
		
62
		$scope.callRemoteMethod('ListMetadataFormats', {
63
			'baseUrl' : $scope.baseUrl,
64
			'verb'    : 'ListMetadataFormats' 
65
        });
66
	}
67
	
68
	$scope.listSets = function() {
69
		$scope.oaiUrl = $scope.baseUrl + "?verb=ListSets";
70
		
71
		$scope.callRemoteMethod('ListSets', {
72
			'baseUrl' : $scope.baseUrl,
73
			'verb'    : 'ListSets'
74
        });
75
	}
76

  
77
	$scope.listRecords = function(mdf, set) {
78
		$scope.oaiUrl = $scope.baseUrl + "?verb=ListRecords&metadataPrefix=" + mdf;
79
		if (set) {
80
			$scope.oaiUrl += "&set=" + set; 
81
		}
82
		
83
		$scope.callRemoteMethod('ListRecords', {
84
			'baseUrl' : $scope.baseUrl,
85
			'verb'    : 'ListRecords',
86
			'mdf'     : mdf,
87
			'set'     : set
88
        });
89
	}
90

  
91
	$scope.listIdentifiers = function(mdf, set) {
92
		$scope.oaiUrl = $scope.baseUrl + "?verb=ListIdentifier&metadataPrefix=" + mdf;
93
		if (set) {
94
			$scope.oaiUrl += "&set=" + set; 
95
		}
96
		
97
		$scope.callRemoteMethod('ListIdentifiers', {
98
			'baseUrl' : $scope.baseUrl,
99
			'verb'    : 'ListIdentifiers',
100
			'mdf'     : mdf,
101
			'set'     : set
102
        });
103
	}
104

  
105
	$scope.getRecord = function(id, mdf) {
106
		$scope.currentAction = "GetRecord";
107
		$scope.oaiUrl = $scope.baseUrl + "?verb=GetRecord&metadataPrefix=" + mdf + "&identifier=" + id;
108
		$scope.callRemoteMethod('GetRecord', {
109
			'baseUrl' : $scope.baseUrl,
110
			'verb'    : 'GetRecord',
111
			'mdf'     : mdf,
112
			'id'      : id
113
        });
114
	}
115
	
116
	$scope.nextPage = function(token) {
117
		$scope.oaiUrl = $scope.baseUrl + "?verb=" + $scope.currentAction + "&resumptionToken=" + token;
118
		$scope.callRemoteMethod($scope.currentAction, {
119
			'baseUrl': $scope.baseUrl,
120
			'verb': $scope.currentAction,
121
			'token' : token
122
        });
123
	}
124

  
125
	
126
	$scope.testAllVerbs = function() {
127
		$scope.currentAction = "testAllVerbs";
128
		$scope.oaiDataHTML = "";
129
		$scope.oaiUrl = $scope.baseUrl + "?verb=Identify";
130
		$scope.testAllVerbsData = [];
131
		$scope.testHarvestingData = [];
132
		$scope.continueIteration = true;		
133
		
134
		$scope.time_min = 9999999;
135
		$scope.time_max = 0;
136
		$scope.time_total = 0;
137
		$scope.time_sqrTotal = 0;
138
		$scope.time_avg = 0;
139
		$scope.time_stddev = 0;
140
		
141
		$scope.testVerb($scope.testAllVerbsData, "test_oai_verb", {
142
			'baseUrl' : $scope.baseUrl,
143
			'verb'    : 'Identify',
144
        });
145
	}
146
	
147
	$scope.testHarvesting = function() {
148
		$scope.currentAction = "testHarvesting";
149
		$scope.oaiUrl = $scope.baseUrl + "?verb=ListRecords&metadataPrefix=oai_dc";
150
		$scope.oaiDataHTML = "";
151
		$scope.testAllVerbsData = [];
152
		$scope.testHarvestingData = [];
153
		$scope.continueIteration = false;
154
		
155
		$scope.time_min = 9999999;
156
		$scope.time_max = 0;
157
		$scope.time_total = 0;
158
		$scope.time_sqrTotal = 0;
159
		$scope.time_avg = 0;
160
		$scope.time_stddev = 0;
161
	}
162

  
163
	$scope.startTestHarvesting = function() {
164
		$scope.continueIteration = true;
165
		$scope.time_min = 9999999;
166
		$scope.time_max = 0;
167
		$scope.time_total = 0;
168
		$scope.time_sqrTotal = 0;
169
		$scope.time_avg = 0;
170
		$scope.time_stddev = 0;
171
		
172
		$scope.testHarvestingData = [];
173
		$scope.testVerb($scope.testHarvestingData, "test_harvesting", {
174
			'baseUrl' : $scope.baseUrl,
175
			'verb'    : 'ListRecords',
176
			'mdf'     : 'oai_dc'
177
        });
178
	}
179
	
180
	$scope.stopTestHarvesting = function() {
181
		$scope.continueIteration = false;
182
	}
183
	
184
	$scope.testVerb = function(list, method, params) {
185
		//$scope.showSpinner();
186
		$http.post(method, params).success(function(data) {
187
        	list.push(data);
188
        	
189
        	if (data.time) {
190
        		var curr = data.time / 1000;
191

  
192
        		$scope.time_min = Math.min($scope.time_min, curr);
193
        		$scope.time_max = Math.max($scope.time_max, curr);
194
        		$scope.time_total += curr;
195
        		$scope.time_sqrTotal += curr*curr;
196
        		$scope.time_avg = ($scope.time_total/list.length);
197
        		$scope.time_stddev = Math.sqrt((list.length * $scope.time_sqrTotal) - ($scope.time_total * $scope.time_total)) / list.length;
198
        	}
199
        	
200
        	location.href="#endPage";
201
        	//$scope.hideSpinner();
202
        	if ($scope.continueIteration && data.nextCall && data.nextCall.verb) {
203
        		$scope.testVerb(list, method, data.nextCall);
204
        	} else {
205
        		$scope.continueIteration = false;
206
        	}
207
        }).error(
208
            function() {
209
            	$scope.showError('Something really bad must have happened to our fellow hamster..');
210
            	//$scope.hideSpinner();
211
            }
212
        );
213
	}
214
		
215
	$scope.callRemoteMethod = function(name, params) {
216
		$scope.currentAction = name;
217
		$scope.oaiDataHTML = "";
218
		$scope.testAllVerbsData = [];
219
		$scope.testHarvestingData = [];
220
		
221
		$scope.showSpinner();
222

  
223
		$http.post('oai_verb', params).success(function(data) {
224
        	$scope.oaiDataHTML = $sce.trustAsHtml(data);
225
        	$scope.hideSpinner();
226
        }).error(
227
            function() {
228
            	$scope.showError('Something really bad must have happened to our fellow hamster..');
229
            	$scope.hideSpinner();
230
            }
231
        );
232
	}
233
	
234
	$scope.updateGraph = function(list, field) {
235
		var i = 1;
236
		var d = [];
237
		angular.forEach(list, function(obj) {
238
			if (obj[field]) {
239
				d[i] = [i, obj[field]];
240
			}
241
			i++;
242
		});
243
		jQuery.plot("#harvestingGraph", [ d ]);
244
	}
245
	
246
	
247
	if ($scope.tmpBaseUrl && $scope.isValidUrl($scope.tmpBaseUrl)) {
248
		$scope.verifyBaseUrl($scope.tmpBaseUrl);
249
	}
250

  
251
}
modules/dnet-modular-oai-explorer-ui/trunk/src/main/resources/eu/dnetlib/web/resources/js/jquery.flot.js
1
/* Javascript plotting library for jQuery, version 0.8.3.
2

  
3
Copyright (c) 2007-2014 IOLA and Ole Laursen.
4
Licensed under the MIT license.
5

  
6
*/
7

  
8
// first an inline dependency, jquery.colorhelpers.js, we inline it here
9
// for convenience
10

  
11
/* Plugin for jQuery for working with colors.
12
 *
13
 * Version 1.1.
14
 *
15
 * Inspiration from jQuery color animation plugin by John Resig.
16
 *
17
 * Released under the MIT license by Ole Laursen, October 2009.
18
 *
19
 * Examples:
20
 *
21
 *   $.color.parse("#fff").scale('rgb', 0.25).add('a', -0.5).toString()
22
 *   var c = $.color.extract($("#mydiv"), 'background-color');
23
 *   console.log(c.r, c.g, c.b, c.a);
24
 *   $.color.make(100, 50, 25, 0.4).toString() // returns "rgba(100,50,25,0.4)"
25
 *
26
 * Note that .scale() and .add() return the same modified object
27
 * instead of making a new one.
28
 *
29
 * V. 1.1: Fix error handling so e.g. parsing an empty string does
30
 * produce a color rather than just crashing.
31
 */
32
(function($){$.color={};$.color.make=function(r,g,b,a){var o={};o.r=r||0;o.g=g||0;o.b=b||0;o.a=a!=null?a:1;o.add=function(c,d){for(var i=0;i<c.length;++i)o[c.charAt(i)]+=d;return o.normalize()};o.scale=function(c,f){for(var i=0;i<c.length;++i)o[c.charAt(i)]*=f;return o.normalize()};o.toString=function(){if(o.a>=1){return"rgb("+[o.r,o.g,o.b].join(",")+")"}else{return"rgba("+[o.r,o.g,o.b,o.a].join(",")+")"}};o.normalize=function(){function clamp(min,value,max){return value<min?min:value>max?max:value}o.r=clamp(0,parseInt(o.r),255);o.g=clamp(0,parseInt(o.g),255);o.b=clamp(0,parseInt(o.b),255);o.a=clamp(0,o.a,1);return o};o.clone=function(){return $.color.make(o.r,o.b,o.g,o.a)};return o.normalize()};$.color.extract=function(elem,css){var c;do{c=elem.css(css).toLowerCase();if(c!=""&&c!="transparent")break;elem=elem.parent()}while(elem.length&&!$.nodeName(elem.get(0),"body"));if(c=="rgba(0, 0, 0, 0)")c="transparent";return $.color.parse(c)};$.color.parse=function(str){var res,m=$.color.make;if(res=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(str))return m(parseInt(res[1],10),parseInt(res[2],10),parseInt(res[3],10));if(res=/rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str))return m(parseInt(res[1],10),parseInt(res[2],10),parseInt(res[3],10),parseFloat(res[4]));if(res=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(str))return m(parseFloat(res[1])*2.55,parseFloat(res[2])*2.55,parseFloat(res[3])*2.55);if(res=/rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str))return m(parseFloat(res[1])*2.55,parseFloat(res[2])*2.55,parseFloat(res[3])*2.55,parseFloat(res[4]));if(res=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(str))return m(parseInt(res[1],16),parseInt(res[2],16),parseInt(res[3],16));if(res=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(str))return m(parseInt(res[1]+res[1],16),parseInt(res[2]+res[2],16),parseInt(res[3]+res[3],16));var name=$.trim(str).toLowerCase();if(name=="transparent")return m(255,255,255,0);else{res=lookupColors[name]||[0,0,0];return m(res[0],res[1],res[2])}};var lookupColors={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]}})(jQuery);
33

  
34
// the actual Flot code
35
(function($) {
36

  
37
	// Cache the prototype hasOwnProperty for faster access
38

  
39
	var hasOwnProperty = Object.prototype.hasOwnProperty;
40

  
41
    // A shim to provide 'detach' to jQuery versions prior to 1.4.  Using a DOM
42
    // operation produces the same effect as detach, i.e. removing the element
43
    // without touching its jQuery data.
44

  
45
    // Do not merge this into Flot 0.9, since it requires jQuery 1.4.4+.
46

  
47
    if (!$.fn.detach) {
48
        $.fn.detach = function() {
49
            return this.each(function() {
50
                if (this.parentNode) {
51
                    this.parentNode.removeChild( this );
52
                }
53
            });
54
        };
55
    }
56

  
57
	///////////////////////////////////////////////////////////////////////////
58
	// The Canvas object is a wrapper around an HTML5 <canvas> tag.
59
	//
60
	// @constructor
61
	// @param {string} cls List of classes to apply to the canvas.
62
	// @param {element} container Element onto which to append the canvas.
63
	//
64
	// Requiring a container is a little iffy, but unfortunately canvas
65
	// operations don't work unless the canvas is attached to the DOM.
66

  
67
	function Canvas(cls, container) {
68

  
69
		var element = container.children("." + cls)[0];
70

  
71
		if (element == null) {
72

  
73
			element = document.createElement("canvas");
74
			element.className = cls;
75

  
76
			$(element).css({ direction: "ltr", position: "absolute", left: 0, top: 0 })
77
				.appendTo(container);
78

  
79
			// If HTML5 Canvas isn't available, fall back to [Ex|Flash]canvas
80

  
81
			if (!element.getContext) {
82
				if (window.G_vmlCanvasManager) {
83
					element = window.G_vmlCanvasManager.initElement(element);
84
				} else {
85
					throw new Error("Canvas is not available. If you're using IE with a fall-back such as Excanvas, then there's either a mistake in your conditional include, or the page has no DOCTYPE and is rendering in Quirks Mode.");
86
				}
87
			}
88
		}
89

  
90
		this.element = element;
91

  
92
		var context = this.context = element.getContext("2d");
93

  
94
		// Determine the screen's ratio of physical to device-independent
95
		// pixels.  This is the ratio between the canvas width that the browser
96
		// advertises and the number of pixels actually present in that space.
97

  
98
		// The iPhone 4, for example, has a device-independent width of 320px,
99
		// but its screen is actually 640px wide.  It therefore has a pixel
100
		// ratio of 2, while most normal devices have a ratio of 1.
101

  
102
		var devicePixelRatio = window.devicePixelRatio || 1,
103
			backingStoreRatio =
104
				context.webkitBackingStorePixelRatio ||
105
				context.mozBackingStorePixelRatio ||
106
				context.msBackingStorePixelRatio ||
107
				context.oBackingStorePixelRatio ||
108
				context.backingStorePixelRatio || 1;
109

  
110
		this.pixelRatio = devicePixelRatio / backingStoreRatio;
111

  
112
		// Size the canvas to match the internal dimensions of its container
113

  
114
		this.resize(container.width(), container.height());
115

  
116
		// Collection of HTML div layers for text overlaid onto the canvas
117

  
118
		this.textContainer = null;
119
		this.text = {};
120

  
121
		// Cache of text fragments and metrics, so we can avoid expensively
122
		// re-calculating them when the plot is re-rendered in a loop.
123

  
124
		this._textCache = {};
125
	}
126

  
127
	// Resizes the canvas to the given dimensions.
128
	//
129
	// @param {number} width New width of the canvas, in pixels.
130
	// @param {number} width New height of the canvas, in pixels.
131

  
132
	Canvas.prototype.resize = function(width, height) {
133

  
134
		if (width <= 0 || height <= 0) {
135
			throw new Error("Invalid dimensions for plot, width = " + width + ", height = " + height);
136
		}
137

  
138
		var element = this.element,
139
			context = this.context,
140
			pixelRatio = this.pixelRatio;
141

  
142
		// Resize the canvas, increasing its density based on the display's
143
		// pixel ratio; basically giving it more pixels without increasing the
144
		// size of its element, to take advantage of the fact that retina
145
		// displays have that many more pixels in the same advertised space.
146

  
147
		// Resizing should reset the state (excanvas seems to be buggy though)
148

  
149
		if (this.width != width) {
150
			element.width = width * pixelRatio;
151
			element.style.width = width + "px";
152
			this.width = width;
153
		}
154

  
155
		if (this.height != height) {
156
			element.height = height * pixelRatio;
157
			element.style.height = height + "px";
158
			this.height = height;
159
		}
160

  
161
		// Save the context, so we can reset in case we get replotted.  The
162
		// restore ensure that we're really back at the initial state, and
163
		// should be safe even if we haven't saved the initial state yet.
164

  
165
		context.restore();
166
		context.save();
167

  
168
		// Scale the coordinate space to match the display density; so even though we
169
		// may have twice as many pixels, we still want lines and other drawing to
170
		// appear at the same size; the extra pixels will just make them crisper.
171

  
172
		context.scale(pixelRatio, pixelRatio);
173
	};
174

  
175
	// Clears the entire canvas area, not including any overlaid HTML text
176

  
177
	Canvas.prototype.clear = function() {
178
		this.context.clearRect(0, 0, this.width, this.height);
179
	};
180

  
181
	// Finishes rendering the canvas, including managing the text overlay.
182

  
183
	Canvas.prototype.render = function() {
184

  
185
		var cache = this._textCache;
186

  
187
		// For each text layer, add elements marked as active that haven't
188
		// already been rendered, and remove those that are no longer active.
189

  
190
		for (var layerKey in cache) {
191
			if (hasOwnProperty.call(cache, layerKey)) {
192

  
193
				var layer = this.getTextLayer(layerKey),
194
					layerCache = cache[layerKey];
195

  
196
				layer.hide();
197

  
198
				for (var styleKey in layerCache) {
199
					if (hasOwnProperty.call(layerCache, styleKey)) {
200
						var styleCache = layerCache[styleKey];
201
						for (var key in styleCache) {
202
							if (hasOwnProperty.call(styleCache, key)) {
203

  
204
								var positions = styleCache[key].positions;
205

  
206
								for (var i = 0, position; position = positions[i]; i++) {
207
									if (position.active) {
208
										if (!position.rendered) {
209
											layer.append(position.element);
210
											position.rendered = true;
211
										}
212
									} else {
213
										positions.splice(i--, 1);
214
										if (position.rendered) {
215
											position.element.detach();
216
										}
217
									}
218
								}
219

  
220
								if (positions.length == 0) {
221
									delete styleCache[key];
222
								}
223
							}
224
						}
225
					}
226
				}
227

  
228
				layer.show();
229
			}
230
		}
231
	};
232

  
233
	// Creates (if necessary) and returns the text overlay container.
234
	//
235
	// @param {string} classes String of space-separated CSS classes used to
236
	//     uniquely identify the text layer.
237
	// @return {object} The jQuery-wrapped text-layer div.
238

  
239
	Canvas.prototype.getTextLayer = function(classes) {
240

  
241
		var layer = this.text[classes];
242

  
243
		// Create the text layer if it doesn't exist
244

  
245
		if (layer == null) {
246

  
247
			// Create the text layer container, if it doesn't exist
248

  
249
			if (this.textContainer == null) {
250
				this.textContainer = $("<div class='flot-text'></div>")
251
					.css({
252
						position: "absolute",
253
						top: 0,
254
						left: 0,
255
						bottom: 0,
256
						right: 0,
257
						'font-size': "smaller",
258
						color: "#545454"
259
					})
260
					.insertAfter(this.element);
261
			}
262

  
263
			layer = this.text[classes] = $("<div></div>")
264
				.addClass(classes)
265
				.css({
266
					position: "absolute",
267
					top: 0,
268
					left: 0,
269
					bottom: 0,
270
					right: 0
271
				})
272
				.appendTo(this.textContainer);
273
		}
274

  
275
		return layer;
276
	};
277

  
278
	// Creates (if necessary) and returns a text info object.
279
	//
280
	// The object looks like this:
281
	//
282
	// {
283
	//     width: Width of the text's wrapper div.
284
	//     height: Height of the text's wrapper div.
285
	//     element: The jQuery-wrapped HTML div containing the text.
286
	//     positions: Array of positions at which this text is drawn.
287
	// }
288
	//
289
	// The positions array contains objects that look like this:
290
	//
291
	// {
292
	//     active: Flag indicating whether the text should be visible.
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff