Giter VIP home page Giter VIP logo

django-datetime-widget's People

Contributors

asaglimbeni avatar bcbwilla avatar idlesign avatar ionelmc avatar jimr avatar kleinlieu avatar komackaj avatar michaeljones avatar urtzai avatar vlad-khramov avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

django-datetime-widget's Issues

startDate, endDate and daysOfWeekDisabled not working

Hello,

these options (startDate, endDate and daysOfWeekDisabled) are not working because the resulting javascript is incorrect. I think the quote function in datetimewidget/widgets.py is not quoting datetime values. Also, 'daysOfWeekDisabled' has to be in form of list (i.e. [0,6]) but it's being rendered without any quotation.

Regards,
Hector.

Inconsistency with boolean values

I'm wondering why some values are expected to be passed as python booleans and others as quoted booleans. For instance, todayBtn cannot be set as True, but todayHighlight can.

Does it work within the admin?

Hello and thank you for your awesome widget,

I am trying to use your widget in the admin for this i am trying via a form in the following way:

class MovieAdminForm(forms.ModelForm):
class Meta:
    model = Movie
    widgets = {
        'date': DateTimeWidget(attrs={'id':"id_date_0"}, usel10n = True, bootstrap_version=3)
        }  

@admin.register(Movie)
    class MovieAdmin(SummernoteModelAdmin):
    list_display = ('title', 'date','end_date', )
    search_fields = ('title',)
    form = MovieAdminForm
    fieldsets = (
    ('General Info',{
        'fields':('title','description', 'date', 'end_date', 'picture', 'room', ),
        }),
    )

this produce the following output:
screenshot_3

at client side it all works great but once i try to save:
screenshot_4

i believe this is because normally in the admin datetime field is repsented by two inputs one for time and one for date is there and easy workaround for this?

Clear button does not work

Firstly, thank you for your widget. It's great.

I have developed a DateField using your widget:

DATE_FIELD_OPTIONS = {
    'format' : 'dd/mm/yyyy',
    'autoclose': 'true',
    'minView' : '2',
    'weekStart': '1',
    'clearBtn' : 'true',   
}
start_date = forms.DateField(required=False, 
                     label='Start Date',   
                     widget=DateTimeWidget(options = DATE_FIELD_OPTIONS))

Everything works perfectly, however, the Clear button does not clear the form.

I'm using GET instead of POST to pass the parameters. Could that be the problem?

I'm using Django 1.4.8 and the latest version on PyPi.

Best regards,

Blackout dates, hours

Would like to define some blackout dates/hours. Is this possible? Would be happy to do it with some guidance.

Suggestion for Django 1.8+: DurationWidget

I am finding these widgets very useful. Django 1.8+ introduces a new time-related field type for durations. At the moment I am using a TimeField so I can use a DateTimeWidget with it, but I would like a widget that looked much the same, but gave a result compatible with a DurationField.

Datepicker is not showing

I have all requirements. So I think something is wrong with my model or form

#models.py
class MyModel(models.Model):
    number = models.IntegerField(max_length=20, unique=True)
    start_date = models.DateField(null=True, blank=True)
    end_date = models.DateField(null=True, blank=True)

    def __str__(self):
        return '%s' % self.first_name
#forms.py
class MyForm(forms.ModelForm):
    class Meta:
        model = MyModel
        widgets = {
            'datetime': DateTimeWidget(attrs={'id': "yourdatetimeid"})
        }

Do not require users to load JS first

Use something like the following to defer execution of your plugin code, until Jquery is available.

function defer(method) {
    if (window.$)
        method();
    else
        setTimeout(function() { defer(method) }, 50);
}

Option clearBtn doesn't work when Boolean

Constructing DateTimeWidget with options dictionary containing 'clearBtn' key doesn't work when used as per documentation - it says

Boolean. Default: False

but

  • there is no entry in quoted_bool_options
  • initializing clearBtn variable in PickerWidgetMixin's render method is buggy due to self.options.get('clearBtn', 'true') == 'true' (True != 'true') - we should compare quoted value to handle both strings (to preserve backward comaptibility) and booleans

DateWidget tries to convert date to current timezone and fails

I am using version 0.9. Trying to edit an object with DateField using a form with DateWidget leads to the following:

File "python2.7/site-packages/django/forms/widgets.py", line 804, in render
value = self.decompress(value)

File "python2.7/site-packages/datetimewidget/widgets.py", line 185, in decompress
value = to_current_timezone(value).strftime(self.format)

