Project

General

Profile

« Previous | Next » 

Revision 31555

[maven-release-plugin] copy for tag dnet-modular-oai-explorer-ui-1.0

View differences:

modules/dnet-modular-oai-explorer-ui/tags/dnet-modular-oai-explorer-ui-1.0/pom.xml
1
<?xml version="1.0" encoding="UTF-8"?>
2
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
3
	<parent>
4
		<groupId>eu.dnetlib</groupId>
5
		<artifactId>dnet-parent</artifactId>
6
		<version>1.0.0</version>
7
		<relativePath />
8
	</parent>
9
	<modelVersion>4.0.0</modelVersion>
10
	<groupId>eu.dnetlib</groupId>
11
	<artifactId>dnet-modular-oai-explorer-ui</artifactId>
12
	<packaging>jar</packaging>
13
	<version>1.0</version>
14
	<scm>
15
	  <developerConnection>scm:svn:https://svn.driver.research-infrastructures.eu/driver/dnet40/modules/dnet-modular-oai-explorer-ui/tags/dnet-modular-oai-explorer-ui-1.0</developerConnection>
16
	</scm>
17
	<dependencies>
18
		<dependency>
19
			<groupId>eu.dnetlib</groupId>
20
			<artifactId>dnet-modular-ui</artifactId>
21
			<version>[2.0.0,3.0.0)</version>
22
		</dependency>
23
		<dependency>
24
			<groupId>javax.servlet</groupId>
25
			<artifactId>javax.servlet-api</artifactId>
26
			<version>${javax.servlet.version}</version>
27
			<scope>provided</scope>
28
		</dependency>
29
		<dependency>
30
			<groupId>commons-httpclient</groupId>
31
			<artifactId>commons-httpclient</artifactId>
32
			<version>3.1</version>
33
		</dependency>
34
		<dependency>
35
			<groupId>junit</groupId>
36
			<artifactId>junit</artifactId>
37
			<version>${junit.version}</version>
38
			<scope>test</scope>
39
		</dependency>
40
	</dependencies>
41
</project>
modules/dnet-modular-oai-explorer-ui/tags/dnet-modular-oai-explorer-ui-1.0/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/tags/dnet-modular-oai-explorer-ui-1.0/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/tags/dnet-modular-oai-explorer-ui-1.0/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/tags/dnet-modular-oai-explorer-ui-1.0/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/tags/dnet-modular-oai-explorer-ui-1.0/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/tags/dnet-modular-oai-explorer-ui-1.0/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/tags/dnet-modular-oai-explorer-ui-1.0/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.
293
	//     rendered: Flag indicating whether the text is currently visible.
294
	//     element: The jQuery-wrapped HTML div containing the text.
295
	//     x: X coordinate at which to draw the text.
296
	//     y: Y coordinate at which to draw the text.
297
	// }
298
	//
299
	// Each position after the first receives a clone of the original element.
300
	//
301
	// The idea is that that the width, height, and general 'identity' of the
302
	// text is constant no matter where it is placed; the placements are a
303
	// secondary property.
304
	//
305
	// Canvas maintains a cache of recently-used text info objects; getTextInfo
306
	// either returns the cached element or creates a new entry.
307
	//
308
	// @param {string} layer A string of space-separated CSS classes uniquely
309
	//     identifying the layer containing this text.
310
	// @param {string} text Text string to retrieve info for.
311
	// @param {(string|object)=} font Either a string of space-separated CSS
312
	//     classes or a font-spec object, defining the text's font and style.
313
	// @param {number=} angle Angle at which to rotate the text, in degrees.
314
	//     Angle is currently unused, it will be implemented in the future.
315
	// @param {number=} width Maximum width of the text before it wraps.
316
	// @return {object} a text info object.
317

  
318
	Canvas.prototype.getTextInfo = function(layer, text, font, angle, width) {
319

  
320
		var textStyle, layerCache, styleCache, info;
321

  
322
		// Cast the value to a string, in case we were given a number or such
323

  
324
		text = "" + text;
325

  
326
		// If the font is a font-spec object, generate a CSS font definition
327

  
328
		if (typeof font === "object") {
329
			textStyle = font.style + " " + font.variant + " " + font.weight + " " + font.size + "px/" + font.lineHeight + "px " + font.family;
330
		} else {
331
			textStyle = font;
332
		}
333

  
334
		// Retrieve (or create) the cache for the text's layer and styles
335

  
336
		layerCache = this._textCache[layer];
337

  
338
		if (layerCache == null) {
339
			layerCache = this._textCache[layer] = {};
340
		}
341

  
342
		styleCache = layerCache[textStyle];
343

  
344
		if (styleCache == null) {
345
			styleCache = layerCache[textStyle] = {};
346
		}
347

  
348
		info = styleCache[text];
349

  
350
		// If we can't find a matching element in our cache, create a new one
351

  
352
		if (info == null) {
353

  
354
			var element = $("<div></div>").html(text)
355
				.css({
356
					position: "absolute",
357
					'max-width': width,
358
					top: -9999
359
				})
360
				.appendTo(this.getTextLayer(layer));
361

  
362
			if (typeof font === "object") {
363
				element.css({
364
					font: textStyle,
365
					color: font.color
366
				});
367
			} else if (typeof font === "string") {
368
				element.addClass(font);
369
			}
370

  
371
			info = styleCache[text] = {
372
				width: element.outerWidth(true),
373
				height: element.outerHeight(true),
374
				element: element,
375
				positions: []
376
			};
377

  
378
			element.detach();
379
		}
380

  
381
		return info;
382
	};
