diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100755 index 0000000..7152b80 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1 @@ +include README.md LICENSE \ No newline at end of file diff --git a/README.md b/README.md index 8916e82..0c85790 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,52 @@ Flask-Moment ============ + +This extension enhances Jinja2 templates with formatting of dates and times using [moment.js](http://momentjs.com/). + +Quick Start +----------- + +Step 1: Initialize the extension: + + from flask.ext.moment import Moment + moment = Moment(app) + +Step 2: In your `` section of your base template add the following code: + + + {{ moment.include_jquery() }} + {{ moment.include_moment() }} + + +Note that jQuery is required. If you are already including it on your own then you can remove the `include_jquery()` line. + +Step 3: Render timestamps in your template. For example: + +

The current date and time is: {{ moment().format('MMMM Do YYYY, h:mm:ss a') }}.

+

Something happened {{ moment(then).fromTime(now) }}.

+

{{ moment(then).calendar() }}.

+ +In the second and third examples template variables `then` and `now` are used. These must be instances of Python's `datetime` class, and must be "naive" objects given in UTC timezone. See the [documentation](http://docs.python.org/2/library/datetime.html) for a discussion of naive date and time objects. As an example, `now` can be set as follows: + + now = datetime.utcnow() + +Note that even though the timestamps are provided in UTC the rendered dates and times will be in the local time of the client computer, so each users will always see their local time regardless of where they are located. + +The supported list of display functions is shown below: + +- `moment(timestamp = None).format(format_string)` +- `moment(timestamp = None).fromNow(no_suffix = False)` +- `moment(timestamp = None).fromTime(another_timesatmp, no_suffix = False)` +- `moment(timestamp = None).calendar()` +- `moment(timestamp = None).valueOf()` +- `moment(timestamp = None).unix()` + +Consult the [moment.js documentation](http://momentjs.com/) for details on these functions. + +All the display functions take an optional `refresh` argument that when set to `True` will re-render timestamps every minute. This can be useful for relative time formats such as the one returned by the `fromNow()` or `fromTime()` functions. By default refreshing is disabled. + +By default dates and times are rendered in English. To change to a different language add the following line in the `` section after the `include_moment()` line: + + {{ moment.lang("es") }} + +The above example sets the language to Spanish. Moment.js supports a large number of languages, consult the documentation for the list of languages and their two letter codes. diff --git a/example/app.py b/example/app.py new file mode 100644 index 0000000..9315f90 --- /dev/null +++ b/example/app.py @@ -0,0 +1,15 @@ +from datetime import datetime +from flask import Flask, render_template +from flask.ext.moment import Moment + +app = Flask(__name__) +moment = Moment(app) + +@app.route('/') +def index(): + now = datetime.utcnow() + midnight = datetime(now.year, now.month, now.day, 0, 0, 0) + return render_template('index.html', now = now, midnight = midnight) + +if __name__ == '__main__': + app.run(debug = True) diff --git a/example/requirements.txt b/example/requirements.txt new file mode 100644 index 0000000..e2254de --- /dev/null +++ b/example/requirements.txt @@ -0,0 +1,6 @@ +Flask==0.10.1 +Flask-Moment==0.1.0 +Jinja2==2.7.1 +MarkupSafe==0.18 +Werkzeug==0.9.4 +itsdangerous==0.23 diff --git a/example/templates/index.html b/example/templates/index.html new file mode 100644 index 0000000..3c61d7e --- /dev/null +++ b/example/templates/index.html @@ -0,0 +1,18 @@ + + + Flask-Moment example app + {{ moment.include_jquery() }} + {{ moment.include_moment() }} + + +

The current date and time is: {{ moment().format('MMMM Do YYYY, h:mm:ss a') }}.

+

+ {{ moment(midnight).fromTime(now) }} it was midnight in the UTC timezone. + That was {{ moment(midnight).calendar() }} in your local time. +

+

+ This page was rendered on {{ moment(now).format('LLL') }}, + which was {{ moment(now).fromNow(refresh = True) }}. +

+ + diff --git a/flask_moment.py b/flask_moment.py new file mode 100644 index 0000000..4abdbb7 --- /dev/null +++ b/flask_moment.py @@ -0,0 +1,78 @@ +from datetime import datetime +import json +from jinja2 import Markup +from flask import current_app + +class _moment(object): + @staticmethod + def include_moment(version = '2.3.1'): + if version is not None: + js = '\n' % version + return Markup('''%s''' % js) + + @staticmethod + def include_jquery(version = '1.10.1'): + return Markup('' % version) + + @staticmethod + def lang(language): + return Markup('' % language) + + def __init__(self, timestamp = None): + if timestamp is None: + timestamp = datetime.utcnow() + self.timestamp = timestamp + + def _timestamp_as_iso_8601(self, timestamp): + return timestamp.strftime('%Y-%m-%dT%H:%M:%SZ') + + def _render(self, format, refresh = False): + t = self._timestamp_as_iso_8601(self.timestamp) + return Markup('%s' % (t, format, int(refresh) * 60000, t)) + + def format(self, fmt, refresh = False): + return self._render("format('%s')" % fmt, refresh) + + def fromNow(self, no_suffix = False, refresh = False): + return self._render("fromNow(%s)" % int(no_suffix), refresh) + + def fromTime(self, timestamp, no_suffix = False, refresh = False): + return self._render("from(moment('%s'),%s)" % (self._timestamp_as_iso_8601(timestamp),int(no_suffix)), refresh) + + def calendar(self, refresh = False): + return self._render("calendar()", refresh) + + def valueOf(self, refresh = False): + return self._render("valueOf()", refresh) + + def unix(self, refresh = False): + return self._render("unix()", refresh) + +class Moment(object): + def __init__(self, app = None): + if app is not None: + self.init_app(app) + + def init_app(self, app): + if not hasattr(app, 'extensions'): + app.extensions = {} + app.extensions['moment'] = _moment + app.context_processor(self.context_processor) + + @staticmethod + def context_processor(): + return { + 'moment': current_app.extensions['moment'] + } diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..1721b38 --- /dev/null +++ b/setup.py @@ -0,0 +1,36 @@ +""" +Flask-Moment +------------ + +Formatting of dates and times in Flask templates using moment.js. +""" +from setuptools import setup + + +setup( + name='Flask-Moment', + version='0.1.0', + url='http://github.com/miguelgrinberg/flask-moment/', + license='MIT', + author='Miguel Grinberg', + author_email='miguelgrinberg50@gmail.com', + description='Formatting of dates and times in Flask templates using moment.js.', + long_description=__doc__, + py_modules=['flask_moment'], + zip_safe=False, + include_package_data=True, + platforms='any', + install_requires=[ + 'Flask' + ], + classifiers=[ + 'Environment :: Web Environment', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: BSD License', + 'Operating System :: OS Independent', + 'Programming Language :: Python', + 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', + 'Topic :: Software Development :: Libraries :: Python Modules' + ] +) +