File "python2.7/site-packages/django/forms/utils.py", line 166, in to_current_timezone
if settings.USE_TZ and value is not None and timezone.is_aware(value):

File "python2.7/site-packages/django/utils/timezone.py", line 339, in is_aware
return value.tzinfo is not None and value.tzinfo.utcoffset(value) is not None

AttributeError: 'datetime.date' object has no attribute 'tzinfo'

Accessing the Javascript hooks

Hi,

Firstly, thank you very much for writing this app and supporting it. I have found it very useful so far.

I currently have a form that has a start datetime field and an end datetime field. Currently they are independent but I would like to change it so that when a datetime is selected on the start field that value becomes the default/starting point for the end datetime field so that people are guided to the same date & time by default as they will frequently be on the same date and only hours apart.

I think this will involve responding to the changeData event from the time picker. I am new to this but I think I would either try to add my additional javascript to the datetime-picker template or try to reference the appropriate input field by its id. The first might be possible by overriding the datetimewidget.BOOTSTRAP_INPUT_TEMPLATE string, though that feels quite hacky and would have global effects and the second approach is difficult as the input's id is a randomly generated string.

Do you have any advice here? Am I missing an easier option? If not, would you be interested in supporting this workflow? I would be happy to try to contribute changes that might make it easier?

Kind regards and many thanks for the project,
Michael

Unique IDs

Hi, thank you very much for your widget.

I just notice a problem. You are using the same id for the div that contain the input and for the input itself.

IDs have been created to be unique. The current implementation create problems if for example you want to change the value of the input using JQuery. You are forced to use the selector "input[name="id"]" which is reported to be slower in old browsers.

Enter a valid date/time.

Hi I have setup a form widget like

dt = forms.DateTimeField("Export start time",
widget=DateTimeWidget(usel10n=True, bootstrap_version=3))

The format I chose in formats.py is chosen correctly. I can change the format and the widget changes
when choosing a date. On submit though I always get "Enter a valid date/time."

Any suggestions ?

Thanks

Additional input-group-addon

I've managed to add an additional input-group-addon to the datetimewidget by modifying widgets.py to accept an additional 'label' in the attr dictionary. (as shown below, the 'Start' and 'End' text)

  • before I fork the project for use in my own code, is there a way to achieve this already, natively with your module? If not, I'll fork it and submit a merge request.

screen shot 2015-01-21 at 17 41 37

Back to 1899

Hello,

I've been working with this widget for a while and I found it very useful for my project.

When it comes to fill a new datetime field everything is ok. However, attempting to open the widget for edition, it jumps back to 1899. It works, but I want to launch it from the date shown in the field.

image

My widget settings:
dateTimeOptions = {
'format': 'dd.mm.yyyy hh:00', # I guess this is causing the problem
'autoclose': True,
'todayHighlight': True,
'minuteStep': 60,
'minView': 1,
'maxView': 2
}

I've tried to access to the widget from js, but I couldn't. Is it possible?

Thanks in advance

Update Readme

Update Readme with latest relase.

  • More detailed configuration.
  • Section for set django L10N .
  • add ClearBtn
  • Autoclose default now is true.
  • update js lib, native localization, thanks to quantum13
  • Change log

Can't set attrs of widget

Hi asaglimbeni! Your widget great and work fine with default settings. But attrs dont work for me. I'm trying do it in this way:

class FilterForm(forms.ModelForm):
   from_date = forms.DateField(
       widget=DateWidget(
           attrs={'weekStart': '3', 'autoclose': 'false'}, 
           usel10n=True, 
           bootstrap_version=3
       ),
       required=False
   )
   class Meta:
       model = Grid
       fields = ['from_date']

Nothing happens at any settings, widget run as default. Localization dont work too. In setting.py

LANGUAGE_CODE = 'ru-RU'
TIME_ZONE = 'Europe/Kiev'
USE_I18N = True
USE_L10N = True
USE_TZ = True

Please help me tuning widget!
Best regards

bootstrap-datetimepicker.min.css not found

Awesome work on the update, I get an error:
/static/datetimepicker/css/bootstrap-datetimepicker.min.css returns a 404 and sure enough doesn't exist.
Is this something to do with the setup script?
I cloned the latest version and used

setup.py build
setup.py install

Picker display bugs

Hello, thank you for your very useful widget.

I have noticed some bugs in the picker display:

  • first of all, the highlighted month is not the good one !!

wrong_highlited_month

