bvaughn / react-window

React components for efficiently rendering large lists and tabular data
https://react-window.now.sh/
MIT License
15.9k stars 787 forks source link

Using html table element #60

Closed einarq closed 6 years ago

einarq commented 6 years ago

Do you have an example of using this with tables? I'm trying to get it working but I have a strong suspicion that it either doesn't work, or that I'm doing something very wrong. I've set the outerTagName to "table" and the innerTagName to "tbody", but I don't get any scrolling.

Here is my code, not sure if it helps (items is a list of objects):

 <List
            outerRef={this._list}
            outerTagName="table"
            innerTagName="tbody"
            height={300}
            itemData={items}
            itemSize={() => 30}
            itemCount={items.length}
            itemKey={item => item.uniqueId}>
            {({index, style, data}) => {
              return (
                <tr style={style} key={index}>
                  <td>Item {index}</td>
                </tr>
              );
            }}
          </List>
bvaughn commented 6 years ago

I don't think this will really work. To my knowledge, HTMLTableElement doesn't really support overflow in the way a windowing component would need. You could change the style to display: block but I still don't think it would quite work right. (Here is an example.)

Why do you need a table? I think you can achieve the same column layout with inline blocks or flex layouts.

Couple of additional things:

einarq commented 6 years ago

Thanks for the quick reply. We have already discussed rewriting it to divs, but since this is for an existing rather large component we just wanted to make sure before starting that rewrite. I saw some other comments about rc-table, so thought that maybe it was supposed to work. Anyway, don’t mind the rewrite, it should be worth it I think.

I got React warnings about keys without the key on the row, which was also confusing to me considering I’m setting an itemKey, so not sure what’s going on there.

Thanks

Einar

On 21 Sep 2018, at 16:52, Brian Vaughn notifications@github.com wrote:

I don't think this will really work. To my knowledge, HTMLTableElement doesn't really support overflow in the way a windowing component would need. You could change the style to display: block but I still don't think it would quite work right.

Why do you need a table? I think you can achieve the same column layout with inline blocks or flex layouts.

Couple of additional things:

You aren't specifying a require parameter width to List You don't need to add the key to your rows itemSize can just be 30 rather than () => 30 (it will perform slightly better) — You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or mute the thread.

bvaughn commented 6 years ago

I got React warnings about keys without the key on the row, which was also confusing to me considering I’m setting an itemKey, so not sure what’s going on there.

This is not expected. Can you share a repro case with me (via Code Sandbox)?

bvaughn commented 6 years ago

Ooh, sorry. I should add that this would only be expected if your itemKey function returned undefined for some items– in which case the fix would need to be to that function.

BlaineBradbury commented 5 years ago

@bvaughn I'm not finding anything specific about overflow support being a limiting factor. Curiously, I'd like to know what that might be. I certainly get that supporting the core functionality for both might be tedious, but it does only look like the base list element is all that is out of the implementor's choice at the moment. Speaking for myself and anyone who might be using react-window with fixed header scenarios, it would be nice to gain the inherent tabular support built into table layouts. Using display: table does take "some" dev overhead and is a one-off layout for surrounding applications who might incidentally be built using tables. I could always tweak overflow or other properties via css (I'm doing that in a current implementation anyway). Is an elementType prop out of the question?

bvaughn commented 5 years ago

@bvaughn I'm not finding anything specific about overflow support being a limiting factor.

Maybe I didn't use the best phrasing– but if you look at the Sandbox I linked to (rrn61wkzwm), you'll see the unexpected behavior.

Here is another example that's just HTML: lx65871p69

The HTMLSelectElement (the <tbody>) ignores styles like height and overflow – making it useless for windowing. You can "fix" this by changing its display mode (display: block) but this defeats the purpose of using an HTMLTableElement because it breaks the column sizing behavior.

That column sizing behavior is broken to begin with for the windowing use case anyway, because the size is dependent on the content in the columns (which would change as a user scrolled).

but it does only look like the base list element is all that is out of the implementor's choice at the moment...Is an elementType prop out of the question?

You can already specify the tag type if you really want to (2j0z718mwy) although I don't see what it gains you.

Speaking for myself and anyone who might be using react-window with fixed header scenarios, it would be nice to gain the inherent tabular support built into table layouts.