383

  
384
	// Adds a text string to the canvas text overlay.
385
	//
386
	// The text isn't drawn immediately; it is marked as rendering, which will
387
	// result in its addition to the canvas on the next render pass.
388
	//
389
	// @param {string} layer A string of space-separated CSS classes uniquely
390
	//     identifying the layer containing this text.
391
	// @param {number} x X coordinate at which to draw the text.
392
	// @param {number} y Y coordinate at which to draw the text.
393
	// @param {string} text Text string to draw.
394
	// @param {(string|object)=} font Either a string of space-separated CSS
395
	//     classes or a font-spec object, defining the text's font and style.
396
	// @param {number=} angle Angle at which to rotate the text, in degrees.
397
	//     Angle is currently unused, it will be implemented in the future.
398
	// @param {number=} width Maximum width of the text before it wraps.
399
	// @param {string=} halign Horizontal alignment of the text; either "left",
400
	//     "center" or "right".
401
	// @param {string=} valign Vertical alignment of the text; either "top",
402
	//     "middle" or "bottom".
403

  
404
	Canvas.prototype.addText = function(layer, x, y, text, font, angle, width, halign, valign) {
405

  
406
		var info = this.getTextInfo(layer, text, font, angle, width),
407
			positions = info.positions;
408

  
409
		// Tweak the div's position to match the text's alignment
410

  
411
		if (halign == "center") {
412
			x -= info.width / 2;
413
		} else if (halign == "right") {
414
			x -= info.width;
415
		}
416

  
417
		if (valign == "middle") {
418
			y -= info.height / 2;
419
		} else if (valign == "bottom") {
420
			y -= info.height;
421
		}
422

  
423
		// Determine whether this text already exists at this position.
424
		// If so, mark it for inclusion in the next render pass.
425

  
426
		for (var i = 0, position; position = positions[i]; i++) {
427
			if (position.x == x && position.y == y) {
428
				position.active = true;
429
				return;
430
			}
431
		}
432

  
433
		// If the text doesn't exist at this position, create a new entry
434

  
435
		// For the very first position we'll re-use the original element,
436
		// while for subsequent ones we'll clone it.
437

  
438
		position = {
439
			active: true,
440
			rendered: false,
441
			element: positions.length ? info.element.clone() : info.element,
442
			x: x,
443
			y: y
444
		};
445

  
446
		positions.push(position);
447

  
448
		// Move the element to its final position within the container
449

  
450
		position.element.css({
451
			top: Math.round(y),
452
			left: Math.round(x),
453
			'text-align': halign	// In case the text wraps
454
		});
455
	};
456

  
457
	// Removes one or more text strings from the canvas text overlay.
458
	//
459
	// If no parameters are given, all text within the layer is removed.
460
	//
461
	// Note that the text is not immediately removed; it is simply marked as
462
	// inactive, which will result in its removal on the next render pass.
463
	// This avoids the performance penalty for 'clear and redraw' behavior,
464
	// where we potentially get rid of all text on a layer, but will likely
465
	// add back most or all of it later, as when redrawing axes, for example.
466
	//
467
	// @param {string} layer A string of space-separated CSS classes uniquely
468
	//     identifying the layer containing this text.
469
	// @param {number=} x X coordinate of the text.
470
	// @param {number=} y Y coordinate of the text.
471
	// @param {string=} text Text string to remove.
472
	// @param {(string|object)=} font Either a string of space-separated CSS
473
	//     classes or a font-spec object, defining the text's font and style.
474
	// @param {number=} angle Angle at which the text is rotated, in degrees.
475
	//     Angle is currently unused, it will be implemented in the future.
476

  
477
	Canvas.prototype.removeText = function(layer, x, y, text, font, angle) {
478
		if (text == null) {
479
			var layerCache = this._textCache[layer];
480
			if (layerCache != null) {
481
				for (var styleKey in layerCache) {
482
					if (hasOwnProperty.call(layerCache, styleKey)) {
483
						var styleCache = layerCache[styleKey];
484
						for (var key in styleCache) {
485
							if (hasOwnProperty.call(styleCache, key)) {
486
								var positions = styleCache[key].positions;
487
								for (var i = 0, position; position = positions[i]; i++) {
488
									position.active = false;
489
								}
490
							}
491
						}
492
					}
493
				}
494
			}
495
		} else {
496
			var positions = this.getTextInfo(layer, text, font, angle).positions;
497
			for (var i = 0, position; position = positions[i]; i++) {
498
				if (position.x == x && position.y == y) {
499
					position.active = false;
500
				}
501
			}
502
		}
503
	};