... which is annoying because if you set the endDate to today, it prevents you from selecting the current month

  • but you can still access the good month with the right arrow

can_still_go_forward
can_still_access_today

  • turning todayHighlight option to 'false' (or False) does not seem to work
  • and the last bug is that if you set a startDate, there is two much selectable decades on the left (one actually). Example with startDate at 1911:

too_much_left_decades
last_left_decade

... but if you select a year, and go back to decades view, then it is corrected and you cannot access the last left decade anymore

Here are my options:

start = datetime.date(1911, 01, 01)
end = datetime.date.today()
dt_options = {
    'startView': 4,
    'minView': 2,
    'startDate': str(start),
    'endDate': str(end),
    'todayBtn': 'true',
    'todayHighlight': 'false',
}
widget=DateWidget(
    usel10n=False,
    options=dt_options,
    bootstrap_version=3
)

Besides, I had to convert booleans and dates to string, unlike what is written in the README :(

Please tell me if you need more informations.

Regards,
TM

I get TypeError: 'undefined' is not a function (evalua ….)

Hello, thanks a lot for providing this kind of widget. I'm having a problem using this widget. I see the widget in the page with the icon. I push the icon and nothing occurs. I see in the debugger this error:
TypeError: 'undefined' is not a function (evaluating '$("#f4f0d394302e4843a2f0863dd7c428ee").datetimepicker')
global code (39, line 144)

I've tried to follow closely the example, but I do not know where the problem is.
In the base template I have:

<link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet" media="screen">
<link href="{% static 'css/bootstrap-responsive.min.css' %}" rel="stylesheet">
 <!-- This file store project specific CSS -->
<link href="{% static 'css/project.css' %}" rel="stylesheet">
<!-- Use this to quickly test CSS changes in a template,
    then move to project.css -->
{% block extra_css %}{% endblock extra_css %}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>  
<script src="{% static 'js/jquery.ui.datepicker.js' %}"></script>
<script src="{% static 'js/bootstrap.min.js' %}"></script>

{{ form.media }}

Then in the template where these widgets are I have:

{% csrf_token %} {{ formset.management_form }} {% for miform in formset %} {{ miform.id}} {% if miform.instance.indicador.esIntervalo %} {{ miform.instance.indicador.nombre }}: {% else %} {% endif %} {% endfor %}
{{ miform.instance.indicador.nombre }}: Inicio Intervalo{{ miform.fecha1 }}Fin Intervalo{{miform.fecha2}} {{ miform.numero }} de {{ miform.total}}{{ miform.instance.indicador.nombre }}: {{ miform.valor|center:'4' }} {{miform.instance.indicador.unidad}}

The form for the formset is:

class InsIndicForm(forms.ModelForm):
#valor = forms.FloatField(widget=forms.TextInput(attrs={'size':'5'}))
class Meta:
model=InstanciaIndicador
fields=('valor','fecha1','fecha2','numero', 'total')
widgets = {
'fecha1': DateTimeWidget(attrs={'id':"fecha1"}, usel10n = True),
'fecha2': DateTimeWidget(attrs={'id':"fecha2"}, usel10n = True),

    }

Please, do you see where is the error?

Thanks in advance,

Diego.

js locale file doesn't loads when language is changed

If a site uses multiple languages​​ and you switch the current language then app doesn't load corresponding js-file with translation when variable {{ form.media }} is used.
I found a workaround which works for me, please have a look:

widgets.py [@@ -251,7 +251,7 @@]

 class PickerWidgetMixin(object):

         js = ["js/bootstrap-datetimepicker.js"]

-        language = self.options.get('language', 'en')
+        language = get_supported_language(get_language())
         if language != 'en':
             js.append("js/locales/bootstrap-datetimepicker.%s.js" % language)

Problem with translation of "Today"

We have an issue with this line :

https://github.com/asaglimbeni/django-datetime-widget/blob/master/datetimewidget/widgets.py#L118

Since the french word for "Today" is "Aujourd'hui", it has an apostrophe in it which breaks the widget.

We solved it doing that : TODAY = '"%s"'%_("Today")

Not sure if it's an acceptable fix for you. If yes, I could do a pull request or let you code it since I don't want to fork your project and keep everything in the same place. Please advise. Thanks for the great widget by the way.

cc @francisbissonnette

Unit Test?

I was working on #33 and then realized you don't have any unit test, yet. Don't you think it's high time we added some?

Editable text field?

Hi,

I'm trying to change the default behaviour of the field in order to manually change the date text, how can I achive this?

Not working on production site

I have been playing with the datetimewidget. It works fine on the "./manage runserver" site, but not on my apache server. It doesn't seem to be able to find
/static/css/datetimepicker.css or
/static/js/bootstrap-datetimepicker.js

It is as though /static is getting confused between the widget and the main django project, and only serving one set of files. Any advice on making it work properly?

Wrong behavior treating widget in form as a single field after last update

Hi there,
I'm using Django 1.7 and always keeping the widget updated.
Since the last update I'm getting a wrong behavior in displaying the widget in a form with several fields.

Specifically with the following code:

<form action="" method="POST"> {% csrf_token %} 
{% for field in form %}
        {{ field }}
 {% endfor %}
<input id="submit" type="submit" value="Submit"> </form>

I get this: http://i.imgur.com/ylGpheD.png

While the correct (and former) behavior:
http://i.imgur.com/uGulGTO.png
is working just adding the "safe" filter to {{ field }}:

<form action="" method="POST"> {% csrf_token %}     
    {% for field in form %}
        {{field|safe}}
    {% endfor %}
<input id="submit" type="submit" value="Submit"> </form>

or keeping the basic implementation:

<form action="" method="POST"> 
{% csrf_token %} 
{{ form.as_table }}
<input id="submit" type="submit" value="Submit"> </form>

Unluckily I am forced to treat the fields one by one to have some customization. Do you have any idea on how to fix this without being forced to use the "safe" filter?

Thanks for your help and work, regards.

Exception Value: must be string, not None

When rendering the template, the following error occurs:

Environment:


Request Method: POST
Request URL: http://localhost:8000/seeds/new

Django Version: 1.5.1
Python Version: 2.7.3
Installed Applications:
('django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.sites',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'django.contrib.admin',
 'south',
 'django_forms_bootstrap',
 'datetimewidget',
 'seedbank',
 'debug_toolbar')
Installed Middleware:
('django.middleware.common.CommonMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'debug_toolbar.middleware.DebugToolbarMiddleware')


Traceback:
File "/Users/nateaune/Dropbox/code/venvs/sim/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
  115.                         response = callback(request, *callback_args, **callback_kwargs)
File "/Users/nateaune/Dropbox/code/venvs/sim/lib/python2.7/site-packages/django/views/generic/base.py" in view
  68.             return self.dispatch(request, *args, **kwargs)
File "/Users/nateaune/Dropbox/code/venvs/sim/lib/python2.7/site-packages/django/views/generic/base.py" in dispatch
  86.         return handler(request, *args, **kwargs)
File "/Users/nateaune/Dropbox/code/venvs/sim/lib/python2.7/site-packages/django/views/generic/edit.py" in post
  199.         return super(BaseCreateView, self).post(request, *args, **kwargs)
File "/Users/nateaune/Dropbox/code/venvs/sim/lib/python2.7/site-packages/django/views/generic/edit.py" in post
  164.         if form.is_valid():
File "/Users/nateaune/Dropbox/code/venvs/sim/lib/python2.7/site-packages/django/forms/forms.py" in is_valid
  126.         return self.is_bound and not bool(self.errors)
File "/Users/nateaune/Dropbox/code/venvs/sim/lib/python2.7/site-packages/django/forms/forms.py" in _get_errors
  117.             self.full_clean()
File "/Users/nateaune/Dropbox/code/venvs/sim/lib/python2.7/site-packages/django/forms/forms.py" in full_clean
  272.         self._clean_fields()
File "/Users/nateaune/Dropbox/code/venvs/sim/lib/python2.7/site-packages/django/forms/forms.py" in _clean_fields
  281.             value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))