Using an HTMLTableElement would be problematic for reasons I explained above. If you want a tabular/grid layout with a fixed header, you can accomplish this using one of the regular list components though: pk78pvwnkx

sompylasar commented 5 years ago

Why do you need a table? I think you can achieve the same column layout with inline blocks or flex layouts.

Maybe a table structure is required for some accessibility (like, better screen reading compared to non-semantic divs)? I'm guessing here.

In this case I would go with overriding the CSS display style and any other styles that are inherent to table elements.

My experience building a complex table component (with fixed/pinned headings from top and left, convoluted colspan/rowspan structure, and a data model to describe the structure behind it) about nine years ago (then we had no React, no accessibility concerns, and as far as I remember no virtualization) is that my colleague who was responsible for this component tried implementing it in proper table elements, struggled with forcing the layout to behave in certain ways, and then decided to implement the table layout in pure JavaScript from absolutely positioned and sized divs. That solution worked perfectly: no weird layout jumps, smooth scrolling (not per-row/per-column), etc.

bvaughn commented 5 years ago

Maybe a table structure is required for some accessibility (like, better screen reading compared to non-semantic divs)? I'm guessing here.

Aria roles can be used for this 😄

BlaineBradbury commented 5 years ago

Super thorough, thank you. You just saved me going down the rabbit hole to attempt a prototype that would solve one problem only to create others.

lipoolock commented 5 years ago

Hi I tried to find an existing thread instead of creating a new one. I hope I am in the good place...

Is there a way to have a sort of "colspan" to merge two cells for FixedSizeGrid (would probably make more sense in my context) ? This question relies on another discussion started here, but to make more sense I prefer to post here.

bvaughn commented 5 years ago

Is there a way to have a sort of "colspan" to merge two cells for FixedSizeGrid (would probably make more sense in my context) ?

No. This is not supported.

pupudu commented 5 years ago

@einarq @BlaineBradbury @sompylasar In case you are still interested, I managed to get windowing work with table tags. In-fact, I ended up creating a library wrapping react-window. You can see a live demo here: https://window-table.netlify.com/

The reason why I wanted the table tags was mainly for styling. Styling a regular html table is pretty easy with tw-bootstrap, and hence I wanted to do the same with a windowed table.

I am tempted to tag and ask Brian, about what he thinks about this implementation(Since he mentioned that html table tags would not work). But he's already helped me enough. So I'll leave it to you guys.

Thank you.

bvaughn commented 5 years ago

That's an interesting approach @pupudu. I don't know if there would be any accessibility concerns for having separate <table> tags for the headers and rows, but neat idea otherwise.

linonetwo commented 5 years ago

I'm trying to use react-datasheet with react-window, it basically works:


function sheetRenderer(props) {
  const Row = ({ index, style }) => (
    React.cloneElement(props.children[index], { style })
  );
  return (
    <table className={props.className}>
        <tbody>
          <FixedSizeList
              height={150}
              itemCount={1000}
              itemSize={35}
              width={300}
          >
            {Row}
          </FixedSizeList>
        </tbody>
    </table>
  )
}

export default function EntityTable(props: IEntityTableProps) {
  const initialGrid = useMemo(() => {
    return getTableGridFromCSV(props.entityListCSV);
  }, [props.entityListCSV]);
  const [modifiedGrid, updateModifiedGrid] = useImmer(initialGrid);
  return (
    <ReactDataSheet
      data={modifiedGrid}
      sheetRenderer={sheetRenderer}
      valueRenderer={cell => cell.value}
      onCellsChanged={changes => {
        updateModifiedGrid(draft => {
          changes.forEach(({ cell, row, col, value }) => {
            draft[row][col].value = value || '';
          });
        });
      }}
    />
  );
}

function getTableGridFromCSV(csv: string) {
  return csv.split('\n').map(row =>
    row.split(',').map((cell, index) => {
      if (index === 0) {
        return {
          value: cell,
          forceComponent: true,
          component: <button onClick={() => console.log(cell)}>{cell}</button>,
        };
      }
      if (index === 2) {
        return {
          value: cell,
        };
      }
      return {
        value: cell,
        component: <span>{cell}</span>,
      };
    }),
  );
}

It renders, the only problem is Warning: validateDOMNesting(...): <tr> cannot appear as a child of <div>. index.js:1437 Warning: validateDOMNesting(...): <div> cannot appear as a child of <tbody>.

