Giter Site home page Giter Site logo

ui-router-tabs's Introduction

UI Router Tabs

Leverages UI Bootstrap and UI Router to give you full-strength route-driven tabs in Angular.js.

Build Status Coverage Status     Gratipay

Example / Demo

Link

How to Install / Usage

  1. Install the plugin into your Angular.js project, manually or via bower install angular-ui-router-tabs

  2. Add ui.router.tabs as a new module dependency in your angular app.

  3. Define your routes in a hierarchy that makes sense for a tabbed layout, Eg:

    $stateProvider.state('user', {
      url:         '',
      controller: 'UserCtrl',
      templateUrl: 'example.html'
    }).state('user.settings', {
      url:         '/user/settings',
      templateUrl: 'user/settings.html'
    }).state('user.accounts', {
      url:         '/user/accounts',
      templateUrl: 'user/accounts.html'
    });
  1. Define your tabData (or similiar variable) in the root view controller of your tabs (ie. UserCtrl in the case above) Eg:
    $scope.tabData   = [
      {
        heading: 'Settings',
        route:   'user.settings'
      },
      {
        heading: 'Accounts',
        route:   'user.accounts',
        disable: true
      }
    ];

NOTE: You can also specify params and options to pass special parameters or options for the target route to UI Router, Eg:

    {
      heading: 'Accounts',
      route:   'user.accounts',
      params:  {
                 accountId: account.id
               },
      options: {}
    }
  1. Declare the following in your the parent HTML view template <tabs data="tabData" type="tabs"></tabs>.

Optional attributes for the <tabs> (which are passed on to the UI Bootstrap component) are:

  • type: [ 'tabs' | 'pills' ]
  • vertical: boolean
  • justified: boolean
  • class: string
  • templateUrl: <template url name>

NOTE: If you use a custom template, you may need to define a ui-view placeholder for the child content panes in the same HTML view template eg. <ui-view></ui-view>.

