You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2013/12/05 22:13:12 UTC

[3/3] git commit: TAP5-2253: TimeInterval component - display localized interval between two dates

TAP5-2253: TimeInterval component - display localized interval between two dates


Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/bc1c43ac
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/bc1c43ac
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/bc1c43ac

Branch: refs/heads/master
Commit: bc1c43acc8f0ccdfb641790fd1092bc57493ed72
Parents: af6a0e0
Author: Howard M. Lewis Ship <hl...@apache.org>
Authored: Thu Dec 5 13:12:50 2013 -0800
Committer: Howard M. Lewis Ship <hl...@apache.org>
Committed: Thu Dec 5 13:12:50 2013 -0800

----------------------------------------------------------------------
 .../modules/t5/core/time-interval.coffee        |  53 ++++++++++
 .../tapestry5/corelib/components/LocalDate.java |   1 +
 .../corelib/components/TimeInterval.java        | 100 +++++++++++++++++++
 .../internal/services/DateUtilitiesImpl.java    |   2 +-
 .../src/test/app1/TimeIntervalDemo.tml          |  26 +++++
 .../tapestry5/integration/app1/MiscTests.groovy |   9 ++
 .../app1/pages/TimeIntervalDemo.groovy          |  29 ++++++
 .../tapestry5/integration/app1/pages/Index.java |   3 +
 8 files changed, 222 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/bc1c43ac/tapestry-core/src/main/coffeescript/META-INF/modules/t5/core/time-interval.coffee
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/coffeescript/META-INF/modules/t5/core/time-interval.coffee b/tapestry-core/src/main/coffeescript/META-INF/modules/t5/core/time-interval.coffee
new file mode 100644
index 0000000..f386760
--- /dev/null
+++ b/tapestry-core/src/main/coffeescript/META-INF/modules/t5/core/time-interval.coffee
@@ -0,0 +1,53 @@
+# Copyright 2013 The Apache Software Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http:#www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# ## t5/core/time-interval
+#
+# Used with the Interval component to express the interval between two timestamps,
+# or the dynamic difference between now and an end point in the past or future.
+define ["./dom", "./moment"],
+(dom, moment) ->
+
+  ATTR = "data-timeinterval"
+
+  toMoment = (s) -> if s then moment s else moment()
+
+  updateElement = (el) ->
+    start = toMoment el.attr "data-timeinterval-start"
+    end = toMoment el.attr "data-timeinterval-end"
+    plain = el.attr "data-timeinterval-plain"
+
+    el.update end.from start, plain
+    return
+
+  updateDynamics = ->
+    for el in dom.body.find "[#{ATTR}=dynamic]"
+      updateElement el
+    return
+
+  # Update any dynamic intervals (the ones without a specific start date) about once a second
+  setInterval updateDynamics, 1000
+
+  dom.scanner "[#{ATTR}=true]", (el) ->
+
+    updateElement el
+
+    if (el.attr "data-timeinterval-start") and (el.attr "data-timeinterval-end")
+      el.attr ATTR, null
+    else
+      el.attr ATTR, "dynamic"
+
+    return
+
+  return # no exports

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/bc1c43ac/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/LocalDate.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/LocalDate.java b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/LocalDate.java
index 9ca0e27..bf33f30 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/LocalDate.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/LocalDate.java
@@ -41,6 +41,7 @@ import java.util.Date;
  * zone.
  *
  * @tapestrydoc