simkessy commented 4 years ago

Hey, I'm trying out this with React-Table and noticing I have to use divs instead of table elements. Problem with this is that styling libraries like material/bootstrap rely on those elements. So it's a lot more work to change my table schema to divs instead of table elements. Is it possible at all to use table elements to diffs or do I have to create my own styling now?

pupudu commented 4 years ago

@simkessy Unless you have noticed already, you should checkout window-table. It allows using html table tags allowing us to reuse existing styles. Have to admit that the table is not as advanced as react-table though. https://window-table.netlify.com/

jamesmfriedman commented 4 years ago

@pupudu I applaud your open source efforts and looked through your code extensively before deciding to try to tackle this on my own. I just wanted the super straightforward thing other people were looking for: this library but with table elements.

Turns out I was able to pull this off with a very small bit of code, and a lot of creativity. The code is simple enough that anyone should be able to copy / paste and extend to their liking. @bvaughn after figuring out the how, this would be pretty trivial to add to the library if you want, but also pretty trivial to override if you know how.

The short of it:

Working Code Sandbox: https://codesandbox.io/s/react-window-with-table-elements-d861o

Code for reference

import React from 'react'
import { useState, useRef, useContext } from 'react'
import { FixedSizeList, FixedSizeListProps } from 'react-window'
import { render } from 'react-dom'

/** Context for cross component communication */
const VirtualTableContext = React.createContext<{
  top: number
  setTop: (top: number) => void
  header: React.ReactNode
  footer: React.ReactNode
}>({
  top: 0,
  setTop: (value: number) => {},
  header: <></>,
  footer: <></>,
})

/** The virtual table. It basically accepts all of the same params as the original FixedSizeList.*/
function VirtualTable({
  row,
  header,
  footer,
  ...rest
}: {
  header?: React.ReactNode
  footer?: React.ReactNode
  row: FixedSizeListProps['children']
} & Omit<FixedSizeListProps, 'children' | 'innerElementType'>) {
  const listRef = useRef<FixedSizeList | null>()
  const [top, setTop] = useState(0)

  return (
    <VirtualTableContext.Provider value={{ top, setTop, header, footer }}>
      <FixedSizeList
        {...rest}
        innerElementType={Inner}
        onItemsRendered={props => {
          const style =
            listRef.current &&
            // @ts-ignore private method access
            listRef.current._getItemStyle(props.overscanStartIndex)
          setTop((style && style.top) || 0)

          // Call the original callback
          rest.onItemsRendered && rest.onItemsRendered(props)
        }}
        ref={el => (listRef.current = el)}
      >
        {row}
      </FixedSizeList>
    </VirtualTableContext.Provider>
  )
}

/** The Row component. This should be a table row, and noted that we don't use the style that regular `react-window` examples pass in.*/
function Row({ index }: { index: number }) {
  return (
    <tr>
      {/** Make sure your table rows are the same height as what you passed into the list... */}
      <td style={{ height: '36px' }}>Row {index}</td>
      <td>Col 2</td>
      <td>Col 3</td>
      <td>Col 4</td>
    </tr>
  )
}

/**
 * The Inner component of the virtual list. This is the "Magic".
 * Capture what would have been the top elements position and apply it to the table.
 * Other than that, render an optional header and footer.
 **/
const Inner = React.forwardRef<HTMLDivElement, React.HTMLProps<HTMLDivElement>>(
  function Inner({ children, ...rest }, ref) {
    const { header, footer, top } = useContext(VirtualTableContext)
    return (
      <div {...rest} ref={ref}>
        <table style={{ top, position: 'absolute', width: '100%' }}>
          {header}
          <tbody>{children}</tbody>
          {footer}
        </table>
      </div>
    )
  }
)

/**
 * Render Our Example
 **/
render(
  <VirtualTable
    height={300}
    width="100%"
    itemCount={1000}
    itemSize={36}
    header={
      <thead>
        <tr>
          <th>Index</th>
          <th>Header 2</th>
          <th>Header 3</th>
          <th>Header 4</th>
        </tr>
      </thead>
    }
    row={Row}
    footer={
      <tfoot>
        <tr>
          <td>Footer 1</td>
          <td>Footer 2</td>
          <td>Footer 3</td>
          <td>Footer 4</td>
        </tr>
      </tfoot>
    }
  />,
  document.querySelector('main')
)
pupudu commented 4 years ago