Tips

  • UI Bootstrap Tabs will not select a tab by default. If you want it to, specify the target sub-route when you show the tabs (ie. link the ui-view containing the tabs with the default (first) element as the sub-route example/#/user/settings in the example.)
  • You can override the default directive template by specifying template-url="my_template.html" on the <tabs> element.
  • You can enable / disable tabs by specifying disable: true in the tabData (can be dynamically set).
  • You can use <tab-heading> in a custom directive template to add any HTML into the tab title (eg. icons)
  • You can update the tabData variable dynamically, if you want to.
  • You can move the <tabs> tag around to wherever you want the tab listing to appear. (left-positioned is the best spot to enable responsive design.).
  • Each tab will have a default class of tab, an active tab will have the active class.

Running Locally

  1. Checkout git repository locally: git clone [email protected]:rpocklin/ui-router-tabs.git
  2. npm install
  3. bower install
  4. grunt serve
  5. View http://localhost:9000/example/ in your browser to see the example.

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Added some feature') - please consider adding tests!
  4. Push to the branch (git push origin my-new-feature)
  5. Run grunt and ensure there are no errors.
  6. Create a new Pull Request

History

  • 2.0.2 Fixed invalid <ui-view> placement in default template.
  • 2.0.1 Fixed invalid html in default template (missing <div>).
  • 2.0.0 Added class and template-url attributes on uib-tab and began using <uib-tab-heading> tag.
  • 1.8.0 Added inline template by default (as requested) and allowed customer classes parameter.
  • 1.7.0 Added uib prefix for UI Bootstrap elements (as per v0.14.0). See #47.
    Upgraded angular-bootstrap to v14.0.
  • 1.6.0 Renamed disabled attribute to disable in line with UI Bootstrap <tab>. See #39.
  • 1.5.1 Removed bower_components from repository. See #40.
  • 1.5.0 Bumped angular-bootstrap dependency to v0.13.0 (fixes default tab being auto-selected).
  • 1.4.3 Added handling of $stateChangeCancel, $stateChangeError and $stateNotFound to reset active tab.
  • 1.4.2 Added feature to update tabs if state change event is cancelled. See #19.
  • 1.4.1 Bumped angular-bootstrap dependency to v0.12.1.
  • 1.4.0 Removed default $state.go(..) route option, added disabled option and updated jsbeautifier. See #16.
  • 1.3.0 Improved state equality checking to include params and options.
  • 1.2.0 Prevented reload of current state again. See #11.
  • 1.1.4 Added support for strict-di mode.
  • 1.1.3 Fixed tab switching when using ngTouch. See #2.
  • 1.1.2 Added $stateChangeSuccess watcher to update parent tab(s) when using
    ui-sref or $state.go(). See #1.
  • 1.1.0 Added nested tab support (tabs within tabs)
  • 1.0.0 Initial release

License

Released under the MIT License. See the LICENSE file for further details.

ui-router-tabs's People

Contributors

alexilyaev avatar cesarandreu avatar glsee avatar kravchina avatar rpocklin avatar stefanotorresi avatar tlvince avatar tmont avatar wesleycho 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

ui-router-tabs's Issues

Minor version bump for ignored test file?

Would you please do a new release with the test file ignored?

I check-in my bower_components folder into my project, so I like it when projects have as few files as possible.

Tab contents empty following file-rev/usemin minification

I have an application that is working fine ... until I attempt to file-rev and minimize it. It makes use of tabs nested within the main view as follows:

detail.html contains

<div class="jobDetail" style="width: 100%; overflow: auto;">
    <tabs data="tabData" type="tabs" template-url="detailTabs.html"/>
    <ui-view></ui-view> <!-- ="detailTabs" -->
</div>

details.html contains the following:

<tabset class="tab-container" type="{{::type}}" vertical="{{::vertical}}" justified="{{::justified}}">
    <tab class="tab" ng-repeat="tab in ::tabs" active="tab.active" disabled="tab.disabled" ng-click="go(tab)">
        <tab-heading>
            {{::tab.heading}}
            <span ng-if="tab.actionCount" class="action">{{tab.actionCount}}</span>
            <span ng-if="tab.warningCount" class="problem">{{tab.warningCount}}</span>
        </tab-heading>
    </tab>
</tabset>

This works perfectly and the tabs behave and display the contents associated with the appropriate states when the code has not yet been minimized.

However, once we minimize via grunt file-rev and usemin, the tab contents are no longer displayed with the above configuration. It appears as if the is not located or not replaced for some reason (yet I have verified and confirmed its existence in the minimized html).

To add to the mystery, if I relocate the from detail.html and add it as the last line in detailTabs.html, the contents are then displayed - even following grunt usemin! Surprising at best - I stumbled upon this while trying to isolate the issue However, this does not following the documentation examples and causes additional problems downstream as it appears to change where the ui-router current state is set and breaks (or would at least require changes to) logic depending upon it. As such, this does not appear like a solution at all, just an interesting quirk result.

I am using version 1.5.0 at the moment with this app.

Unfortunately, as this is file-rev/minimization specific, I don't believe a plunker will be useful.

Are there known issues related to using angular-ui-router-tabs with grunt file-rev and usemin minimized html/code? Are there specific changes or workarounds that I should employ to make this combination work as successfully as it does prior to minimization?

TIA!

Stopping tab change

I have a scenario in which I am listening to the $stateChangeStart. In this case, I am verifying if the user has an unsaved changes and presenting a confirmation dialog to allow then to cancel (stay on the present tab and save the data) or continue (ignore their changes). All is working well with one important exception: event though I am calling event.preventDefault in response to the $stateChangeStart event, the tab is still be moved (i.e. the active tab class still changes) to the new tab the user clicked on. Is there a way to get ui-router-tabs to behave correctly in this situation (i.e. if the event is cancelled with preventDefault() then stay on present tab)? I have not seen anything in the docs or a quick review of the code, so would appreciate your assistance please.

child/nested tab targeting can lead to loss of parent tab highlighiting

I have a set of tabs with one tab containing another set of child/nested tabs. In my application, the child tabs can also be disabled via the associated attribute (unfortunately, do to other constraints preventing me from upgrading bootstrap in my application, I am not able to upgrade beyond v1.5 of ui-router-tabs at present).

I have a plunker demonstrating the issue at: http://plnkr.co/edit/UUcHHxlhPBbaWrMO6Srb?p=preview

In the plunker, Tab 3 is the one that has the child tabs and demonstrates the issue. The first child Tab (child 1) is disabled. In order to avoid landing the user that clicks on Tab 3 on a blank Tab, I set the Tab 3 route to 'main.tab3.child2' to target the first enabled tab and land them on the Child 2 tab instead. This works correctly and does maintain the correct Tab 3 parent tab highlighted.

However, if the user subsequently clicks on Child 3, the Tab 3 parent highlighting is lost. This is the issue I am trying to avoid (loss of parent tab active state highlighting).

If the Tab 3 route is only set to 'main.tab3', then the parent highlighting is not lost. However, the user will land on a blank Child 1 with it highlighted even though it is disabled.

Is there a workaround or better approach to ensure the user does not land on the blank Child 1/disabled tab and to also maintain the correct parent tab highlighting?

Thank you in advance for your help.

passing function as data

I pass in a function to the data attribute on tabs like this

<tabs data="tabs()" type="tabs"></tabs>

it renders the tabs but i can not select and i also get this error on the console

Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting! Watchers fired in the last 5 iterations: [[{"msg":"fn: regularInterceptedExpression","newVal":[{"heading":"Folders",........

Required to click on tab twice to get class='active'

First go around, used this directive, and it appears to be changing the URL when clicking each tab. Unfrotunately the active tab state isn't working. URL Changes after first click, tab becomes active class after second click.

Any ideas?

sibling tab-content should be hidden or removed or transclude

After implementing tabs directive, there is a <div class="tab-content"> sibling to <ul class="nav nav-tabs" />

screen shot 2015-05-05 at 2 01 20 pm

You can see that my ui-view has a tab-content class on it as well to fall in line with angular-ui. Unfortunately, this creates two tab-content classes which produces some unexpected UI with empty spacing / padding from the former.

If the functionality is required, then this could just be hidden. Otherwise if it doesn't matter, we can remove it. If possible, it would be cool to replace the .tab-content with transclude.. EG: ui-view.

<tabs ...>
   <ui-view></ui-view>
</tabs>

Tab heading Icon

Hi

How do we add heading icon with tab data...???

$scope.tabData = [
{
heading: "Settings fdf",
route: 'user.settings'
},
{
heading: 'Accounts',
route: 'user.accounts'
}
];

How to start controller only when tab is changed

I have got the code :

.state('metric-tabs', {
                parent: 'metric-page',
                'abstract': true,
                views: {

                    'actions': {
                        templateUrl: 'scripts/app/admin/metrics/metrics-actions.html'

                    },
                    'content': {
                        //controller: 'MetricsTabController',
                        //controllerAs: 'vm',
                        templateUrl: 'scripts/app/admin/metrics/metrics.html'

                    }
                }
            })
           .state('metrics', {
                parent: 'metric-tabs',
                url: '/metrics/:serverId',
                controller: 'MetricsTabController',
                controllerAs: 'vm',
                templateUrl: 'scripts/app/admin/metrics/metrics-tab.html'

            });

and metrics.html

<div class="tabs-container">
    <tabs data="vmPage.tabs" type="tabs"></tabs>
</div>

Is there possitble to run controller only when tab is change ?
If i put controller into 'metrics-tab.html'' its run more than one ...
I have got dynamic tabs so i dont now how many tabs i have the tabs name i get from server, and when i change my tab i also run ajax http request.

wher i need put my tab controller in state 'metrics' or in views 'content'?

Default tab or route

I've read this paragraph a few times - looked through the sample code but can not understand what this is telling me to do.....

UI Bootstrap Tabs will not select a tab by default. If you want it to, specify the target sub-route when you show the tabs (ie. link the ui-view containing the tabs with the default (first) element as the sub-route example/#/user/settings in the example.)

Would it be possible to provide a small sample code?

Double initialisation of child state controller

Hi there!

I configured the two child states in the router passing the name of the controller. When the view loads on the page with tabs the controller is initialised twice. Did you also encounter this behaviour?

Thanks

Can't get it to work at all

Hi there,

I hope you could help me out, because I just can't get this to work (I'm inexperienced with Angular).

My config is defined like this:

$stateProvider.state('articledetail', {
                url: 'articledetail/:article',
                templateUrl: '/articledetail/articleDetail.html',
                controller: 'articleDetailController',
                controllerAs: 'vm'
            }).state('articledetail.tab1', {
                url: '/tab1',
                templateUrl: '/articledetail/tab1.html'
            }).state('articledetail.tab2', {
                url: '/tab2',
                templateUrl: '/articledetail/tab2.html'
            }).state('articledetail.tab13', {
                url: '/tab3',
                templateUrl: '/articledetail/tab3.html'
            }).state('articledetail.tab4', {
                url: '/tab4',
                templateUrl: '/articledetail/tab4.html'
            });

            $stateProvider.state('error', {
                url: '/error',
                templateUrl: '/error/error.html'
            })

I'm moving to my articledetail state:

$state.go('articledetail', { 'article': article.itemNumber });

In the controller (articleDetaillController), I'm defining the tabs:

        vm.tabData   = [
            {
                heading: 'Algemene info',
                route:   'articledetail.tab1'
            },
            {
                heading: 'Info 2',
                route:   'articledetail.tab2'
            },
            {
                heading: 'Info 3',
                route:   'articledetail.tab3'
            },
            {
                heading: 'Info 4',
                route:   'articledetail.tab4'
            }
        ];

My articledetail.html:

<div role="tabpanel" class="col-xs-12">
    <tabs data="vm.tabData" type="tabs" />
    <form class="form-horizontal" name="editForm" novalidate>
        <div class="tab-content col-xs-7">
                <div ui-view></div>

                <br />

            <div class="col-xs-7">
                <button class="btn btn-primary pull-right" type="submit">Artikelgegevens aanpassen</button>
            </div>
        </div>
    </form>
</div>

The 4 tab html's contain content that should be loaded at the place of ui-view

It just doesn't work, that's all I can say. I'm not getting ANY error at all, the tabs are just not displayed (and I've confirmed vm.tabData exists in the view) and no tabs are loaded.

What am I doing wrong here?

How to select the first tab on init?

Hi, I'm trying to make the first tab selected by default when the parent view loads.

Here's my setup:

.state('admin.reports.account', {
    url: '/account',
    controller: 'AccountReportController',
    controllerAs: 'reports',
    template: accountView,
.state('admin.reports.account.groups', {
    url: '/groups',
    template: accountGroupsListView
})
.state('admin.reports.account.meetings', {
    url: '/meetings',
    template: accountMeetingsListView
})
this.tabsData = [
    {
        heading: 'Groups',
        route: 'admin.reports.account.groups',
        active: true
    },
    {
        heading: 'Meetings',
        route: 'admin.reports.account.meetings'
    }
];
<tabs data="reports.tabsData" type="tabs"></tabs>

The tabs themselves work correctly, just that setting active: true doesn't do anything.
Checking the source code, this is because $scope.update_tabs resets the active property based on $scope.active, but I want to trigger the selection of that specific tab.

Looking at the underlying ui-tabs docs, this should be possible:
https://angular-ui.github.io/bootstrap/#/tabs

And I didn't understand the first tip in the README, the referenced example does not select the first tab automatically.

Dynamically setting tabData

I am trying to dynamically set the disabled state of a tab, but cannot get anything to work.

Do I need to notify the instance of tabs that the tabData has changed?

Actually this works.

Can't Get Dynamic Tab Data to Update

I've enjoyed using your ui-router-tabs project, and have recently tried implementing a custom template with a heading icon that will be toggled based on a value I defined in options that is bound to service data representing the validation state of a form.

I'm receiving the changing Boolean value in my tabs controller, but it's not being "pushed" down into the corresponding tabs. If I hard-code the value, it will display as I expect, it's just not changing in response to the service data change.

I'm fairly new to Angular so I may well be doing something wrong or against the spirit of your meaning of dynamic tab data. I have prepared a Plunk http://plnkr.co/edit/iefvwcffSZmpfy83NGde?p=preview that demonstrates the issue.

On View 1, enter a valid email, which will make the form validate and the validation state will bubble up to the parent controller. I expect that the "ban-circle" (false) would toggle to a check mark (true, see view 2's heading), but it does not. Any suggestions about how to make this work would be much appreciated.

Upgraded to 1.3.0 and tabs no longer work when clicked

I recently upgraded from 1.2.0 to 1.3.0 and my tabs stopped working (i.e. I cannot move from the first tab to any other tabs by clicking on them). No other changes were made in combination with this. There are no errors/warning/etc. in the console. Verified that rolling back to 1.2.0 resolved the issue.

Any ideas what has changed with 1.3.0 that may be causing this? FYI, I am using angular version 1.4.0.

Example2 is broken

Could not resolve 'undefined' from state 'ones' when clicking the Secondtab.

Can't have multiple routes highlight same tab

I click a "users" tab and get a list of users. I click on a user to load the edit view, but I would like the "users" tab to remain active.

Perhaps the tabData route value could be an array? If the current $state is any of those, then highlight the corresponding tab.

Another solution could be to allow the tabData route to be an abstract state, and any of the child states would highlight the corresponding tab. When the tab is clicked, go to the first child state.

I haven't tested either of those solutions yet.

disabled not working

I looked it and there's a conflict between the code and the docs.
In the docs the key for disabling is 'disabled' and in the code it's 'disable'.
The fix is 5 minutes, I'm willing to fix it and create a PR. Just need to know which one should it be, disable or disabled.

Feature request

Add extra data to the tab like icon/counter/label (numbers) by callback.

Selecting a tab on load

Great jobs works really well, one thing though given your example:

<div class="row">
    <div class="col-md-12">
        <tabs data="tabData" type="tabs"></tabs>
    </div>

    <div class="col-md-12">
        <ui-view autoscroll>  </ui-view>
    </div>
</div>

How would one select a tab by default? You say: "link the ui-view containing the tabs with the default (first) element as the sub-route example/#/user/settings in the example", In the Tips section, but I'm not sure how to apply this in practice. My '/' shows the tabs, and '/create' is my first tab that I'd like to select. Any help would be awesome.

The location of ui-view should be inside of uib-tab

Since ui-router-tabs expects ui-view to be defined outside of uib-tab, it behaves weirdly when you css expects your tab contents to be inside of uib-tab. I think the more natural default template is:

<div>
  <uib-tabset class="tab-container" type="{{type}}" vertical="{{vertical}}" justified="{{justified}}">
    <uib-tab class="tab" ng-repeat="tab in tabs" heading="{{tab.heading}}" active="tab.active" disable="tab.disable" ng-click="go(tab)">
      <ui-view></ui-view>
    </uib-tab>
  </uib-tabset>
</div>

This way you don't need to specify ui-view explicitly, and everything is in its expected location.

Maybe this was intentional to give more flexibility? I'm currently using the template above for my application. Either way, let me know!

Can't access the options defined in tabData in either controller or ui router

First of all thank you for creating UI Router tabs library. It is very helpful and I am using for a sample project while learning Angular JS.
I am trying to use the options parameter in tabData as mentioned in the Readme.md like below:
{
heading: 'Accounts',
route: 'user.accounts',
params: {
accountId: account.id
},
options: {}
}
I am passing custom data in this options parameter and same I want to use in the respective controller. But I am not successful to access the parameters either in the ui router or controller. I am able to access the params in router and passing it to the controller using resolve parameter.
I followed the same resolve parameter in ui router for the options parameter also, but with no luck.
I would like to inject into the data parameter of ui router so that I can access with $state.current.data.myVariable (or) is there any way to access in the controller with selected tab options.

Use of tab-heading

Hi, you mention in the guide about using in a custom template directive to control the tab heading itself. I am unsure how to go about doing this, can you provide an example?

Does not work when template is in templateCache

If I put the template in a cache.js file, clicking on the tabs does nothing

`







`

The same when referred to in the ui-router's templateUrl with the full path of the html then it works, but not when the templateUrl contains the templateCache's key

Clicking active tab makes tab inactive

As per #7, I think this is unexpected behaviour as it differs to ui-bootstrap's behaviour; in ui-bootstrap, you cannot click a tab that's already active.

This happens because ui-bootstrap's behaviour is effectively overridden via the use of ui-sref.

Ability to 'properly' have <ui-view></ui-view> inside tab-content

Following issue #24 is there a way (custom template maybe) to have the <div class="tab-content"></div> be filled automatically by defining a inside ??

examples like:

<div class="row">
      <div class="col-md-12">
        <div class="tab-container">
          <tabs data="tabData" type="tabs"></tabs>
          <div class="tab-content">
            <div ui-view></div>
          </div>
        </div>
      </div>
    </div>

wouldn't do anything. I wouldn't want to hide the tab content since it is already there by the template.

Example link not working

Tab selection on refresh

Hello,

I currently use ui-bootstrap ~1.2 and I realized that tab activation is controlled by the active attribute of uib-tabset that takes the index of the selected tab instead of the active attribute of uib-tab.
Put a value (a boolean) on the last one has no effect.

Can you confirm this, or I'm wrong ?

Disabled Tab update reflects incorrect tab

If you click on a tab which has been disabled via the disabled attribute, the tab contents do not update as expected. However the visual representation of which tab is selected incorrectly changes to the tab which has been disabled. I have tried this in both the 1.4.2 and 1.4.3 versions with the same result.

Multiple tabs with the same state

Hi,

Is it possible to have the same route state with multiple data sets which share the same state?

ex: /users/edit/id_1 and /users/edit/id_2
id_1 and id_2 are parameters, but with the same state, and both in a different tab.

Kind regards,
Martijn W

if the tabs directive is used in index.html with a custom template, the route may be lost on page reload. (was route is lost on reload when using custom tabs template)

When I use the following custom template on a page with two tabs, adding an id field to each tab in the tab data, reloading the page always returns the user to the default tab. This behaviour doesn't happen if I make the same change to the default template right in ui-router-tabs.js, so it appears to be a custom template issue (the template is just the default with an id added):

Conditional routing within a tab?

Is it possible have conditional routing within your tab data? Something like:

$scope.tabData = [
{
heading: 'MyTab',
route: myService.isDetailMode() ? 'main.details' : 'main.overview
}

The above does not appear to generate any errors, but toggling toggle the service controlled value also does not produce the desired dynamic switch between states.

Is there a better way to achieve this? Basically, I'm hoping to have a tab's contents dynamically adapt in response to service controlled values.

TIA!

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.