From 422b1caeaa9f7d069a9208ecb0d0249485b1a05e Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Wed, 26 Dec 2012 21:45:38 +0100 Subject: o Adding details page for persons. o Better front page. --- .../core/badge/UnbreakableBadgeProgress.java | 1 - .../trygvis/esper/testing/core/db/PersonDao.java | 18 +- .../java/io/trygvis/esper/testing/esper/Test1.java | 1 - .../java/io/trygvis/esper/testing/esper/Test3.java | 1 - .../esper/testing/gitorious/GitoriousClient.java | 1 - .../gitorious/GitoriousProjectDiscovery.java | 1 - .../esper/testing/nexus/NexusFeedParser.java | 1 - .../trygvis/esper/testing/nexus/NexusImporter.java | 1 - .../io/trygvis/esper/testing/util/HttpClient.java | 1 - .../io/trygvis/esper/testing/util/XmlParser.java | 1 - .../esper/testing/util/object/ObjectUtil.java | 1 - .../esper/testing/util/sql/PageRequest.java | 2 +- .../esper/testing/web/AbstractResource.java | 26 + .../io/trygvis/esper/testing/web/CoreResource.java | 66 +- .../trygvis/esper/testing/web/JenkinsResource.java | 19 +- .../esper/testing/web/JerseyApplication.java | 3 +- .../webapp/WEB-INF/tags/common/head-element.tagx | 10 +- src/main/webapp/WEB-INF/urlrewrite.xml | 6 + src/main/webapp/apps/app.css | 41 + src/main/webapp/apps/frontPageApp/frontPage.html | 29 +- src/main/webapp/apps/frontPageApp/frontPageApp.js | 64 +- src/main/webapp/apps/personApp/person.html | 17 + src/main/webapp/apps/personApp/personApp.js | 12 + .../ng-grid-1.5.0/ng-grid-1.5.0.debug.js | 2334 ++++++++++++++++++++ .../angular-ui/ng-grid-1.5.0/ng-grid-1.5.0.js | 7 + .../external/angular-ui/ng-grid-1.5.0/ng-grid.css | 456 ++++ src/main/webapp/login.jspx | 4 +- src/main/webapp/person/person.jspx | 22 + 28 files changed, 3069 insertions(+), 77 deletions(-) create mode 100644 src/main/java/io/trygvis/esper/testing/web/AbstractResource.java create mode 100644 src/main/webapp/apps/app.css create mode 100644 src/main/webapp/apps/personApp/person.html create mode 100644 src/main/webapp/apps/personApp/personApp.js create mode 100644 src/main/webapp/external/angular-ui/ng-grid-1.5.0/ng-grid-1.5.0.debug.js create mode 100644 src/main/webapp/external/angular-ui/ng-grid-1.5.0/ng-grid-1.5.0.js create mode 100644 src/main/webapp/external/angular-ui/ng-grid-1.5.0/ng-grid.css create mode 100644 src/main/webapp/person/person.jspx diff --git a/src/main/java/io/trygvis/esper/testing/core/badge/UnbreakableBadgeProgress.java b/src/main/java/io/trygvis/esper/testing/core/badge/UnbreakableBadgeProgress.java index dc9a5bc..4cba611 100644 --- a/src/main/java/io/trygvis/esper/testing/core/badge/UnbreakableBadgeProgress.java +++ b/src/main/java/io/trygvis/esper/testing/core/badge/UnbreakableBadgeProgress.java @@ -80,7 +80,6 @@ public class UnbreakableBadgeProgress extends BadgeProgress { return 1; } - @Override public String toString() { return "UnbreakableBadgeProgress{person=" + person + ", count=" + count + '}'; } diff --git a/src/main/java/io/trygvis/esper/testing/core/db/PersonDao.java b/src/main/java/io/trygvis/esper/testing/core/db/PersonDao.java index 6605999..62c4f2b 100644 --- a/src/main/java/io/trygvis/esper/testing/core/db/PersonDao.java +++ b/src/main/java/io/trygvis/esper/testing/core/db/PersonDao.java @@ -1,6 +1,5 @@ package io.trygvis.esper.testing.core.db; -import static io.trygvis.esper.testing.Util.toList; import io.trygvis.esper.testing.core.db.PersonBadgeDto.*; import io.trygvis.esper.testing.util.sql.*; import org.joda.time.*; @@ -8,6 +7,7 @@ import org.joda.time.*; import java.sql.*; import java.util.*; +import static io.trygvis.esper.testing.Util.*; import static io.trygvis.esper.testing.util.sql.SqlOption.*; import static java.lang.System.*; @@ -36,7 +36,7 @@ public class PersonDao { new DateTime(rs.getTimestamp(i++).getTime()), UUID.fromString(rs.getString(i++)), BadgeType.valueOf(rs.getString(i++)), - rs.getInt(i), + rs.getInt(i++), rs.getInt(i)); } }; @@ -63,16 +63,16 @@ public class PersonDao { // Person // ----------------------------------------------------------------------- - public SqlOption selectPerson(String id) throws SQLException { - try (PreparedStatement s = c.prepareStatement("SELECT " + PERSON + " FROM person WHERE id=?")) { + public SqlOption selectPerson(UUID uuid) throws SQLException { + try (PreparedStatement s = c.prepareStatement("SELECT " + PERSON + " FROM person WHERE uuid=?")) { int i = 1; - s.setString(i, id); + s.setString(i, uuid.toString()); return fromRs(s.executeQuery()).map(person); } } public List selectPerson(PageRequest pageRequest) throws SQLException { - try (PreparedStatement s = c.prepareStatement("SELECT " + PERSON + " FROM person ORDER BY created_date LIMIT ? OFFSET ?")) { + try (PreparedStatement s = c.prepareStatement("SELECT " + PERSON + " FROM person ORDER BY created_date, name LIMIT ? OFFSET ?")) { int i = 1; s.setInt(i++, pageRequest.count.orSome(10)); s.setInt(i, pageRequest.startIndex.orSome(0)); @@ -80,6 +80,12 @@ public class PersonDao { } } + public int selectPersonCount() throws SQLException { + try (PreparedStatement s = c.prepareStatement("SELECT count(1) FROM person")) { + return fromRs(s.executeQuery()).map(ResultSetF.getInt).get(); + } + } + public SqlOption selectPersonByJenkinsUuid(UUID jenkinsUser) throws SQLException { try (PreparedStatement s = c.prepareStatement("SELECT " + PERSON + " FROM person WHERE uuid=(SELECT person FROM person_jenkins_user WHERE jenkins_user=?)")) { int i = 1; diff --git a/src/main/java/io/trygvis/esper/testing/esper/Test1.java b/src/main/java/io/trygvis/esper/testing/esper/Test1.java index 842dcb3..43f857b 100644 --- a/src/main/java/io/trygvis/esper/testing/esper/Test1.java +++ b/src/main/java/io/trygvis/esper/testing/esper/Test1.java @@ -68,7 +68,6 @@ public class Test1 { Timer timer = new Timer(); timer.scheduleAtFixedRate(new TimerTask() { - @Override public void run() { logger.info("tick"); } diff --git a/src/main/java/io/trygvis/esper/testing/esper/Test3.java b/src/main/java/io/trygvis/esper/testing/esper/Test3.java index 70c4dc3..1c007b9 100644 --- a/src/main/java/io/trygvis/esper/testing/esper/Test3.java +++ b/src/main/java/io/trygvis/esper/testing/esper/Test3.java @@ -68,7 +68,6 @@ public class Test3 { Timer timer = new Timer(); timer.scheduleAtFixedRate(new TimerTask() { - @Override public void run() { logger.info("tick"); } diff --git a/src/main/java/io/trygvis/esper/testing/gitorious/GitoriousClient.java b/src/main/java/io/trygvis/esper/testing/gitorious/GitoriousClient.java index 0071b1f..745c36a 100644 --- a/src/main/java/io/trygvis/esper/testing/gitorious/GitoriousClient.java +++ b/src/main/java/io/trygvis/esper/testing/gitorious/GitoriousClient.java @@ -31,7 +31,6 @@ public class GitoriousClient { private final GitoriousAtomFeedParser parser; private final F>> parseDocument = new F>>() { - @Override public Option> f(HTTPResponse response) { MIMEType mimeType = MIMEType.valueOf(trimToEmpty(response.getHeaders().getFirstHeaderValue("Content-Type"))); if (!mimeType.getPrimaryType().equals("application") || !mimeType.getSubType().equals("xml")) { diff --git a/src/main/java/io/trygvis/esper/testing/gitorious/GitoriousProjectDiscovery.java b/src/main/java/io/trygvis/esper/testing/gitorious/GitoriousProjectDiscovery.java index 1429f83..9fe809c 100644 --- a/src/main/java/io/trygvis/esper/testing/gitorious/GitoriousProjectDiscovery.java +++ b/src/main/java/io/trygvis/esper/testing/gitorious/GitoriousProjectDiscovery.java @@ -50,7 +50,6 @@ public class GitoriousProjectDiscovery { }); ObjectUtil.scheduledActorWithFixedDelay(service, config.gitorious.projectListUpdateDelay, config.gitorious.projectListUpdateInterval, TimeUnit.MILLISECONDS, boneCp, "Gitorious", new TransactionalActor() { - @Override public void act(Connection c) throws Exception { try (Daos daos = new Daos(c)) { discoverProjects(daos); diff --git a/src/main/java/io/trygvis/esper/testing/nexus/NexusFeedParser.java b/src/main/java/io/trygvis/esper/testing/nexus/NexusFeedParser.java index eb89f30..fa5f2a1 100644 --- a/src/main/java/io/trygvis/esper/testing/nexus/NexusFeedParser.java +++ b/src/main/java/io/trygvis/esper/testing/nexus/NexusFeedParser.java @@ -50,7 +50,6 @@ public class NexusFeedParser { Option guid = Option.fromNull(item.getChildText("guid")); Option creator = Option.fromNull(item.getChildText("creator", dc)); Option date = Option.fromNull(item.getChildText("date", dc)).bind(new F>() { - @Override public Option f(String s) { try { return some(ISODateTimeFormat.dateTimeNoMillis().parseDateTime(s)); diff --git a/src/main/java/io/trygvis/esper/testing/nexus/NexusImporter.java b/src/main/java/io/trygvis/esper/testing/nexus/NexusImporter.java index 4042108..024cde2 100644 --- a/src/main/java/io/trygvis/esper/testing/nexus/NexusImporter.java +++ b/src/main/java/io/trygvis/esper/testing/nexus/NexusImporter.java @@ -71,7 +71,6 @@ class NexusServer implements TransactionalActor { this.xmlParser = xmlParser; } - @Override public void act(Connection c) throws Exception { NexusDao dao = new NexusDao(c); diff --git a/src/main/java/io/trygvis/esper/testing/util/HttpClient.java b/src/main/java/io/trygvis/esper/testing/util/HttpClient.java index 69c74fe..1676d3f 100644 --- a/src/main/java/io/trygvis/esper/testing/util/HttpClient.java +++ b/src/main/java/io/trygvis/esper/testing/util/HttpClient.java @@ -34,7 +34,6 @@ public class HttpClient { public static F> inputStreamOnly(final F> f) { return new F>() { - @Override public Option f(HTTPResponse response) { InputStream inputStream = response.getPayload().getInputStream(); try { diff --git a/src/main/java/io/trygvis/esper/testing/util/XmlParser.java b/src/main/java/io/trygvis/esper/testing/util/XmlParser.java index 9c585fc..624785c 100644 --- a/src/main/java/io/trygvis/esper/testing/util/XmlParser.java +++ b/src/main/java/io/trygvis/esper/testing/util/XmlParser.java @@ -46,7 +46,6 @@ public class XmlParser { boolean seenStartDocument; - @Override public boolean accept(XMLStreamReader reader) { if(reader.getEventType() == SPACE && !seenStartDocument) { return false; diff --git a/src/main/java/io/trygvis/esper/testing/util/object/ObjectUtil.java b/src/main/java/io/trygvis/esper/testing/util/object/ObjectUtil.java index 143a181..26c9e14 100644 --- a/src/main/java/io/trygvis/esper/testing/util/object/ObjectUtil.java +++ b/src/main/java/io/trygvis/esper/testing/util/object/ObjectUtil.java @@ -80,7 +80,6 @@ public class ObjectUtil { future.cancel(true); } - @Override public void run() { actor.run(); } diff --git a/src/main/java/io/trygvis/esper/testing/util/sql/PageRequest.java b/src/main/java/io/trygvis/esper/testing/util/sql/PageRequest.java index 2d8edfe..91a00f8 100644 --- a/src/main/java/io/trygvis/esper/testing/util/sql/PageRequest.java +++ b/src/main/java/io/trygvis/esper/testing/util/sql/PageRequest.java @@ -15,7 +15,7 @@ public class PageRequest { this.count = count; } - public static PageRequest fromReq(HttpServletRequest req) { + public static PageRequest pageReq(HttpServletRequest req) { return new PageRequest( fromNull(req.getParameter("startIndex")).bind(Util.parseInt), fromNull(req.getParameter("count")).bind(Util.parseInt)); diff --git a/src/main/java/io/trygvis/esper/testing/web/AbstractResource.java b/src/main/java/io/trygvis/esper/testing/web/AbstractResource.java new file mode 100644 index 0000000..c811a2f --- /dev/null +++ b/src/main/java/io/trygvis/esper/testing/web/AbstractResource.java @@ -0,0 +1,26 @@ +package io.trygvis.esper.testing.web; + +import fj.data.*; +import io.trygvis.esper.testing.*; + +import javax.ws.rs.*; +import javax.ws.rs.core.*; +import java.sql.*; + +public class AbstractResource { + protected final DatabaseAccess da; + + public AbstractResource(DatabaseAccess da) { + this.da = da; + } + + public T get(DatabaseAccess.DaosCallback> callback) throws SQLException { + Option server = da.inTransaction(callback); + + if(server.isNone()) { + throw new WebApplicationException(Response.Status.NOT_FOUND); + } + + return server.some(); + } +} diff --git a/src/main/java/io/trygvis/esper/testing/web/CoreResource.java b/src/main/java/io/trygvis/esper/testing/web/CoreResource.java index 3132a62..f2fb12a 100644 --- a/src/main/java/io/trygvis/esper/testing/web/CoreResource.java +++ b/src/main/java/io/trygvis/esper/testing/web/CoreResource.java @@ -1,5 +1,6 @@ package io.trygvis.esper.testing.web; +import fj.data.*; import io.trygvis.esper.testing.*; import io.trygvis.esper.testing.core.badge.*; import io.trygvis.esper.testing.core.db.*; @@ -10,27 +11,31 @@ import javax.ws.rs.*; import javax.ws.rs.core.*; import java.sql.*; import java.util.*; +import java.util.List; + +import static io.trygvis.esper.testing.util.sql.PageRequest.*; +import static io.trygvis.esper.testing.web.JenkinsResource.*; @Path("/resource/core") -public class CoreResource { +@Produces(MediaType.APPLICATION_JSON) +public class CoreResource extends AbstractResource { - private final DatabaseAccess da; private final BadgeService badgeService; public CoreResource(DatabaseAccess da, BadgeService badgeService) { - this.da = da; + super(da); this.badgeService = badgeService; } @GET @Path("/person") - @Produces(MediaType.APPLICATION_JSON) - public List getServers(@Context final HttpServletRequest req) throws Exception { + public List getPersons(@Context final HttpServletRequest req) throws Exception { + final PageRequest pageRequest = pageReq(req); + return da.inTransaction(new DatabaseAccess.DaosCallback>() { - @Override public List run(Daos daos) throws SQLException { List list = new ArrayList<>(); - for (PersonDto person : daos.personDao.selectPerson(PageRequest.fromReq(req))) { + for (PersonDto person : daos.personDao.selectPerson(pageRequest)) { list.add(getPersonJson(daos, person)); } return list; @@ -38,6 +43,36 @@ public class CoreResource { }); } + /** + * This is wrong, but Angular's $resource is a bit dumb. + */ + @GET + @Path("/person-count") + public int getPersonCount() throws Exception { + return da.inTransaction(new DatabaseAccess.DaosCallback() { + public Integer run(Daos daos) throws SQLException { + return daos.personDao.selectPersonCount(); + } + }); + } + + @GET + @Path("/person/{uuid}") + public PersonJson getPerson(@PathParam("uuid") final String s) throws Exception { + final UUID uuid = parseUuid(s); + + return get(new DatabaseAccess.DaosCallback>() { + public Option run(Daos daos) throws SQLException { + SqlOption o = daos.personDao.selectPerson(uuid); + if (o.isNone()) { + return Option.none(); + } + + return Option.some(getPersonJson(daos, o.get())); + } + }); + } + private PersonJson getPersonJson(Daos daos, PersonDto person) throws SQLException { List badges = new ArrayList<>(); @@ -45,16 +80,19 @@ public class CoreResource { badges.add(new BadgeJson(badge.type.name(), badge.level, badge.count, 100, 100)); } + List badgesInProgress = new ArrayList<>(); + for (PersonBadgeProgressDto badgeProgressDto : daos.personDao.selectBadgeProgresses(person.uuid)) { UnbreakableBadgeProgress progress = badgeService.unbreakable(badgeProgressDto); - badges.add(new BadgeJson(progress.type.name(), progress.progressingAgainstLevel(), 0, - progress.progression(), progress.goal())); + badgesInProgress.add(new BadgeJson(progress.type.name(), progress.progressingAgainstLevel(), 0, + progress.progression(), progress.goal())); } return new PersonJson( - person.uuid, - person.name, - badges + person.uuid, + person.name, + badges, + badgesInProgress ); } @@ -62,11 +100,13 @@ public class CoreResource { public final UUID uuid; public final String name; public final List badges; + public final List badgesInProgress; - public PersonJson(UUID uuid, String name, List badges) { + public PersonJson(UUID uuid, String name, List badges, List badgesInProgress) { this.uuid = uuid; this.name = name; this.badges = badges; + this.badgesInProgress = badgesInProgress; } } diff --git a/src/main/java/io/trygvis/esper/testing/web/JenkinsResource.java b/src/main/java/io/trygvis/esper/testing/web/JenkinsResource.java index 6551cea..bd925b6 100644 --- a/src/main/java/io/trygvis/esper/testing/web/JenkinsResource.java +++ b/src/main/java/io/trygvis/esper/testing/web/JenkinsResource.java @@ -15,12 +15,10 @@ import java.util.List; import static fj.data.Option.*; @Path("/resource/jenkins") -public class JenkinsResource { - - private final DatabaseAccess da; +public class JenkinsResource extends AbstractResource { public JenkinsResource(DatabaseAccess da) { - this.da = da; + super(da); } @GET @@ -28,7 +26,6 @@ public class JenkinsResource { @Produces(MediaType.APPLICATION_JSON) public List getServers() throws Exception { return da.inTransaction(new DatabaseAccess.DaosCallback>() { - @Override public List run(Daos daos) throws SQLException { List list = new ArrayList<>(); for (JenkinsServerDto server : daos.jenkinsDao.selectServers(false)) { @@ -63,17 +60,7 @@ public class JenkinsResource { return new JenkinsServerJson(server.uuid, server.createdDate, server.url, server.enabled, count); } - private T get(DatabaseAccess.DaosCallback> callback) throws SQLException { - Option server = da.inTransaction(callback); - - if(server.isNone()) { - throw new WebApplicationException(Response.Status.NOT_FOUND); - } - - return server.some(); - } - - private UUID parseUuid(String s) { + public static UUID parseUuid(String s) { try { return UUID.fromString(s); } catch (IllegalArgumentException e) { diff --git a/src/main/java/io/trygvis/esper/testing/web/JerseyApplication.java b/src/main/java/io/trygvis/esper/testing/web/JerseyApplication.java index 67fbf74..eded64c 100644 --- a/src/main/java/io/trygvis/esper/testing/web/JerseyApplication.java +++ b/src/main/java/io/trygvis/esper/testing/web/JerseyApplication.java @@ -15,13 +15,12 @@ public class JerseyApplication extends Application { BadgeService badgeService = new BadgeService(); - singletons = new HashSet<>(Arrays.asList( + singletons = new HashSet(Arrays.asList( new CoreResource(da, badgeService), new JenkinsResource(da) )); } - @Override public Set getSingletons() { return singletons; } diff --git a/src/main/webapp/WEB-INF/tags/common/head-element.tagx b/src/main/webapp/WEB-INF/tags/common/head-element.tagx index e552b7b..bb8804c 100644 --- a/src/main/webapp/WEB-INF/tags/common/head-element.tagx +++ b/src/main/webapp/WEB-INF/tags/common/head-element.tagx @@ -1,7 +1,6 @@ - + @@ -11,13 +10,16 @@ <c:if test="${not empty title }">${title } - </c:if>Yeah + + diff --git a/src/main/webapp/WEB-INF/urlrewrite.xml b/src/main/webapp/WEB-INF/urlrewrite.xml index ff4bf10..e5f3338 100644 --- a/src/main/webapp/WEB-INF/urlrewrite.xml +++ b/src/main/webapp/WEB-INF/urlrewrite.xml @@ -15,4 +15,10 @@ /index.jspx + + ^/person/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$ + $1 + /person/person.jspx + + diff --git a/src/main/webapp/apps/app.css b/src/main/webapp/apps/app.css new file mode 100644 index 0000000..761b765 --- /dev/null +++ b/src/main/webapp/apps/app.css @@ -0,0 +1,41 @@ +/* + bronze = #8c7853 + bronze ii = #a67d3d + */ + +.badge-level-1 { background-color: #a67d3d; } +.badge-level-2 { background-color: silver; } +.badge-level-3 { background-color: #ffd700; } + +#content { + background-color: #ffffff; + padding-bottom: 60px; +} + +#footer { + background-color: #f5f5f5; + border-top: 1px solid #ccc; + color: #000000; +} + +#footer .container { + padding: 60px 0; +} + +#footer abbr[title] { + border-bottom: 1px dotted #000; +} + +#footer p { + margin-bottom: 0; + color: #777; +} + +#footer-links { + margin: 10px 0; +} + +#footer-links li { + display: inline; + margin-right: 10px; +} diff --git a/src/main/webapp/apps/frontPageApp/frontPage.html b/src/main/webapp/apps/frontPageApp/frontPage.html index bfa2477..4523e6f 100644 --- a/src/main/webapp/apps/frontPageApp/frontPage.html +++ b/src/main/webapp/apps/frontPageApp/frontPage.html @@ -1,24 +1,15 @@
- + + + -

- - - - - - - - - - - - - -
NameLevelCountProgressGoal
{{person.name}}{{person.badges.length}}
-

+
diff --git a/src/main/webapp/apps/frontPageApp/frontPageApp.js b/src/main/webapp/apps/frontPageApp/frontPageApp.js index 4c5df8b..d92a163 100644 --- a/src/main/webapp/apps/frontPageApp/frontPageApp.js +++ b/src/main/webapp/apps/frontPageApp/frontPageApp.js @@ -1,12 +1,68 @@ 'use strict'; -var frontPageApp = angular.module('frontPageApp', ['personService']).config(function ($routeProvider, $locationProvider) { +var frontPageApp = angular.module('frontPageApp', ['ngGrid', 'personService']).config(function ($routeProvider, $locationProvider) { $routeProvider. when('/', {controller: FrontPageCtrl, templateUrl: '/apps/frontPageApp/frontPage.html?noCache=' + noCache}); }); -function FrontPageCtrl($scope, $location, PersonService) { - PersonService.query(function (persons) { - $scope.persons = persons; +function FrontPageCtrl($scope, $http, PersonService) { + $scope.persons = []; + + $scope.pagingOptions = { + pageSizes: [10], + pageSize: 10, + totalServerItems: 0, + currentPage: 1 + }; + + $scope.personsGridOptions = { + data: 'persons', + displayFooter: true, + enablePaging: true, + showFilter: false, + showColumnMenu: false, + canSelectRows: false, + displaySelectionCheckbox: false, + pagingOptions: $scope.pagingOptions, + columnDefs: [ + { + field: 'name', + displayName: 'Name', + cellTemplate: '{{row.getProperty(col.field)}}' + }, + { + field: 'badges', + displayName: 'Badges', + cellTemplate: '
{{row.getProperty(col.field).length}}
' + } + ] + }; + + $scope.setPagingData = function(data, page, pageSize){ +// $scope.persons = data.slice((page - 1) * pageSize, page * pageSize); + $scope.persons = data; + $scope.personsGridOptions.totalServerItems = data.length; + if (!$scope.$$phase) { + $scope.$apply(); + } + }; + + $scope.getPagedDataAsync = function (pageSize, page/*, searchText*/) { + setTimeout(function () { + + PersonService.query({startIndex: page * pageSize, count: pageSize}, function (persons) { + $scope.setPagingData(persons, page, pageSize); + }); + }, 100); + }; + + $scope.$watch('pagingOptions', function () { + $scope.getPagedDataAsync($scope.pagingOptions.pageSize, $scope.pagingOptions.currentPage); + }, true); + + $http.get('/resource/core/person-count').success(function(count) { + $scope.pagingOptions.totalServerItems = count; + + $scope.getPagedDataAsync($scope.pagingOptions.pageSize, $scope.pagingOptions.currentPage); }); } diff --git a/src/main/webapp/apps/personApp/person.html b/src/main/webapp/apps/personApp/person.html new file mode 100644 index 0000000..4189f20 --- /dev/null +++ b/src/main/webapp/apps/personApp/person.html @@ -0,0 +1,17 @@ +
+ + + +

Badges

+

+ {{badge.name}} x {{badge.count}} +

+ +

Badges in progress

+

+ {{badge.name}} progress: {{badge.progress}} of {{badge.goal}} +

+ +
diff --git a/src/main/webapp/apps/personApp/personApp.js b/src/main/webapp/apps/personApp/personApp.js new file mode 100644 index 0000000..59f5a7d --- /dev/null +++ b/src/main/webapp/apps/personApp/personApp.js @@ -0,0 +1,12 @@ +'use strict'; + +var personApp = angular.module('personApp', ['personService']).config(function ($routeProvider, $locationProvider) { + $routeProvider. + when('/', {controller: PersonCtrl, templateUrl: '/apps/personApp/person.html?noCache=' + noCache}); +}); + +function PersonCtrl($scope, $location, PersonService) { + PersonService.get({uuid: uuid}, function (person) { + $scope.person = person; + }); +} diff --git a/src/main/webapp/external/angular-ui/ng-grid-1.5.0/ng-grid-1.5.0.debug.js b/src/main/webapp/external/angular-ui/ng-grid-1.5.0/ng-grid-1.5.0.debug.js new file mode 100644 index 0000000..4ceaa00 --- /dev/null +++ b/src/main/webapp/external/angular-ui/ng-grid-1.5.0/ng-grid-1.5.0.debug.js @@ -0,0 +1,2334 @@ +/*********************************************** + * ng-grid JavaScript Library + * Authors: https://github.com/angular-ui/ng-grid/blob/master/README.md + * License: MIT (http://www.opensource.org/licenses/mit-license.php) + * Compiled At: 12/21/2012 15:55:15 + ***********************************************/ + +(function(window) { + 'use strict'; + + /*********************************************** + * FILE: ..\src\namespace.js + ***********************************************/ + window.ng = {}; + window.ng.$http = undefined; + var ngGridServices = angular.module('ngGrid.services', []); + var ngGridDirectives = angular.module('ngGrid.directives', []); + var ngGridFilters = angular.module('ngGrid.filters', []); +// Declare app level module which depends on filters, and services + + /*********************************************** + * FILE: ..\src\constants.js + ***********************************************/ + var SELECTED_PROP = '__ng_selected__'; + var GRID_KEY = '__koGrid__'; +// the # of rows we want to add to the top and bottom of the rendered grid rows + var EXCESS_ROWS = 8; + var SCROLL_THRESHOLD = 6; + var ASC = "asc"; +// constant for sorting direction + var DESC = "desc"; +// constant for sorting direction + var NG_FIELD = '_ng_field_'; + var NG_DEPTH = '_ng_depth_'; + var NG_HIDDEN = '_ng_hidden_'; + var NG_COLUMN = '_ng_column_'; + var CUSTOM_FILTERS = /CUSTOM_FILTERS/g; + var TEMPLATE_REGEXP = /<.+>/; + + /*********************************************** + * FILE: ..\src\navigation.js + ***********************************************/ +//set event binding on the grid so we can select using the up/down keys + ng.moveSelectionHandler = function($scope, grid, evt) { + // null checks + if (grid === null || grid === undefined) { + return true; + } + if (grid.config.selectedItems === undefined) { + return true; + } + var charCode = evt.which || evt.keyCode; + // detect which direction for arrow keys to navigate the grid + var offset = (charCode == 38 ? -1 : (charCode == 40 ? 1 : null)); + if (!offset) { + return true; + } + var items = $scope.renderedRows; + var index = items.indexOf(grid.selectionService.lastClickedRow) + offset; + if (index < 0 || index >= items.length) { + return true; + } + grid.selectionService.ChangeSelection(items[index], evt); + if (index > items.length - EXCESS_ROWS) { + grid.$viewport.scrollTop(grid.$viewport.scrollTop() + (grid.config.rowHeight * 2)); + } else if (index < EXCESS_ROWS) { + grid.$viewport.scrollTop(grid.$viewport.scrollTop() - (grid.config.rowHeight * 2)); + } + if (!$scope.$$phase) { + $scope.$parent.$digest(); + } + return false; + }; + + /*********************************************** + * FILE: ..\src\utils.js + ***********************************************/ + if (!String.prototype.trim) { + String.prototype.trim = function() { + return this.replace(/^\s+|\s+$/g, ''); + }; + } + if (!Array.prototype.indexOf) { + Array.prototype.indexOf = function(elt /*, from*/) { + var len = this.length >>> 0; + var from = Number(arguments[1]) || 0; + from = (from < 0) ? Math.ceil(from) : Math.floor(from); + if (from < 0) { + from += len; + } + for (; from < len; from++) { + if (from in this && this[from] === elt) { + return from; + } + } + return -1; + }; + } + if (!Array.prototype.filter) { + Array.prototype.filter = function(fun /*, thisp */) { + "use strict"; + var t = Object(this); + var len = t.length >>> 0; + if (typeof fun !== "function") { + throw new TypeError(); + } + var res = []; + var thisp = arguments[1]; + for (var i = 0; i < len; i++) { + if (i in t) { + var val = t[i]; // in case fun mutates this + if (fun.call(thisp, val, i, t)) { + res.push(val); + } + } + } + return res; + }; + } + ng.utils = { + visualLength: function(node) { + var elem = document.getElementById('testDataLength'); + if (!elem) { + elem = document.createElement('SPAN'); + elem.id = "testDataLength"; + elem.style.visibility = "hidden"; + document.body.appendChild(elem); + } + $(elem).css('font', $(node).css('font')); + elem.innerHTML = $(node).text(); + return elem.offsetWidth; + }, + forIn: function(obj, action) { + for (var prop in obj) { + if (obj.hasOwnProperty(prop)) { + action(obj[prop], prop); + } + } + }, + evalProperty: function(entity, path) { + var propPath = path.split('.'), i = 0; + var tempProp = entity[propPath[i]], links = propPath.length; + i++; + while (tempProp && i < links) { + tempProp = tempProp[propPath[i]]; + i++; + } + return tempProp; + }, + endsWith: function(str, suffix) { + if (!str || !suffix || typeof str != "string") { + return false; + } + return str.indexOf(suffix, str.length - suffix.length) !== -1; + }, + isNullOrUndefined: function(obj) { + if (obj === undefined || obj === null) { + return true; + } + return false; + }, + getElementsByClassName: function(cl) { + var retnode = []; + var myclass = new RegExp('\\b' + cl + '\\b'); + var elem = document.getElementsByTagName('*'); + for (var i = 0; i < elem.length; i++) { + var classes = elem[i].className; + if (myclass.test(classes)) { + retnode.push(elem[i]); + } + } + return retnode; + }, + newId: (function() { + var seedId = new Date().getTime(); + return function() { + return seedId += 1; + }; + })(), + + // we copy KO's ie detection here bc it isn't exported in the min versions of KO + // Detect IE versions for workarounds (uses IE conditionals, not UA string, for robustness) + ieVersion: (function() { + var version = 3, div = document.createElement('div'), iElems = div.getElementsByTagName('i'); + // Keep constructing conditional HTML blocks until we hit one that resolves to an empty fragment + while (div.innerHTML = '', + iElems[0]); + return version > 4 ? version : undefined; + })() + }; + + $.extend(ng.utils, { + isIe6: (function() { + return ng.utils.ieVersion === 6; + })(), + isIe7: (function() { + return ng.utils.ieVersion === 7; + })(), + isIe: (function() { + return ng.utils.ieVersion !== undefined; + })() + }); + + /*********************************************** + * FILE: ..\src\filters\ngColumns.js + ***********************************************/ + ngGridFilters.filter('ngColumns', function() { + return function(input) { + return input.filter(function(col) { + return !col.isAggCol; + }); + }; + }); + + /*********************************************** + * FILE: ..\src\filters\checkmark.js + ***********************************************/ + ngGridFilters.filter('checkmark', function() { + return function(input) { + return input ? '\u2714' : '\u2718'; + }; + }); + + /*********************************************** + * FILE: ..\src\services\SortService.js + ***********************************************/ + ngGridServices.factory('SortService', function() { + var sortService = {}; + sortService.colSortFnCache = {}; // cache of sorting functions. Once we create them, we don't want to keep re-doing it + sortService.dateRE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/; // nasty regex for date parsing + // this takes an piece of data from the cell and tries to determine its type and what sorting + // function to use for it + // @item - the cell data + sortService.guessSortFn = function(item) { + var sortFn, // sorting function that is guessed + itemType, // the typeof item + dateParts, // for date parsing + month, // for date parsing + day; // for date parsing + + if (item === undefined || item === null || item === '') { + return null; + } + itemType = typeof(item); + //check for numbers and booleans + switch (itemType) { + case "number": + sortFn = sortService.sortNumber; + break; + case "boolean": + sortFn = sortService.sortBool; + break; + default: + sortFn = undefined; + break; + } + //if we found one, return it + if (sortFn) { + return sortFn; + } + //check if the item is a valid Date + if (Object.prototype.toString.call(item) === '[object Date]') { + return sortService.sortDate; + } + // if we aren't left with a string, return a basic sorting function... + if (itemType !== "string") { + return sortService.basicSort; + } + // now lets string check.. + //check if the item data is a valid number + if (item.match(/^-?[�$�]?[\d,.]+%?$/)) { + return sortService.sortNumberStr; + } + // check for a date: dd/mm/yyyy or dd/mm/yy + // can have / or . or - as separator + // can be mm/dd as well + dateParts = item.match(sortService.dateRE); + if (dateParts) { + // looks like a date + month = parseInt(dateParts[1], 10); + day = parseInt(dateParts[2], 10); + if (month > 12) { + // definitely dd/mm + return sortService.sortDDMMStr; + } else if (day > 12) { + return sortService.sortMMDDStr; + } else { + // looks like a date, but we can't tell which, so assume that it's MM/DD + return sortService.sortMMDDStr; + } + } + //finally just sort the normal string... + return sortService.sortAlpha; + }; + //#region Sorting Functions + sortService.basicSort = function(a, b) { + if (a == b) { + return 0; + } + if (a < b) { + return -1; + } + return 1; + }; + sortService.sortNumber = function(a, b) { + return a - b; + }; + sortService.sortNumberStr = function(a, b) { + var numA, numB, badA = false, badB = false; + numA = parseFloat(a.replace(/[^0-9.-]/g, '')); + if (isNaN(numA)) { + badA = true; + } + numB = parseFloat(b.replace(/[^0-9.-]/g, '')); + if (isNaN(numB)) { + badB = true; + } + // we want bad ones to get pushed to the bottom... which effectively is "greater than" + if (badA && badB) { + return 0; + } + if (badA) { + return 1; + } + if (badB) { + return -1; + } + return numA - numB; + }; + sortService.sortAlpha = function(a, b) { + var strA = a.toLowerCase(), + strB = b.toLowerCase(); + return strA == strB ? 0 : (strA < strB ? -1 : 1); + }; + sortService.sortDate = function(a, b) { + var timeA = a.getTime(), + timeB = b.getTime(); + return timeA == timeB ? 0 : (timeA < timeB ? -1 : 1); + }; + sortService.sortBool = function(a, b) { + if (a && b) { + return 0; + } + if (!a && !b) { + return 0; + } else { + return a ? 1 : -1; + } + }; + sortService.sortDDMMStr = function(a, b) { + var dateA, dateB, mtch, m, d, y; + mtch = a.match(sortService.dateRE); + y = mtch[3]; + m = mtch[2]; + d = mtch[1]; + if (m.length == 1) { + m = '0' + m; + } + if (d.length == 1) { + d = '0' + d; + } + dateA = y + m + d; + mtch = b.match(sortService.dateRE); + y = mtch[3]; + m = mtch[2]; + d = mtch[1]; + if (m.length == 1) { + m = '0' + m; + } + if (d.length == 1) { + d = '0' + d; + } + dateB = y + m + d; + if (dateA == dateB) { + return 0; + } + if (dateA < dateB) { + return -1; + } + return 1; + }; + sortService.sortMMDDStr = function(a, b) { + var dateA, dateB, mtch, m, d, y; + mtch = a.match(sortService.dateRE); + y = mtch[3]; + d = mtch[2]; + m = mtch[1]; + if (m.length == 1) { + m = '0' + m; + } + if (d.length == 1) { + d = '0' + d; + } + dateA = y + m + d; + mtch = b.match(sortService.dateRE); + y = mtch[3]; + d = mtch[2]; + m = mtch[1]; + if (m.length == 1) { + m = '0' + m; + } + if (d.length == 1) { + d = '0' + d; + } + dateB = y + m + d; + if (dateA == dateB) { + return 0; + } + if (dateA < dateB) { + return -1; + } + return 1; + }; + //#endregion + // the core sorting logic trigger + sortService.sortData = function(data /*datasource*/, sortInfo) { + // first make sure we are even supposed to do work + if (!data || !sortInfo) { + return; + } + // grab the metadata for the rest of the logic + var col = sortInfo.column, + direction = sortInfo.direction, + sortFn, + item; + + //see if we already figured out what to use to sort the column + if (sortService.colSortFnCache[col.field]) { + sortFn = sortService.colSortFnCache[col.field]; + } else if (col.sortingAlgorithm != undefined) { + sortFn = col.sortingAlgorithm; + sortService.colSortFnCache[col.field] = col.sortingAlgorithm; + } else { // try and guess what sort function to use + item = data[0]; + if (!item) { + return; + } + sortFn = sortService.guessSortFn(item[col.field]); + //cache it + if (sortFn) { + sortService.colSortFnCache[col.field] = sortFn; + } else { + // we assign the alpha sort because anything that is null/undefined will never get passed to + // the actual sorting function. It will get caught in our null check and returned to be sorted + // down to the bottom + sortFn = sortService.sortAlpha; + } + } + //now actually sort the data + data.sort(function(itemA, itemB) { + var propA = ng.utils.evalProperty(itemA, col.field); + var propB = ng.utils.evalProperty(itemB, col.field); + // we want to force nulls and such to the bottom when we sort... which effectively is "greater than" + if (!propB && !propA) { + return 0; + } else if (!propA) { + return 1; + } else if (!propB) { + return -1; + } + //made it this far, we don't have to worry about null & undefined + if (direction === ASC) { + return sortFn(propA, propB); + } else { + return 0 - sortFn(propA, propB); + } + }); + return; + }; + sortService.Sort = function(sortInfo, data) { + if (sortService.isSorting) { + return; + } + sortService.isSorting = true; + sortService.sortData(data, sortInfo); + sortService.isSorting = false; + }; + return sortService; + }); + + /*********************************************** + * FILE: ..\src\services\DomUtilityService.js + ***********************************************/ + ngGridServices.factory('DomUtilityService', function() { + var domUtilityService = {}; + var getWidths = function() { + var $testContainer = $('
'); + $testContainer.appendTo('body'); + // 1. Run all the following measurements on startup! + //measure Scroll Bars + $testContainer.height(100).width(100).css("position", "absolute").css("overflow", "scroll"); + $testContainer.append('
'); + domUtilityService.ScrollH = ($testContainer.height() - $testContainer[0].clientHeight); + domUtilityService.ScrollW = ($testContainer.width() - $testContainer[0].clientWidth); + $testContainer.empty(); + //clear styles + $testContainer.attr('style', ''); + //measure letter sizes using a pretty typical font size and fat font-family + $testContainer.append('M'); + domUtilityService.LetterW = $testContainer.children().first().width(); + $testContainer.remove(); + }; + domUtilityService.eventStorage = {}; + domUtilityService.AssignGridContainers = function(rootEl, grid) { + grid.$root = $(rootEl); + //Headers + grid.$topPanel = grid.$root.find(".ngTopPanel"); + grid.$groupPanel = grid.$root.find(".ngGroupPanel"); + grid.$headerContainer = grid.$topPanel.find(".ngHeaderContainer"); + grid.$headerScroller = grid.$topPanel.find(".ngHeaderScroller"); + grid.$headers = grid.$headerScroller.children(); + //Viewport + grid.$viewport = grid.$root.find(".ngViewport"); + //Canvas + grid.$canvas = grid.$viewport.find(".ngCanvas"); + //Footers + grid.$footerPanel = grid.$root.find(".ngFooterPanel"); + domUtilityService.UpdateGridLayout(grid); + }; + domUtilityService.UpdateGridLayout = function(grid) { + //catch this so we can return the viewer to their original scroll after the resize! + var scrollTop = grid.$viewport.scrollTop(); + grid.elementDims.rootMaxW = grid.$root.width(); + grid.elementDims.rootMaxH = grid.$root.height(); + //check to see if anything has changed + grid.refreshDomSizes(); + grid.adjustScrollTop(scrollTop, true); //ensure that the user stays scrolled where they were + }; + domUtilityService.numberOfGrids = 0; + domUtilityService.BuildStyles = function($scope, grid, digest) { + var rowHeight = grid.config.rowHeight, + $style = grid.$styleSheet, + gridId = grid.gridId, + css, + cols = $scope.visibleColumns(), + sumWidth = 0; + + if (!$style) { + $style = $('#' + gridId); + if (!$style[0]) { + $style = $("