File "/Users/nateaune/Dropbox/code/venvs/sim/lib/python2.7/site-packages/datetimewidget/widgets.py" in value_from_datadict
  90.             D  = to_current_timezone(datetime.strptime(date_time[0], self.format))

Exception Type: TypeError at /seeds/new
Exception Value: must be string, not None

Option 'format' doesn't seem to work

As I understand the format option, it decides what the widget will fill into the field?

Currently it fills out 'yyyy-mm-dd hh:mm:ss', and no matter what I fill into format will change this.

Additionally README.md says the default behavior does not include seconds, but it does.

Widget chokes in testing..

Thanks so much for this plugin. It's working well on the front end. However, I'm finding this bug in testing. Seems to choke in this widget. I can't work out why. I've tried to work through what's happening but can't find the issue. Can you help? Thanks again!

The test adds an object using a date and stumbles in its attempt.

    response = self.client.post('/events/new/', {'name': 'Thingie', 
        'location': 'Wels', 'date': '2014-09-04 16:00:00.000000'})


ERROR: test_MyView (crewcal.tests.ResponseTest)
  ----------------------------------------------------------------------
  Traceback (most recent call last):
    File "/Users/methuselah/code/django/ssc/main/../crewcal/tests.py", line 56, in test_MyView
      'location': 'Well Street', 'date': '2014-09-04 16:00:00.000000'})
    File "/Users/methuselah/.virtualenvs/ssc/lib/python2.7/site-packages/django/test/client.py", line 449, in post
      response = super(Client, self).post(path, data=data, content_type=content_type, **extra)
    File "/Users/methuselah/.virtualenvs/ssc/lib/python2.7/site-packages/django/test/client.py", line 262, in post
      return self.request(**r)
    File "/Users/methuselah/.virtualenvs/ssc/lib/python2.7/site-packages/django/core/handlers/base.py", line 111, in get_response
      response = callback(request, *callback_args, **callback_kwargs)
    File "/Users/methuselah/.virtualenvs/ssc/lib/python2.7/site-packages/django/contrib/auth/decorators.py", line 20, in _wrapped_view
      return view_func(request, *args, **kwargs)
    File "/Users/methuselah/.virtualenvs/ssc/lib/python2.7/site-packages/django/contrib/auth/decorators.py", line 20, in _wrapped_view
      return view_func(request, *args, **kwargs)
    File "/Users/methuselah/code/django/ssc/main/../crewcal/views.py", line 118, in new_event
      if form.is_valid():
    File "/Users/methuselah/.virtualenvs/ssc/lib/python2.7/site-packages/django/forms/forms.py", line 124, in is_valid
      return self.is_bound and not bool(self.errors)
    File "/Users/methuselah/.virtualenvs/ssc/lib/python2.7/site-packages/django/forms/forms.py", line 115, in _get_errors
      self.full_clean()
    File "/Users/methuselah/.virtualenvs/ssc/lib/python2.7/site-packages/django/forms/forms.py", line 270, in full_clean
      self._clean_fields()
    File "/Users/methuselah/.virtualenvs/ssc/lib/python2.7/site-packages/django/forms/forms.py", line 281, in _clean_fields
      value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))
    File "/Users/methuselah/.virtualenvs/ssc/lib/python2.7/site-packages/datetimewidget/widgets.py", line 91, in value_from_datadict
      D = to_current_timezone(datetime.strptime(date_time[0], self.format))
  TypeError: must be string, not None