@jamesmfriedman Love the approach. Really interesting idea for using Context to achieve this. I like the fact that you only render one table, unlike in my approach where I render two, one for the header and one for the body. This has caused a lot of confusion(didn't see that coming tbh) in window-table users.

I'll try to use these ideas in window-table if you don't mind. I think the biggest challenge would be figuring out how to auto-size the rows based on the content (which was the biggest challenge of windo-table at least).

Meemaw commented 4 years ago

@jamesmfriedman that looks very promising. @bvaughn do you have any concerns about this approach?

marink commented 4 years ago

@jamesmfriedman it seems like the header scrolls up together with the content. Is it possible to make it sticky?

jamesmfriedman commented 4 years ago

It is in fact possible, and not specific to this implementation. Just do some googling around sticky headers with HTML table elements. I vaguely recall the way to do this is actually to make the TH element position sticky.

JCofman commented 4 years ago

@jamesmfriedman thanks a lot for your example 👍 it helped a lot @marink here is an example for sticky headers https://codesandbox.io/s/react-window-with-table-elements-jj70e you need to add style={{ position: 'sticky', top: 0 }}> to the th tags

olafur164 commented 4 years ago

@jamesmfriedman Thanks a lot for the example. I'm gonna look into using it. But I think using top:0 and position sticky instead of recalculating top and having position absolute on the table element would be the way to go. Because if your using position sticky to get sticky headers on the th elements then everything gets fucked up on fast scroll.

So line 79 would be <table style={{ top: 0, position: 'sticky', width: '100%' }}>

That also fixes the scroll issue that is if you continue scrolling when your at the bottom.

christopher-francisco commented 4 years ago

Another good reason for using HTML tables is supporting IE11. I'm using FixedSizeList and then styling it with CSS-grid. However when you need to add other features like responsive columns, columns with different sizes, etc, and make it all work together with IE11 you end up with massive amounts of code. Whereas HTML tables works by default with no code.

ThiefMaster commented 4 years ago

IE11 is not something you should be supporting anymore :)

pupudu commented 4 years ago

Every single FE developer wants death to IE11. But unfortunately, there are companies/people stuck with it, unable to make the move due to reasons we can't even imagine. Hopefully, it's only a very few years ahead in time. Until that, we will need to support IE11, whether we like it or not.

It was a hard pill to swallow for me as well.

ptimson commented 4 years ago

@olafur164 thanks for your fix for sticky headers not breaking on fast scroll. Do you know if there's a way to keep the "sticky" appearance as now it scrolls a row at a time as oppose to smoothly?

mackankowski commented 4 years ago

Let me share my experience with react-virtualized (even it's react-window issues page) and some material UI library called material-table where the same issue appear (combination table elements with virtualization): https://github.com/mbrn/material-table/issues/891#issuecomment-681986647. There're still some issues like styling problems and validateDOMNesting(...) warning.

DevAKS-Yara commented 4 years ago

@jamesmfriedman thanks a lot for your example 👍 it helped a lot @marink here is an example for sticky headers. you need to add style={{ position: 'sticky', top: 0 }}> to the th tags

Hey @JCofman, I tried your CSS fix but it is not working for me. Here's the code sandbox example - https://codesandbox.io/s/react-window-with-table-elements-forked-huti6?file=/src/index.tsx:514-542

There are two issues -

  1. header is not sticking on the top in spite of having styles in place.
  2. header is flashing/flickering while scrolling heavily towards up direction. [Steps to reproduce - scroll 50% down then do fast scroll up and observe the header movement ].

Thanks in advance :)

Rendez commented 3 years ago