+ * @see TimeInterval
  * @since 5.4
  */
 @SupportsInformalParameters

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/bc1c43ac/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/TimeInterval.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/TimeInterval.java b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/TimeInterval.java
new file mode 100644
index 0000000..789fce9
--- /dev/null
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/TimeInterval.java
@@ -0,0 +1,100 @@
+// Copyright 2013 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.corelib.components;
+
+import org.apache.tapestry5.ComponentResources;
+import org.apache.tapestry5.MarkupWriter;
+import org.apache.tapestry5.annotations.Import;
+import org.apache.tapestry5.annotations.Parameter;
+import org.apache.tapestry5.annotations.SupportsInformalParameters;
+import org.apache.tapestry5.ioc.annotations.Inject;
+import org.apache.tapestry5.services.DateUtilities;
+
+import java.util.Date;
+
+/**
+ * Used to present an interval value using Moment.js's from() or fromNow() functions. The interval
+ * is determined in terms of a start and end date; either (but not both) may be omitted, in which
+ * case the client will dynamically update the element.  In that case, the value will live update, approximately every second.
+ * <p/>
+ * This component will render an empty element. The element will match the template element,
+ * or a "span" if the template did not provide an element. Informal parameters will be rendered
+ * into the element.
+ * <p/>
+ * When the end date is after the start date, the rendered text will be prefixed with "in".
+ * When the end date precedes the start date, the rendered text will be suffixed with "ago".
+ * The plain parameter is used to turn off the prefix or suffix.
+ *
+ * @tapestrydoc
+ * @see LocalDate
+ * @since 5.4
+ */
+@SupportsInformalParameters
+@Import(module = "t5/core/time-interval")
+public class TimeInterval
+{
+    /**
+     * The start date for the interval. If omitted, the start time is considered "now" and will automatically
+     * update in the browser.
+     */
+    @Parameter
+    Date start;
+
+    /**
+     * The end date for the interval. If omitted, the end time is considered "now" and will update automatically
+     * in the browser.
+     */
+    @Parameter()
+    Date end;
+
+    /**
+     * If true, then output is plain: no "in" prefix or "ago" suffix.
+     */
+    @Parameter
+    boolean plain;
+
+    @Inject
+    ComponentResources resources;
+
+    @Inject
+    DateUtilities dateUtilities;
+
+    private String toISO(Date date)
+    {
+        return date == null ? null : dateUtilities.formatISO8601(date);
+    }
+
+    boolean beginRender(MarkupWriter writer)
+    {
+        writer.element(resources.getElementName("span"),
+                // Trigger the client-side logic:
+                "data-timeinterval", "true",
+                "data-timeinterval-start", toISO(start),
+                "data-timeinterval-end", toISO(end));
+
+        if (plain)
+        {
+            writer.attributes("data-timeinterval-plain", true);
+        }
+
+        resources.renderInformalParameters(writer);
+
+        writer.end();
+
+        // Skip the body regardless.
+        return false;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/bc1c43ac/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DateUtilitiesImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DateUtilitiesImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DateUtilitiesImpl.java
index 6f75d4d..8eaaff3 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DateUtilitiesImpl.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DateUtilitiesImpl.java
@@ -28,7 +28,7 @@ public class DateUtilitiesImpl implements DateUtilities
 {
     private static final TimeZone tz = TimeZone.getTimeZone("UTC");
 
-    private DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'");
+    private DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.S'Z'");
 
     {
         df.setTimeZone(tz);

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/bc1c43ac/tapestry-core/src/test/app1/TimeIntervalDemo.tml
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/app1/TimeIntervalDemo.tml b/tapestry-core/src/test/app1/TimeIntervalDemo.tml
new file mode 100644
index 0000000..c937474
--- /dev/null
+++ b/tapestry-core/src/test/app1/TimeIntervalDemo.tml
@@ -0,0 +1,26 @@
+<html t:type="Border" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd">
+
+    <h1>Interval Demo</h1>
+
+    <dl>
+        <dt>Current time</dt>
+        <dd t:type="localdate" value="now" format="HH:mm:ss"/>
+        <dt>Previous render</dt>
+        <dd>
+            <t:localdate value="previousRender" format="HH:mm:ss"/>
+            -
+            <t:timeinterval id="time-since-prev-render" end="previousRender"/>
+        </dd>
+        <dt>Jacob's Age</dt>
+        <dd id="jacob-age" t:type="timeinterval" start="jacobBirth" plain="true"></dd>
+        <dt>Jacob can Vote</dt>
+        <dd id="jacob-vote" t:type="timeinterval" end="jacobVote"/>
+    </dl>
+
+    <div class="btn-toolbar">
+        <t:actionlink t:id="english" class="btn btn-default">English</t:actionlink>
+        <t:actionlink t:id="french" class="btn btn-default">French</t:actionlink>
+    </div>
+
+</html>
+

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/bc1c43ac/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/MiscTests.groovy
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/MiscTests.groovy b/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/MiscTests.groovy
index 2db2c52..5947362 100644
--- a/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/MiscTests.groovy
+++ b/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/MiscTests.groovy
@@ -63,4 +63,13 @@ class MiscTests extends App1TestCase {
         assertNotEquals defaultFormat, customFormat
     }
 
+    @Test
+    void timeinterval_component() {
+        openLinks "TimeInterval Demo", "English"
+
+        assert getText("time-since-prev-render").endsWith(" ago")
+        assert getText("jacob-age").contains("years")
+        assert getText("jacob-vote").startsWith("in ")
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/bc1c43ac/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/pages/TimeIntervalDemo.groovy
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/pages/TimeIntervalDemo.groovy b/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/pages/TimeIntervalDemo.groovy
new file mode 100644
index 0000000..4495db3
--- /dev/null
+++ b/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/pages/TimeIntervalDemo.groovy
@@ -0,0 +1,29 @@
+package org.apache.tapestry5.integration.app1.pages
+
+import org.apache.tapestry5.annotations.Persist
+import org.apache.tapestry5.annotations.Property
+
+
+class TimeIntervalDemo extends LocalDateDemo {
+
+    @Persist
+    @Property
+    private Date previousRender;
+
+    void setupRender() {
+        if (previousRender == null)
+            previousRender = new Date().clearTime()
+    }
+
+    void afterRender() {
+        previousRender = new Date()
+    }
+
+    Date getJacobBirth() {
+        return new Date(2010 - 1900, 1, 15) // Feb 15 2010
+    }
+
+    Date getJacobVote() {
+        return new Date(2010 + 18 - 1900, 1, 15) // Feb 15 2028
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/bc1c43ac/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java
index 388c5c6..8b2e3fe 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java
@@ -58,6 +58,9 @@ public class Index
 
     private static final List<Item> ITEMS = CollectionFactory
             .newList(
+
+                    new Item("TimeIntervalDemo", "TimeInterval Demo", "Interval component, based on Moment.js"),
+
                     new Item("LocalDateDemo", "LocalDate Demo", "LocalDate component, based on Moment.js"),
 
                     new Item("EmptyIfDemo", "Empty If Demo", "Ensure an empty If can still render."),