SplitDateTimeWidget

I think there should be a SplitDateTimeWidget.
Not sure who else would find this useful, I may be able to do this later, just thought I'd put it out there.

Uncaught Reference error: undefined is not a function

I have been trying to get the widget running but the it keeps giving the above error. Please help.
Form:

class BestQuoteQueryForm(forms.ModelForm):
class Meta:
model = BestQuoteQuery
fields = ('email', 'name', 'number', 'additional_requirement','enquiry_for_date','event_type','no_of_guests','event_timing_start','event_timing_end')
widgets = {
'event_timing_start':TimeWidget(),
'event_timing_end':TimeWidget(),
}

HTML

Occasion Time
   <div id="id_event_timing_start"  class="controls input-append date">
       <input id="id_event_timing_start" name="event_timing_start" readonly="" type="text" />
       <span class="add-on"><i class="icon-remove"></i></span>
       <span class="add-on"><i class="icon-th"></i></span>
   </div>
   <script type="text/javascript">
       $("#id_event_timing_start").datetimepicker({minView: 0,

maxView: 1,
autoclose: true,
startView: 1,
format: 'hh:ii'});
</script>






<script type="text/javascript">
$("#id_event_timing_end").datetimepicker({minView: 0,
maxView: 1,
autoclose: true,
startView: 1,
format: 'hh:ii'});
</script>

<scri[t src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>

<script src="/static/scripts/jquery.min.js"></script> <script src="/static/scripts/bootstrap.min.js"></script>"

DateTime range widget.

A specific widget that work with two datetime widget , the first one work like datetime-start and the second one like datetime-end that depend on what the first was selected.

This can work in two way:

  • with two specific datetimefield on form. ( to have start /end datetime)
  • with one datetime-field that count time range from first input to second input.

Maybe They can be two differente widget.
Suggestions are appreciated

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.