@jamesmfriedman Love the approach. Really interesting idea for using Context to achieve this. I like the fact that you only render one table, unlike in my approach where I render two, one for the header and one for the body. This has caused a lot of confusion(didn't see that coming tbh) in window-table users.

I'll try to use these ideas in window-table if you don't mind. I think the biggest challenge would be figuring out how to auto-size the rows based on the content (which was the biggest challenge of windo-table at least).

I ended up finding a very similar solution because I'm using display: grid with display: contents for the rows, so basically adheres to the constraint of table > tr elements.

You used context + refs to call an internal method, however, this is totally unnecessary since the same can be accomplished by looking up the style.top value of the first child:

const Inner = React.forwardRef<HTMLDivElement, React.HTMLProps<HTMLDivElement>>(
  function Inner({ children, ...rest }, ref) {
    const { header, footer } = useContext(VirtualTableContext)
    const {style} = children[0].props;
    return (
      <div {...rest} ref={ref}>
        <table style={style}>
          {header}
          <tbody>{children}</tbody>
          {footer}
        </table>
      </div>
    )
  }
)

The style prop is given by the library when it performs createElement for each row, and since your particular Row component doesn't assign the style to tr, you're not passing them down either.

piecyk commented 3 years ago

Recently, I was wondering about something like this. What if we would move whole table body with padding using pseudo elements ( after / before ) via css custom properties 🤔

In example using react-virtual be https://codesandbox.io/s/poc-react-virtual-table-jyz0m

reyronald commented 3 years ago

I absolutely needed a table so that I could achieve the UX I wanted and was not satisfied with the workarounds to making it work with react-window.

I ended-up just extracting the virutalization logic myself to a hook and implementing it with two tables, one for the headers and the second one for the content, similar to what was posted above. The difference in my approach is that the second table still had its headers in the markup but visually hidden so that it remained accessible, whereas the headers of the first one were there just for sighted users and positionally stickied.. Worked like a charm, and the code was drastically simpler.

Just throwing it out there in case someone wants to try that.

Rendez commented 3 years ago

@piecyk That's a great one, very similar to how virtuoso is implemented: https://virtuoso.dev/grouped-by-first-letter/

I have to add that positioning the entire container with absolute/top is performant, but running a perf audit with Chrome I see CLS problems which might impact FPS. I don't think the impact is noticeable, you can see how fast and smooth it can be on this example: https://b6udg.csb.app/ (even though is a big sized container). However with padding-top/bottom there is NO CLS!

I will attempt this myself and measure the difference some time soon.

josephbridgwaterrowe commented 3 years ago

@pupudu I applaud your open source efforts and looked through your code extensively before deciding to try to tackle this on my own. I just wanted the super straightforward thing other people were looking for: this library but with table elements.

Turns out I was able to pull this off with a very small bit of code, and a lot of creativity. The code is simple enough that anyone should be able to copy / paste and extend to their liking. @bvaughn after figuring out the how, this would be pretty trivial to add to the library if you want, but also pretty trivial to override if you know how.

The short of it:

  • Capture the "top" style of the first row after a render
  • Store that value in React.Context so we can pass it around
  • Apply the value to a table component which will be what gets moved around, instead of the rows themselves
  • Add additional slots for things like headers and footers.
  • The ergonomics of the library don't allow things to be passed around neatly, so React.Context is the hero to overcome the cross component communication.

Working Code Sandbox: https://codesandbox.io/s/react-window-with-table-elements-d861o

Code for reference

import React from 'react'
import { useState, useRef, useContext } from 'react'
import { FixedSizeList, FixedSizeListProps } from 'react-window'
import { render } from 'react-dom'

/** Context for cross component communication */
const VirtualTableContext = React.createContext<{
  top: number
  setTop: (top: number) => void
  header: React.ReactNode
  footer: React.ReactNode
}>({
  top: 0,
  setTop: (value: number) => {},
  header: <></>,
  footer: <></>,
})

/** The virtual table. It basically accepts all of the same params as the original FixedSizeList.*/
function VirtualTable({
  row,
  header,
  footer,
  ...rest
}: {
  header?: React.ReactNode
  footer?: React.ReactNode
  row: FixedSizeListProps['children']
} & Omit<FixedSizeListProps, 'children' | 'innerElementType'>) {
  const listRef = useRef<FixedSizeList | null>()
  const [top, setTop] = useState(0)

  return (
    <VirtualTableContext.Provider value={{ top, setTop, header, footer }}>
      <FixedSizeList
        {...rest}
        innerElementType={Inner}
        onItemsRendered={props => {
          const style =
            listRef.current &&
            // @ts-ignore private method access
            listRef.current._getItemStyle(props.overscanStartIndex)
          setTop((style && style.top) || 0)

          // Call the original callback
          rest.onItemsRendered && rest.onItemsRendered(props)
        }}
        ref={el => (listRef.current = el)}
      >
        {row}
      </FixedSizeList>
    </VirtualTableContext.Provider>
  )
}

/** The Row component. This should be a table row, and noted that we don't use the style that regular `react-window` examples pass in.*/
function Row({ index }: { index: number }) {
  return (
    <tr>
      {/** Make sure your table rows are the same height as what you passed into the list... */}
      <td style={{ height: '36px' }}>Row {index}</td>
      <td>Col 2</td>
      <td>Col 3</td>
      <td>Col 4</td>
    </tr>
  )
}

/**
 * The Inner component of the virtual list. This is the "Magic".
 * Capture what would have been the top elements position and apply it to the table.
 * Other than that, render an optional header and footer.
 **/
const Inner = React.forwardRef<HTMLDivElement, React.HTMLProps<HTMLDivElement>>(
  function Inner({ children, ...rest }, ref) {
    const { header, footer, top } = useContext(VirtualTableContext)
    return (
      <div {...rest} ref={ref}>
        <table style={{ top, position: 'absolute', width: '100%' }}>
          {header}
          <tbody>{children}</tbody>
          {footer}
        </table>
      </div>
    )
  }
)

/**
 * Render Our Example
 **/
render(
  <VirtualTable
    height={300}
    width="100%"
    itemCount={1000}
    itemSize={36}
    header={
      <thead>
        <tr>
          <th>Index</th>
          <th>Header 2</th>
          <th>Header 3</th>
          <th>Header 4</th>
        </tr>
      </thead>
    }
    row={Row}
    footer={
      <tfoot>
        <tr>
          <td>Footer 1</td>
          <td>Footer 2</td>
          <td>Footer 3</td>
          <td>Footer 4</td>
        </tr>
      </tfoot>
    }
  />,
  document.querySelector('main')
)

Thank you for this, has anyone tried (with success) to use this with the InfiniteLoader component?... I've tried kicking it around but I'm having issues with the inner "wrapper", which I assume is because the infinite loader is passing unexpected props to the innerElementType.

alvin-yang68 commented 3 years ago

@josephbridgwaterrowe I was able to get InfiniteLoader to work with the solution posted by @jamesmfriedman.

Code Sandbox: https://codesandbox.io/s/react-window-and-react-window-infinite-loader-with-table-elements-xrwkw

I'm not understanding what you meant by "the infinite loader is passing unexpected props to the innerElementType" since I don't think InfiniteLoader needs to pass anything to innerElementType.

rostero1 commented 3 years ago

I just tried out a few of the examples. Are there any ideas why the header sometimes jumps to the middle of the page if you scroll fast up and down?

josephbridgwaterrowe commented 3 years ago

Thanks @alvin-yang68, I actually moved onto to using react-infinite-scroll-component.

I'll admit, I'm not sure exactly what the nature of the problem was not... but I'll give this component and the sample you reference for another project I'm working on shortly.

Thanks again.

wuarmin commented 2 years ago

Hey @bvaughn, thank you for that great lib! I have a question. Would it be possible to achieve something like that: https://html-next.github.io/vertical-collection/#/examples/dbmon

The react-window pseudo-code could look like this:

<div class="table-wrapper" style="height: 500px; ....">
  <table class="table table-striped latest-data">
    <InnerList (List without outer-element)
      outerElementSelector=".table-wrapper"
      innerTagName="tbody"
      itemCount={1000}
      itemSize={35}
    >
      {Row}
    </List>
  </table>
</div>

the html output would be:

<div class="table-wrapper" style="height: 500px; ....">
  <table class="table table-striped latest-data">
    <tbody> // react-window should only handle tbody, with the help of its outer-container (table-wrapper in this case) 
     <tr>....</tr> 
     <tr>....</tr>
    </tbody>
  </table>
</div>

can you imagine this being implemented? It would be interesting to know what the difficulties would be. For me this option would be awesome, because then I could really combine the best of all worlds (react-table, react-window), to build a table with all features, without hacking.

I would appreciate feedback.

I know you think table tags aren't really necessary. But sometimes that's a requirement (in my case it is). With this feature, one could easily achieve that requirement.

Thanks and best regards

aboucodeur commented 1 year ago

I'm solo coder this my first open source experience . I'm very happy today to Open Source thanks for everybody "Javascript are many particules compare to universe" yeah sir