504

  
505
	///////////////////////////////////////////////////////////////////////////
506
	// The top-level container for the entire plot.
507

  
508
    function Plot(placeholder, data_, options_, plugins) {
509
        // data is on the form:
510
        //   [ series1, series2 ... ]
511
        // where series is either just the data as [ [x1, y1], [x2, y2], ... ]
512
        // or { data: [ [x1, y1], [x2, y2], ... ], label: "some label", ... }
513

  
514
        var series = [],
515
            options = {
516
                // the color theme used for graphs
517
                colors: ["#edc240", "#afd8f8", "#cb4b4b", "#4da74d", "#9440ed"],
518
                legend: {
519
                    show: true,
520
                    noColumns: 1, // number of colums in legend table
521
                    labelFormatter: null, // fn: string -> string
522
                    labelBoxBorderColor: "#ccc", // border color for the little label boxes
523
                    container: null, // container (as jQuery object) to put legend in, null means default on top of graph
524
                    position: "ne", // position of default legend container within plot
525
                    margin: 5, // distance from grid edge to default legend container within plot
526
                    backgroundColor: null, // null means auto-detect
527
                    backgroundOpacity: 0.85, // set to 0 to avoid background
528
                    sorted: null    // default to no legend sorting
529
                },
530
                xaxis: {
531
                    show: null, // null = auto-detect, true = always, false = never
532
                    position: "bottom", // or "top"
533
                    mode: null, // null or "time"
534
                    font: null, // null (derived from CSS in placeholder) or object like { size: 11, lineHeight: 13, style: "italic", weight: "bold", family: "sans-serif", variant: "small-caps" }
535
                    color: null, // base color, labels, ticks
536
                    tickColor: null, // possibly different color of ticks, e.g. "rgba(0,0,0,0.15)"
537
                    transform: null, // null or f: number -> number to transform axis
538
                    inverseTransform: null, // if transform is set, this should be the inverse function
539
                    min: null, // min. value to show, null means set automatically
540
                    max: null, // max. value to show, null means set automatically
541
                    autoscaleMargin: null, // margin in % to add if auto-setting min/max
542
                    ticks: null, // either [1, 3] or [[1, "a"], 3] or (fn: axis info -> ticks) or app. number of ticks for auto-ticks
543
                    tickFormatter: null, // fn: number -> string
544
                    labelWidth: null, // size of tick labels in pixels
545
                    labelHeight: null,
546
                    reserveSpace: null, // whether to reserve space even if axis isn't shown
547
                    tickLength: null, // size in pixels of ticks, or "full" for whole line
548
                    alignTicksWithAxis: null, // axis number or null for no sync
549
                    tickDecimals: null, // no. of decimals, null means auto
550
                    tickSize: null, // number or [number, "unit"]
551
                    minTickSize: null // number or [number, "unit"]
552
                },
553
                yaxis: {
554
                    autoscaleMargin: 0.02,
555
                    position: "left" // or "right"
556
                },
557
                xaxes: [],
558
                yaxes: [],
559
                series: {
560
                    points: {
561
                        show: false,
562
                        radius: 3,
563
                        lineWidth: 2, // in pixels
564
                        fill: true,
565
                        fillColor: "#ffffff",
566
                        symbol: "circle" // or callback
567
                    },
568
                    lines: {
569
                        // we don't put in show: false so we can see
570
                        // whether lines were actively disabled
571
                        lineWidth: 2, // in pixels
572
                        fill: false,
573
                        fillColor: null,
574
                        steps: false
575
                        // Omit 'zero', so we can later default its value to
576
                        // match that of the 'fill' option.
577
                    },
578
                    bars: {
579
                        show: false,
580
                        lineWidth: 2, // in pixels
581
                        barWidth: 1, // in units of the x axis
582
                        fill: true,
583
                        fillColor: null,
584
                        align: "left", // "left", "right", or "center"
585
                        horizontal: false,
586
                        zero: true
587
                    },
588
                    shadowSize: 3,
589
                    highlightColor: null
590
                },
591
                grid: {
592
                    show: true,
593
                    aboveData: false,
594
                    color: "#545454", // primary color used for outline and labels
595
                    backgroundColor: null, // null for transparent, else color
596
                    borderColor: null, // set if different from the grid color
597
                    tickColor: null, // color for the ticks, e.g. "rgba(0,0,0,0.15)"
598
                    margin: 0, // distance from the canvas edge to the grid
599
                    labelMargin: 5, // in pixels
600
                    axisMargin: 8, // in pixels
601
                    borderWidth: 2, // in pixels
602
                    minBorderMargin: null, // in pixels, null means taken from points radius
603
                    markings: null, // array of ranges or fn: axes -> array of ranges
604
                    markingsColor: "#f4f4f4",
605
                    markingsLineWidth: 2,
606
                    // interactive stuff
607
                    clickable: false,
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff