Advertisement
Guest User

Untitled

a guest
Jun 23rd, 2017
70
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. "use strict";
  2.  
  3. const Map         = require("immutable").Map;
  4. const objectUtils = require("../util/object.js");
  5. const React       = require("../react.js");
  6.  
  7. module.exports = class Datatable extends React.Component {
  8.   /**
  9.    * Public Methods
  10.    */
  11.   mergeFilterParameters(filterParameters) {
  12.     const newDynamicFilterParameters = this.dynamicFilterParameters.merge(filterParameters);
  13.  
  14.     if (newDynamicFilterParameters !== this.dynamicFilterParameters) {
  15.       this.dynamicFilterParameters = newDynamicFilterParameters;
  16.       $(this.node).DataTable().ajax.reload();
  17.     }
  18.   }
  19.  
  20.   /**
  21.    * React Callbacks
  22.    */
  23.   render() {
  24.     const filterChildren =
  25.       React.Children.toArray(this.props.children)
  26.       .filter(c => c.type === module.exports.Filters)
  27.       .map(c => React.cloneElement(c, {
  28.         datatable: this,
  29.       }))
  30.     ;
  31.  
  32.     return (
  33.       <div className="wrapper wrapper-content animated fadeInRight ecommerce">
  34.         {do{ if (filterChildren.length > 0) {
  35.           <div id="filters" className="ibox-content m-b-sm border-bottom">
  36.             {filterChildren}
  37.           </div>
  38.         }}}
  39.  
  40.         <div className="row">
  41.           <div className="col-lg-12">
  42.             <div className="wrapper wrapper-content animated fadeInRight">
  43.               <div className="ibox float-e-margins">
  44.                 <div className="ibox-content">
  45.                   <table ref={(ref) => this.node = ref} className="table table-striped dataTable"></table>;
  46.                 </div>
  47.               </div>
  48.             </div>
  49.           </div>
  50.         </div>
  51.       </div>
  52.     );
  53.   }
  54.  
  55.   shouldComponentUpdate() {
  56.     return false;
  57.   }
  58.  
  59.   componentDidMount() {
  60.     this.dynamicFilterParameters = new Map();
  61.     this.csvButton = $('<a class="btn btn-xs btn-primary" data-action="download"><i class="fa fa-download"></i> Download CSV</a>').get(0);
  62.  
  63.     const defaultOptions = {
  64.       columns:
  65.         React.Children.toArray(this.props.children)
  66.         .filter(c => c.type === module.exports.Column)
  67.         .map(module.exports.Column.getConfiguration)
  68.       ,
  69.       processing: true,
  70.       serverSide: true,
  71.       autoWidth: true,
  72.       dom: [
  73.         "<'row'<'col-sm-2'<'csv'>><'col-sm-2'l><'col-sm-4'r><'col-sm-4'p>>",
  74.         "<'row'<'col-sm-12't>>",
  75.         "<'row'<'col-sm-4'i><'col-sm-4'r><'col-sm-4'p>>",
  76.       ].join(""),
  77.  
  78.       ajax: {
  79.         url: this.props.url,
  80.         data: (d, settings) => {
  81.           Object.assign(d, this.staticFilterParameters, this.dynamicFilterParameters.toObject());
  82.  
  83.           const csvParameters = Object.assign({}, d, {
  84.             output: "csv",
  85.             start: 0,
  86.             length: 0,
  87.           });
  88.  
  89.           $(this.csvButton).attr("href", `${ settings.ajax.url }?${ $.param(csvParameters) }`);
  90.         },
  91.       },
  92.     }
  93.  
  94.     const propOptions = objectUtils.withoutKeys(this.props, [
  95.       "children",
  96.       "enableCsv",
  97.       "staticFilterParams",
  98.       "dynamicFilterParams",
  99.       "url",
  100.     ]);
  101.     $(this.node).DataTable(objectUtils.assignDeep({}, defaultOptions, propOptions));
  102.  
  103.     if (this.props.enableCsv) {
  104.       $(this.node).closest("div.dataTables_wrapper").find("div.csv").append(this.csvButton);
  105.     }
  106.   }
  107.  
  108.   componentWillReceiveProps(nextProps) {
  109.     this.mergeFilterParameters(nextProps.filterParameters || {});
  110.   }
  111.  
  112.   componentWillUnmount() {
  113.     this.$node.DataTable().destroy(true);
  114.   }
  115. };
  116.  
  117. module.exports.Column = do {
  118.   const ReactDomServer = require("react-dom/server");
  119.  
  120.   const Column = class Column extends React.ConfigurationComponent {};
  121.   Column.getConfiguration = (column) => {
  122.     if (column.props.RenderComponent) {
  123.       if (column.props.render) {
  124.         throw new Error("Don't set both `render` and `RenderComponent`, they're mutually-exclusive");
  125.       }
  126.  
  127.       /**
  128.       * I do wonder what the performance implications of `RenderComponent`
  129.       * will be, since we're forcing react to render a component to a string
  130.       * each time. For now I'm going to use this because it gives us a lot
  131.       * of benefits, but if it becomes an issue we can revisit column.
  132.       */
  133.       const RenderComponent = column.props.RenderComponent;
  134.       const restProps = objectUtils.withoutKeys(column.props, ["RenderComponent"]);
  135.       const render = (data, type, row, meta) => {
  136.         const reactEl = <RenderComponent data={data} type={type} row={row} meta={meta} />;
  137.         return ReactDomServer.renderToStaticMarkup(reactEl);
  138.       };
  139.  
  140.       return Object.assign({}, restProps, { render });
  141.     } else {
  142.       return column.props;
  143.     }
  144.   };
  145.  
  146.   Column;
  147. };
  148.  
  149. module.exports.Filters = class Filters extends React.StatelessComponent {
  150.   render() { return (
  151.     <div className="row">
  152.       {React.Children.map(this.props.children, c => React.cloneElement(c, {
  153.         datatable: this.props.datatable,
  154.       }))}
  155.     </div>
  156.   ); }
  157. };
  158.  
  159. module.exports.Filters.Action = class ActionFilter extends React.StatelessComponent {
  160.   render() { return (
  161.     <div className="col-sm-4">
  162.       <div className="form-group">
  163.         <label className="control-label">Action</label>
  164.         <input
  165.           type="text"
  166.           name="action"
  167.           className="form-control"
  168.           onChange={({ target: { value } }) => this.props.datatable.mergeFilterParameters({ action: value })}
  169.         />
  170.       </div>
  171.     </div>
  172.   );}
  173. };
  174.  
  175. module.exports.Filters.Date = do{
  176.   const DateTimePicker = require("react-widgets").DateTimePicker;
  177.  
  178.   (class DateFilter extends React.StatelessComponent {
  179.     render() { return (
  180.       <div className="col-sm-4">
  181.         <div className="form-group">
  182.           <label className="control-label">Date</label>
  183.           <DateTimePicker
  184.             time={false}
  185.             onChange={(date) => this.props.datatable.mergeFilterParameters({ timestamp: moment(date).format("L") })}
  186.           />
  187.         </div>
  188.       </div>
  189.     );}
  190.   });
  191. };
  192.  
  193. module.exports.Filters.User = class UserFilter extends React.Component {
  194.   render() { return (
  195.     <div className="col-sm-4">
  196.       <div className="form-group">
  197.         <label className="control-label">User</label>
  198.         <input className="form-control" ref={ref => this.node = ref} />
  199.       </div>
  200.     </div>
  201.   );}
  202.  
  203.   shouldComponentUpdate() {
  204.     return false;
  205.   }
  206.  
  207.   componentDidMount() {
  208.     this.users = this.props.users;
  209.     this.onChange = this.props.onChange;
  210.  
  211.     const usersByName = {};
  212.     for (const user of this.users) {
  213.       usersByName[user.name] = user;
  214.     }
  215.  
  216.     const bloodhound = new Bloodhound({
  217.       identify: (obj) => obj.id,
  218.       datumTokenizer: (datum) => Bloodhound.tokenizers.whitespace(datum.name),
  219.       queryTokenizer: Bloodhound.tokenizers.whitespace,
  220.       local: this.users,
  221.     });
  222.  
  223.     $(this.node).typeahead(
  224.       {
  225.         hint: true,
  226.         highlight: true,
  227.         minLength: 1,
  228.       },
  229.       {
  230.         name: "users",
  231.         source: bloodhound,
  232.         displayKey: "name",
  233.  
  234.         templates: {
  235.           empty: `
  236.             <div class="empty-message">(no results found)</div>
  237.           `,
  238.         },
  239.       }
  240.     );
  241.  
  242.     const onInputChange = () => {
  243.       const selected = usersByName[$(this.node).val()];
  244.       if (selected) {
  245.         this.props.datatable.mergeFilterParameters({ userId: selected.id });
  246.       } else {
  247.         this.props.datatable.mergeFilterParameters({ userId: null });
  248.       }
  249.     };
  250.  
  251.  
  252.     $(this.node)
  253.       .bind("typeahead:change", onInputChange)
  254.       .bind("typeahead:select", onInputChange)
  255.       .keyup(onInputChange)
  256.     ;
  257.   }
  258.  
  259.   componentWillUnmount() {
  260.     throw new Error("Handle componentWillUnmount, find some way of uninitializing this jq plugin");
  261.   }
  262. };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement