<commit_before>import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { Router, Route, IndexRoute, IndexRedirect, Redirect } from 'react-router';
import { routerActions } from 'react-router-redux';
import { connectedReduxRedirect } from 'redux-auth-wrapper/history3/redirect';

import { setConfig } from './app/config/actions';
import App from './app/App';
import Layout from './app/global/Layout';
import LoginController from './app/views/login/LoginController';
import CollectionsController from './app/views/collections/CollectionsController';
import TeamsController from './app/views/teams/TeamsController';
import SelectADataset from './app/views/datasets-new/DatasetsController';
import DatasetEditionsController from './app/views/datasets-new/editions/DatasetEditionsController';
import DatasetVersionsController from './app/views/datasets-new/versions/DatasetVersionsController';
import DatasetMetadataController from './app/views/datasets-new/edit-metadata/DatasetMetadataController';
import CreateVersionController from './app/views/datasets-new/create/CreateVersionController';
import CreateEditionController from './app/views/datasets-new/create/CreateEditionController';
import DatasetsController from './app/views/datasets/DatasetsController';
import DatasetUploadsController from './app/views/uploads/dataset/DatasetUploadsController';
import DatasetUploadDetails from './app/views/uploads/dataset/upload-details/DatasetUploadDetails';
import DatasetUploadMetadata from './app/views/uploads/dataset/upload-details/DatasetUploadMetadata'
import DatasetMetadata from './app/views/datasets/metadata/DatasetMetadata';
import VersionMetadata from './app/views/datasets/metadata/VersionMetadata';
import Logs from './app/views/logs/Logs';

import auth from './app/utilities/auth'

import './scss/main.scss';

import { store, history } from './app/config/store';

import SelectableTest from './SelectableTest';
//import DatasetPreviewController from './app/views/datasets/preview/DatasetPreviewController';
import VersionPreviewController from './app/views/datasets/preview/VersionPreviewController';
import PreviewController from './app/views/preview/PreviewController';
import DatasetPreviewController from './app/views/datasets-new/preview/PreviewController';
import EditMetadatItem from './app/views/datasets-new/edit-metadata/EditMetadataItem';

const config = window.getEnv();
store.dispatch(setConfig(config));

const rootPath = store.getState().state.rootPath;

const userIsAuthenticated = connectedReduxRedirect({
    authenticatedSelector: state => {
        return auth.isAuthenticated(state.state.user);
    },
    redirectAction: routerActions.replace,
    wrapperDisplayName: 'UserIsAuthenticated',
    redirectPath: `${rootPath}/login`
});

const userisAdminOrEditor = connectedReduxRedirect({
    authenticatedSelector: state => {
        return auth.isAdminOrEditor(state.state.user)
    },
    redirectAction: routerActions.replace,
    wrapperDisplayName: 'userisAdminOrEditor',
    redirectPath: `${rootPath}/collections`,
    allowRedirectBack: false
})

class UnknownRoute extends Component {
    render() {
        return (

Sorry, this page couldnt be found

        )
    }
}

class Index extends Component {
    render() {
        return (
            <Provider store={ store }>
                <Router history={ history }>
                    <Route component={ App }>
                        <Route component={ Layout }>
                            <Redirect from={`${rootPath}`} to={`${rootPath}/collections`} />
                            <Route path={`${rootPath}/collections`} component={ userIsAuthenticated(CollectionsController) }>
                                <Route path=':collectionID' component={ userIsAuthenticated(CollectionsController) }>
                                    <Route path='edit' component={ userIsAuthenticated(CollectionsController) }/>
                                    <Route path='restore-content' component={ userIsAuthenticated(CollectionsController) }/>
                                </Route>
                            </Route>
                            <Route path={`${rootPath}/collections/:collectionID/preview`} component={ userIsAuthenticated(PreviewController) }/>

                            {config.enableDatasetImport === true &&
                                <Route path={`${rootPath}/collections/:collectionID/datasets`} >
                                    <IndexRoute component={ userIsAuthenticated(SelectADataset) }/>
                                    <Route path=':datasetID'>
                                        <IndexRoute component={ userIsAuthenticated(DatasetEditionsController) }/>
                                        <Route path={`editions`} component={ userIsAuthenticated(CreateEditionController) }/>
                                        <Route path='editions/:editionID'>
                                            <Route path={`instances`} component={ userIsAuthenticated(CreateVersionController) }/>
                                            <IndexRoute component={ userIsAuthenticated(DatasetVersionsController) }/>
                                            <Route path={`versions/:versionID`} component={ userIsAuthenticated(DatasetMetadataController) }>
                                                <Route path={`edit/:metadataField/:metadataItemID`} component={ userIsAuthenticated(EditMetadatItem) }/>
                                            </Route>
                                            <Route path='versions/:versionID/preview' component={ userIsAuthenticated(DatasetPreviewController) }/>
                                        </Route>
                                    </Route>
                                </Route>
                            }

                            <Route path={`${rootPath}/teams`} component={ userIsAuthenticated(userisAdminOrEditor(TeamsController)) }>
                                <Route path=":team" component={ userIsAuthenticated(TeamsController) }>
                                    <Route path="edit" component={ userIsAuthenticated(TeamsController) }/>
                                    <Route path="delete" component={ userIsAuthenticated(TeamsController) }/>
                                </Route>
                            </Route>
                            {config.enableDatasetImport === true &&
                                <Route>
                                    <Route path={`${rootPath}/uploads`}>
                                        <IndexRedirect to="data" />
                                        <Route path="data">
                                            <IndexRoute component={userIsAuthenticated(userisAdminOrEditor(DatasetUploadsController))} />
                                            <Route path=":jobID">
                                                <IndexRoute component={ userIsAuthenticated(userisAdminOrEditor(DatasetUploadDetails)) } />
                                                <Route path="metadata" component={ userIsAuthenticated(userisAdminOrEditor(DatasetUploadMetadata)) } />
                                            </Route>
                                        </Route>
                                    </Route>
                                    <Route path={`${rootPath}/datasets`} >
                                        <IndexRoute component={ userIsAuthenticated(userisAdminOrEditor(DatasetsController)) } />
                                        <Route path=":datasetID">
                                            <IndexRedirect to={`${rootPath}/datasets`} />
                                            <Route path="preview" component={ userIsAuthenticated(userisAdminOrEditor(DatasetPreviewController)) } />
                                            <Route path="metadata" component={ userIsAuthenticated(userisAdminOrEditor(DatasetMetadata)) } />
                                            <Route path="editions/:edition/versions/:version">
                                                <IndexRedirect to="metadata"/>
                                                <Route path="metadata" component={ userIsAuthenticated(userisAdminOrEditor(VersionMetadata)) }/>
                                                <Route path="preview" component={ userIsAuthenticated(userisAdminOrEditor(VersionPreviewController)) } />
                                            </Route>
                                            <Route path="instances">
                                                <IndexRedirect to={`${rootPath}/datasets`}/>
                                                <Route path=":instanceID/metadata" component={ userIsAuthenticated(userisAdminOrEditor(VersionMetadata)) } />
                                            </Route>
                                        </Route>
                                    </Route>
                                </Route>
                            }
                            <Route path={`${rootPath}/selectable-list`} component={ SelectableTest } />
                            <Route path={`${rootPath}/logs`} component={ Logs } />
                            <Route path={`${rootPath}/login`} component={ LoginController } />
                            <Route path="*" component={ UnknownRoute } />
                        </Route>
                    </Route>
                </Router>
            </Provider>
        )
    }
}

ReactDOM.render(<Index/>, document.getElementById('app'));
<commit_msg>Remove old datasets preview<commit_after>import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { Router, Route, IndexRoute, IndexRedirect, Redirect } from 'react-router';
import { routerActions } from 'react-router-redux';
import { connectedReduxRedirect } from 'redux-auth-wrapper/history3/redirect';

import { setConfig } from './app/config/actions';
import App from './app/App';
import Layout from './app/global/Layout';
import LoginController from './app/views/login/LoginController';
import CollectionsController from './app/views/collections/CollectionsController';
import TeamsController from './app/views/teams/TeamsController';
import SelectADataset from './app/views/datasets-new/DatasetsController';
import DatasetEditionsController from './app/views/datasets-new/editions/DatasetEditionsController';
import DatasetVersionsController from './app/views/datasets-new/versions/DatasetVersionsController';
import DatasetMetadataController from './app/views/datasets-new/edit-metadata/DatasetMetadataController';
import CreateVersionController from './app/views/datasets-new/create/CreateVersionController';
import CreateEditionController from './app/views/datasets-new/create/CreateEditionController';
import DatasetsController from './app/views/datasets/DatasetsController';
import DatasetUploadsController from './app/views/uploads/dataset/DatasetUploadsController';
import DatasetUploadDetails from './app/views/uploads/dataset/upload-details/DatasetUploadDetails';
import DatasetUploadMetadata from './app/views/uploads/dataset/upload-details/DatasetUploadMetadata'
import DatasetMetadata from './app/views/datasets/metadata/DatasetMetadata';
import VersionMetadata from './app/views/datasets/metadata/VersionMetadata';
import Logs from './app/views/logs/Logs';

import auth from './app/utilities/auth'

import './scss/main.scss';

import { store, history } from './app/config/store';

import SelectableTest from './SelectableTest';
import VersionPreviewController from './app/views/datasets/preview/VersionPreviewController';
import PreviewController from './app/views/preview/PreviewController';
import DatasetPreviewController from './app/views/datasets-new/preview/PreviewController';
import EditMetadatItem from './app/views/datasets-new/edit-metadata/EditMetadataItem';

const config = window.getEnv();
store.dispatch(setConfig(config));

const rootPath = store.getState().state.rootPath;

const userIsAuthenticated = connectedReduxRedirect({
    authenticatedSelector: state => {
        return auth.isAuthenticated(state.state.user);
    },
    redirectAction: routerActions.replace,
    wrapperDisplayName: 'UserIsAuthenticated',
    redirectPath: `${rootPath}/login`
});

const userisAdminOrEditor = connectedReduxRedirect({
    authenticatedSelector: state => {
        return auth.isAdminOrEditor(state.state.user)
    },
    redirectAction: routerActions.replace,
    wrapperDisplayName: 'userisAdminOrEditor',
    redirectPath: `${rootPath}/collections`,
    allowRedirectBack: false
})

class UnknownRoute extends Component {
    render() {
        return (

Sorry, this page couldnt be found

        )
    }
}

class Index extends Component {
    render() {
        return (
            <Provider store={ store }>
                <Router history={ history }>
                    <Route component={ App }>
                        <Route component={ Layout }>
                            <Redirect from={`${rootPath}`} to={`${rootPath}/collections`} />
                            <Route path={`${rootPath}/collections`} component={ userIsAuthenticated(CollectionsController) }>
                                <Route path=':collectionID' component={ userIsAuthenticated(CollectionsController) }>
                                    <Route path='edit' component={ userIsAuthenticated(CollectionsController) }/>
                                    <Route path='restore-content' component={ userIsAuthenticated(CollectionsController) }/>
                                </Route>
                            </Route>
                            <Route path={`${rootPath}/collections/:collectionID/preview`} component={ userIsAuthenticated(PreviewController) }/>

                            {config.enableDatasetImport === true &&
                                <Route path={`${rootPath}/collections/:collectionID/datasets`} >
                                    <IndexRoute component={ userIsAuthenticated(SelectADataset) }/>
                                    <Route path=':datasetID'>
                                        <IndexRoute component={ userIsAuthenticated(DatasetEditionsController) }/>
                                        <Route path={`editions`} component={ userIsAuthenticated(CreateEditionController) }/>
                                        <Route path='editions/:editionID'>
                                            <Route path={`instances`} component={ userIsAuthenticated(CreateVersionController) }/>
                                            <IndexRoute component={ userIsAuthenticated(DatasetVersionsController) }/>
                                            <Route path={`versions/:versionID`} component={ userIsAuthenticated(DatasetMetadataController) }>
                                                <Route path={`edit/:metadataField/:metadataItemID`} component={ userIsAuthenticated(EditMetadatItem) }/>
                                            </Route>
                                            <Route path='versions/:versionID/preview' component={ userIsAuthenticated(DatasetPreviewController) }/>
                                        </Route>
                                    </Route>
                                </Route>
                            }

                            <Route path={`${rootPath}/teams`} component={ userIsAuthenticated(userisAdminOrEditor(TeamsController)) }>
                                <Route path=":team" component={ userIsAuthenticated(TeamsController) }>
                                    <Route path="edit" component={ userIsAuthenticated(TeamsController) }/>
                                    <Route path="delete" component={ userIsAuthenticated(TeamsController) }/>
                                </Route>
                            </Route>
                            {config.enableDatasetImport === true &&
                                <Route>
                                    <Route path={`${rootPath}/uploads`}>
                                        <IndexRedirect to="data" />
                                        <Route path="data">
                                            <IndexRoute component={userIsAuthenticated(userisAdminOrEditor(DatasetUploadsController))} />
                                            <Route path=":jobID">
                                                <IndexRoute component={ userIsAuthenticated(userisAdminOrEditor(DatasetUploadDetails)) } />
                                                <Route path="metadata" component={ userIsAuthenticated(userisAdminOrEditor(DatasetUploadMetadata)) } />
                                            </Route>
                                        </Route>
                                    </Route>
                                    <Route path={`${rootPath}/datasets`} >
                                        <IndexRoute component={ userIsAuthenticated(userisAdminOrEditor(DatasetsController)) } />
                                        <Route path=":datasetID">
                                            <IndexRedirect to={`${rootPath}/datasets`} />
                                            <Route path="preview" component={ userIsAuthenticated(userisAdminOrEditor(DatasetPreviewController)) } />
                                            <Route path="metadata" component={ userIsAuthenticated(userisAdminOrEditor(DatasetMetadata)) } />
                                            <Route path="editions/:edition/versions/:version">
                                                <IndexRedirect to="metadata"/>
                                                <Route path="metadata" component={ userIsAuthenticated(userisAdminOrEditor(VersionMetadata)) }/>
                                                <Route path="preview" component={ userIsAuthenticated(userisAdminOrEditor(VersionPreviewController)) } />
                                            </Route>
                                            <Route path="instances">
                                                <IndexRedirect to={`${rootPath}/datasets`}/>
                                                <Route path=":instanceID/metadata" component={ userIsAuthenticated(userisAdminOrEditor(VersionMetadata)) } />
                                            </Route>
                                        </Route>
                                    </Route>
                                </Route>
                            }
                            <Route path={`${rootPath}/selectable-list`} component={ SelectableTest } />
                            <Route path={`${rootPath}/logs`} component={ Logs } />
                            <Route path={`${rootPath}/login`} component={ LoginController } />
                            <Route path="*" component={ UnknownRoute } />
                        </Route>
                    </Route>
                </Router>
            </Provider>
        )
    }
}

ReactDOM.render(<Index/>, document.getElementById('app'));
<|endoftext|>


<commit_before>import * as I     from 'immutable';
import * as THREE from 'three';
import * as React from 'react';

import * as surface from '../geometry/surface';

import Display3d from './Display3d';

const geometry = function geometry(vertices, faces) {
  const geom = new THREE.Geometry();

  vertices.forEach(v => {
    geom.vertices.push(new THREE.Vector3(v[0], v[1], v[2]));
  });

  faces.forEach(function(f) {
    f.forEach(function(v, i) {
      if (i > 0 && i+1 < f.length)
        geom.faces.push(new THREE.Face3(f[0], f[i], f[i+1]));
    });
  });

  geom.computeFaceNormals();
  return geom;
};

const model = material => {
  const pos = [[0,0,0], [0,0,1], [0,1,0], [0,1,1],
               [1,0,0], [1,0,1], [1,1,0], [1,1,1]];

  const faces = [[0,1,3,2],[5,4,6,7],
                 [1,0,4,5],[2,3,7,6],
                 [0,2,6,4],[3,1,5,7]];

  return new THREE.Mesh(geometry(pos, faces), material);
};

const light = function(color, x, y, z) {
  const light = new THREE.PointLight(color);

  light.position.set(x, y, z);

  return light;
};

const apply = function(v, A) {
  return V.make(M.times(M.make([v.data]), A).data.first());
};

const makeScene = function() {
  const scene  = new THREE.Scene();

  const material = new THREE.MeshPhongMaterial({
    color    : 0x0000ff,
    shininess: 50
  });

  const distance = 18;
  const camera = new THREE.PerspectiveCamera(25, 1, 0.1, 10000);
  camera.name = 'camera';
  camera.position.z = 5*distance;

  camera.add(light(0xffffff,  3*distance,  5*distance, distance));
  camera.add(light(0x666666, -5*distance, -5*distance, distance));

  scene.add(model(material));
  scene.add(camera);

  return scene;
};

const App = React.createClass({
  displayName: 'App',

  getInitialState() {
    const scene = makeScene();
    const camera = scene.getObjectByName('camera');
    return {
      scene: scene,
      camera: camera,
      cameraParameters: { distance: camera.position.z }
    };
  },

  handleResize(data) {
    this.setState({
      width: window.innerWidth,
      height: window.innerHeight
    });
  },

  componentDidMount() {
    this.handleResize();
    window.addEventListener('resize', this.handleResize);
  },

  componentWillUnmount() {
    window.removeEventListener('resize', this.handleResize);
  },

  render() {
    return React.DOM.div(
      null,
      React.createElement(Display3d, {
        scene           : this.state.scene,
        camera          : this.state.camera,
        cameraParameters: this.state.cameraParameters,
        width           : this.state.width - 20,
        height          : this.state.height - 20
      }));
  }
});

React.render(React.createElement(App), document.getElementById('react-main'));
<commit_msg>make subD surface test work<commit_after>import * as I     from 'immutable';
import * as THREE from 'three';
import * as React from 'react';

import * as F from '../arithmetic/float';
import _V from '../arithmetic/vector';
const V = _V(F, 0);

import * as surface from '../geometry/surface';

import Display3d from './Display3d';

const geometry = function geometry(vertices, faces) {
  const geom = new THREE.Geometry();

  vertices.forEach(v => {
    geom.vertices.push(new THREE.Vector3(v[0], v[1], v[2]));
  });

  faces.forEach(function(f) {
    f.forEach(function(v, i) {
      if (i > 0 && i+1 < f.length)
        geom.faces.push(new THREE.Face3(f[0], f[i], f[i+1]));
    });
  });

  geom.computeFaceNormals();
  return geom;
};

const model = material => {
  const s0 = {
    pos: I.fromJS([[0,0,0], [0,0,1], [0,1,0], [0,1,1],
                   [1,0,0], [1,0,1], [1,1,0], [1,1,1]]).map(V.make),
    faces: I.fromJS([[0,1,3,2],[5,4,6,7],
                     [1,0,4,5],[2,3,7,6],
                     [0,2,6,4],[3,1,5,7]]),
    isFixed: I.List(I.Repeat(false, 8))
  };
  const s1 = surface.subD(s0);
  const s2 = surface.subD(s1);

  return new THREE.Mesh(
    geometry(s2.pos.map(v => v.data.toJS()), s2.faces.toJS()),
    material);
};

const light = function(color, x, y, z) {
  const light = new THREE.PointLight(color);

  light.position.set(x, y, z);

  return light;
};

const apply = function(v, A) {
  return V.make(M.times(M.make([v.data]), A).data.first());
};

const makeScene = function() {
  const scene  = new THREE.Scene();

  const material = new THREE.MeshPhongMaterial({
    color    : 0x0000ff,
    shininess: 50
  });

  const distance = 3;
  const camera = new THREE.PerspectiveCamera(25, 1, 0.1, 10000);
  camera.name = 'camera';
  camera.position.z = 5*distance;

  camera.add(light(0xffffff,  3*distance,  5*distance, distance));
  camera.add(light(0x666666, -5*distance, -5*distance, distance));

  const m = model(material);

  scene.add(m);
  scene.add(new THREE.WireframeHelper(m, 0x00ff00));
  scene.add(camera);

  return scene;
};

const App = React.createClass({
  displayName: 'App',

  getInitialState() {
    const scene = makeScene();
    const camera = scene.getObjectByName('camera');
    return {
      scene: scene,
      camera: camera,
      cameraParameters: { distance: camera.position.z }
    };
  },

  handleResize(data) {
    this.setState({
      width: window.innerWidth,
      height: window.innerHeight
    });
  },

  componentDidMount() {
    this.handleResize();
    window.addEventListener('resize', this.handleResize);
  },

  componentWillUnmount() {
    window.removeEventListener('resize', this.handleResize);
  },

  render() {
    return React.DOM.div(
      null,
      React.createElement(Display3d, {
        scene           : this.state.scene,
        camera          : this.state.camera,
        cameraParameters: this.state.cameraParameters,
        width           : this.state.width - 20,
        height          : this.state.height - 20
      }));
  }
});

React.render(React.createElement(App), document.getElementById('react-main'));
<|endoftext|>


<commit_before>export { default as themed } from './themed'
export { default as Theme } from './ThemeProvider'
export { default as ThemeProvider } from './ThemeProvider'
export { default as themeContext } from './themeContext'
export { default as compose } from './compose'
export { default as expand } from './expand'
<commit_msg>Export themed decorator as default<commit_after>export default from './themed'
export { default as themed } from './themed'
export { default as Theme } from './ThemeProvider'
export { default as ThemeProvider } from './ThemeProvider'
export { default as themeContext } from './themeContext'
export { default as compose } from './compose'
export { default as expand } from './expand'
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

'use strict';

base.requireStylesheet('ui.quad_view');

base.require('base.color');
base.require('base.event_target');
base.require('base.raf');
base.require('ui');
base.require('ui.quad_view_viewport');

base.exportTo('ui', function() {

  // Care of bckenney@ via
  // http://extremelysatisfactorytotalitarianism.com/blog/?p=2120
  function drawTexturedTriangle(
      ctx,
      img, x0, y0, x1, y1, x2, y2,
      u0, v0, u1, v1, u2, v2) {

    ctx.beginPath();
    ctx.moveTo(x0, y0);
    ctx.lineTo(x1, y1);
    ctx.lineTo(x2, y2);
    ctx.closePath();

    x1 -= x0;
    y1 -= y0;
    x2 -= x0;
    y2 -= y0;

    u1 -= u0;
    v1 -= v0;
    u2 -= u0;
    v2 -= v0;

    var det = 1 / (u1 * v2 - u2 * v1),

        // linear transformation
        a = (v2 * x1 - v1 * x2) * det,
        b = (v2 * y1 - v1 * y2) * det,
        c = (u1 * x2 - u2 * x1) * det,
        d = (u1 * y2 - u2 * y1) * det,

        // translation
        e = x0 - a * u0 - c * v0,
        f = y0 - b * u0 - d * v0;

    ctx.save();
    ctx.transform(a, b, c, d, e, f);
    ctx.clip();
    ctx.drawImage(img, 0, 0);
    ctx.restore();
  }

  var QuadView = ui.define('quad-view');

  QuadView.prototype = {
    __proto__: HTMLUnknownElement.prototype,

    decorate: function() {
      base.EventTargetHelper.decorate(this);

      this.quads_ = undefined;
      this.viewport_ = undefined;
      this.drawDeviceViewportMask_ = false;
      this.canvas_ = document.createElement('canvas');

      this.appendChild(this.canvas_);

      this.onViewportChanged_ = this.onViewportChanged_.bind(this);

      this.onMouseDown_ = this.onMouseDown_.bind(this);
      this.onMouseMove_ = this.onMouseMove_.bind(this);
      this.onMouseUp_ = this.onMouseUp_.bind(this);
      this.canvas_.addEventListener('mousedown', this.onMouseDown_);

      this.canvas_.addEventListener('focus', this.redrawCanvas_.bind(this));
      this.canvas_.addEventListener('blur', this.redrawCanvas_.bind(this));
      this.canvas_.tabIndex = 0;
    },

    get viewport() {
      return this.viewport_;
    },

    set viewport(viewport) {
      if (this.viewport_)
        this.viewport_.removeEventListener('change', this.onViewportChanged_);
      this.viewport_ = viewport;
      if (this.viewport_)
        this.viewport_.addEventListener('change', this.onViewportChanged_);
      this.updateChildren_();
    },

    onViewportChanged_: function() {
      if (!this.hasRequiredProprties_)
        return;
      this.redrawCanvas_();
    },

    get quads() {
      return this.quads_;
    },

    set quads(quads) {
      this.quads_ = quads;
      if (!this.quads_) {
        this.updateChildren_();
        return;
      }
      this.quads_.forEach(function(quad) {
        if (!quad.backgroundRasterData)
          return;
        var tex = quad.backgroundRasterData;
        var helperCanvas = document.createElement('canvas');
        helperCanvas.width = tex.width;
        helperCanvas.height = tex.height;
        var ctx = helperCanvas.getContext('2d');
        var imageData = ctx.createImageData(tex.width, tex.height);
        imageData.data.set(tex.data);
        ctx.putImageData(imageData, 0, 0);
        var img = document.createElement('img');
        img.onload = function() {
          quad.backgroundImage = img;
          this.scheduleRedrawCanvas_();
        }.bind(this);
        img.src = helperCanvas.toDataURL();
      }, this);
      this.updateChildren_();
    },

    get drawDeviceViewportMask() {
      return this.drawDeviceViewportMask_;
    },

    /**
     * When true, darkens the canvas outside of the viewport in order to
     * make waht is inside vs outside the viewport more obvious.
     */
    set drawDeviceViewportMask(draw) {
      this.drawDeviceViewportMask_ = draw;
      this.updateChildren_();
    },

    get hasRequiredProprties_() {
      return this.quads_ &&
          this.viewport_;
    },

    updateChildren_: function() {
      var canvas = this.canvas_;
      if (!this.hasRequiredProprties_) {
        canvas.width = 0;
        canvas.height = 0;
        return;
      }

      this.scheduleRedrawCanvas_();
    },

    scheduleRedrawCanvas_: function() {
      if (this.redrawScheduled_)
        return false;
      this.redrawScheduled_ = true;
      base.requestAnimationFrameInThisFrameIfPossible(
          this.redrawCanvas_, this);
    },

    redrawCanvas_: function() {
      this.redrawScheduled_ = false;

      if (this.canvas_.width != this.viewport_.deviceWidth) {
        this.canvas_.width = this.viewport_.deviceWidth;
        this.canvas_.style.width = this.viewport_.layoutRect.width + 'px';
      }
      if (this.canvas_.height != this.viewport_.deviceHeight) {
        this.canvas_.height = this.viewport_.deviceHeight;
        this.canvas_.style.height = this.viewport_.layoutRect.height + 'px';
      }

      var ctx = this.canvas_.getContext('2d');

      var vp = this.viewport_;
      ctx.clearRect(
          0, 0,
          this.canvas_.width, this.canvas_.height);
      ctx.save();

      vp.applyTransformToContext(ctx);
      ctx.lineWidth = vp.getDeviceLineWidthAssumingTransformIsApplied(1.0);

      var quads = this.quads_ || [];

      // Background colors.
      for (var i = 0; i < quads.length; i++) {
        var quad = quads[i];
        if (quad.backgroundImage) {
          if (quad.isRectangle()) {
            var bounds = quad.boundingRect();
            ctx.drawImage(quad.backgroundImage, 0, 0,
                quad.backgroundImage.width, quad.backgroundImage.height,
                bounds.x, bounds.y, bounds.width, bounds.height);
          } else {
            ctx.save();
            var quadBBox = new base.BBox2();
            quadBBox.addQuad(quad);
            var iw = quad.backgroundImage.width;
            var ih = quad.backgroundImage.height;
            drawTexturedTriangle(
                ctx, quad.backgroundImage,
                quad.p1[0], quad.p1[1],
                quad.p2[0], quad.p2[1],
                quad.p4[0], quad.p4[1],
                0, 0, iw, 0, 0, ih);
            drawTexturedTriangle(
                ctx, quad.backgroundImage,
                quad.p2[0], quad.p2[1],
                quad.p3[0], quad.p3[1],
                quad.p4[0], quad.p4[1],
                iw, 0, iw, ih, 0, ih);
            ctx.restore();
          }
        }

        if (quad.backgroundColor) {
          ctx.fillStyle = quad.backgroundColor;
          ctx.beginPath();
          ctx.moveTo(quad.p1[0], quad.p1[1]);
          ctx.lineTo(quad.p2[0], quad.p2[1]);
          ctx.lineTo(quad.p3[0], quad.p3[1]);
          ctx.lineTo(quad.p4[0], quad.p4[1]);
          ctx.closePath();
          ctx.fill();
        }
      }

      // Outlines.
      for (var i = 0; i < quads.length; i++) {
        var quad = quads[i];
        ctx.beginPath();
        ctx.moveTo(quad.p1[0], quad.p1[1]);
        ctx.lineTo(quad.p2[0], quad.p2[1]);
        ctx.lineTo(quad.p3[0], quad.p3[1]);
        ctx.lineTo(quad.p4[0], quad.p4[1]);
        ctx.closePath();
        if (quad.borderColor)
          ctx.strokeStyle = quad.borderColor;
        else
          ctx.strokeStyle = 'rgb(128,128,128)';
        ctx.stroke();
      }

      // Selection outlines.
      ctx.lineWidth = vp.getDeviceLineWidthAssumingTransformIsApplied(8.0);
      var rules = window.getMatchedCSSRules(this.canvas_);

      // TODO(nduca): Figure out how to get these from css.
      for (var i = 0; i < quads.length; i++) {
        var quad = quads[i];
        if (!quad.upperBorderColor)
          continue;
        if (document.activeElement == this.canvas_) {
          var tmp = base.Color.fromString(quad.upperBorderColor).brighten(0.25);
          ctx.strokeStyle = tmp.toString();
        } else {
          ctx.strokeStyle = quad.upperBorderColor;
        }

        ctx.beginPath();
        ctx.moveTo(quad.p1[0], quad.p1[1]);
        ctx.lineTo(quad.p2[0], quad.p2[1]);
        ctx.lineTo(quad.p3[0], quad.p3[1]);
        ctx.lineTo(quad.p4[0], quad.p4[1]);
        ctx.closePath();
        ctx.stroke();
      }

      if (this.viewport.deviceViewport)
        this.drawDeviceViewport_(this.viewport.deviceViewport, ctx);

      ctx.restore();
    },

    selectQuadsAtCanvasClientPoint: function(clientX, clientY) {
      var selectedQuadIndices = this.findQuadsAtCanvasClientPoint(
          clientX, clientY);
      var e = new base.Event('selectionChanged');
      e.selectedQuadIndices = selectedQuadIndices;
      this.dispatchEvent(e);
      this.viewport_.forceRedrawAll();
    },

    findQuadsAtCanvasClientPoint: function(clientX, clientY) {
      var bounds = this.canvas_.getBoundingClientRect();
      var vecInLayout = vec2.createXY(clientX - bounds.left,
                                      clientY - bounds.top);
      var vecInWorldPixels =
          this.viewport_.layoutPixelsToWorldPixels2(vecInLayout);

      var quads = this.quads_;
      var hitIndices = [];
      for (var i = 0; i < quads.length; i++) {
        var hit = quads[i].vecInside(vecInWorldPixels);
        if (hit)
          hitIndices.push(i);
      }
      return hitIndices;
    },

    drawDeviceViewport_: function(deviceViewport, ctx) {
      if (!this.drawDeviceViewportMask_ || !this.viewport_)
        return;
      var vW = deviceViewport.width;
      var vH = deviceViewport.height;
      var vp = this.viewport_;

      ctx.fillStyle = 'rgba(0,0,0,0.2)';

      // Cover above and below the viewport with dark grey.
      ctx.fillRect(vp.worldRect.x,
                   vp.worldRect.y,
                   vp.worldRect.width,
                   -vp.worldRect.y);
      ctx.fillRect(vp.worldRect.x,
                   vH,
                   vp.worldRect.width,
                   vp.worldRect.height - vH);

      // Cover left and right of the viewport with dark grey.
      ctx.fillRect(vp.worldRect.x,
                   0,
                   -vp.worldRect.x,
                   vH);
      ctx.fillRect(vW,
                   0,
                   vp.worldRect.width - vW,
                   vH);

      // Stroke area around viewport.
      ctx.lineWidth = vp.getDeviceLineWidthAssumingTransformIsApplied(2.0);
      ctx.strokeStyle = 'rgba(0,0,255,1)';
      ctx.strokeRect(0,
                     0,
                     deviceViewport.width,
                     deviceViewport.height);
    },

    onMouseDown_: function(e) {
      if (!this.hasEventListener('selectionChanged'))
        return;
      this.selectQuadsAtCanvasClientPoint(e.clientX, e.clientY);
      document.addEventListener('mousemove', this.onMouseMove_);
      document.addEventListener('mouseup', this.onMouseUp_);
      e.preventDefault();
      this.canvas_.focus();
      return true;
    },

    onMouseMove_: function(e) {
      this.selectQuadsAtCanvasClientPoint(e.clientX, e.clientY);
    },

    onMouseUp_: function(e) {
      this.selectQuadsAtCanvasClientPoint(e.clientX, e.clientY);
      document.removeEventListener('mousemove', this.onMouseMove_);
      document.removeEventListener('mouseup', this.onMouseUp_);
    }

  };

  return {
    QuadView: QuadView
  };
});
<commit_msg>Skip unnecessary canvas clear calls<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

'use strict';

base.requireStylesheet('ui.quad_view');

base.require('base.color');
base.require('base.event_target');
base.require('base.raf');
base.require('ui');
base.require('ui.quad_view_viewport');

base.exportTo('ui', function() {

  // Care of bckenney@ via
  // http://extremelysatisfactorytotalitarianism.com/blog/?p=2120
  function drawTexturedTriangle(
      ctx,
      img, x0, y0, x1, y1, x2, y2,
      u0, v0, u1, v1, u2, v2) {

    ctx.beginPath();
    ctx.moveTo(x0, y0);
    ctx.lineTo(x1, y1);
    ctx.lineTo(x2, y2);
    ctx.closePath();

    x1 -= x0;
    y1 -= y0;
    x2 -= x0;
    y2 -= y0;

    u1 -= u0;
    v1 -= v0;
    u2 -= u0;
    v2 -= v0;

    var det = 1 / (u1 * v2 - u2 * v1),

        // linear transformation
        a = (v2 * x1 - v1 * x2) * det,
        b = (v2 * y1 - v1 * y2) * det,
        c = (u1 * x2 - u2 * x1) * det,
        d = (u1 * y2 - u2 * y1) * det,

        // translation
        e = x0 - a * u0 - c * v0,
        f = y0 - b * u0 - d * v0;

    ctx.save();
    ctx.transform(a, b, c, d, e, f);
    ctx.clip();
    ctx.drawImage(img, 0, 0);
    ctx.restore();
  }

  var QuadView = ui.define('quad-view');

  QuadView.prototype = {
    __proto__: HTMLUnknownElement.prototype,

    decorate: function() {
      base.EventTargetHelper.decorate(this);

      this.quads_ = undefined;
      this.viewport_ = undefined;
      this.drawDeviceViewportMask_ = false;
      this.canvas_ = document.createElement('canvas');

      this.appendChild(this.canvas_);

      this.onViewportChanged_ = this.onViewportChanged_.bind(this);

      this.onMouseDown_ = this.onMouseDown_.bind(this);
      this.onMouseMove_ = this.onMouseMove_.bind(this);
      this.onMouseUp_ = this.onMouseUp_.bind(this);
      this.canvas_.addEventListener('mousedown', this.onMouseDown_);

      this.canvas_.addEventListener('focus', this.redrawCanvas_.bind(this));
      this.canvas_.addEventListener('blur', this.redrawCanvas_.bind(this));
      this.canvas_.tabIndex = 0;
    },

    get viewport() {
      return this.viewport_;
    },

    set viewport(viewport) {
      if (this.viewport_)
        this.viewport_.removeEventListener('change', this.onViewportChanged_);
      this.viewport_ = viewport;
      if (this.viewport_)
        this.viewport_.addEventListener('change', this.onViewportChanged_);
      this.updateChildren_();
    },

    onViewportChanged_: function() {
      if (!this.hasRequiredProprties_)
        return;
      this.redrawCanvas_();
    },

    get quads() {
      return this.quads_;
    },

    set quads(quads) {
      this.quads_ = quads;
      if (!this.quads_) {
        this.updateChildren_();
        return;
      }
      this.quads_.forEach(function(quad) {
        if (!quad.backgroundRasterData)
          return;
        var tex = quad.backgroundRasterData;
        var helperCanvas = document.createElement('canvas');
        helperCanvas.width = tex.width;
        helperCanvas.height = tex.height;
        var ctx = helperCanvas.getContext('2d');
        var imageData = ctx.createImageData(tex.width, tex.height);
        imageData.data.set(tex.data);
        ctx.putImageData(imageData, 0, 0);
        var img = document.createElement('img');
        img.onload = function() {
          quad.backgroundImage = img;
          this.scheduleRedrawCanvas_();
        }.bind(this);
        img.src = helperCanvas.toDataURL();
      }, this);
      this.updateChildren_();
    },

    get drawDeviceViewportMask() {
      return this.drawDeviceViewportMask_;
    },

    /**
     * When true, darkens the canvas outside of the viewport in order to
     * make waht is inside vs outside the viewport more obvious.
     */
    set drawDeviceViewportMask(draw) {
      this.drawDeviceViewportMask_ = draw;
      this.updateChildren_();
    },

    get hasRequiredProprties_() {
      return this.quads_ &&
          this.viewport_;
    },

    updateChildren_: function() {
      var canvas = this.canvas_;
      if (!this.hasRequiredProprties_) {
        canvas.width = 0;
        canvas.height = 0;
        return;
      }

      this.scheduleRedrawCanvas_();
    },

    scheduleRedrawCanvas_: function() {
      if (this.redrawScheduled_)
        return false;
      this.redrawScheduled_ = true;
      base.requestAnimationFrameInThisFrameIfPossible(
          this.redrawCanvas_, this);
    },

    redrawCanvas_: function() {
      this.redrawScheduled_ = false;

      var resizedCanvas = false;
      if (this.canvas_.width != this.viewport_.deviceWidth) {
        this.canvas_.width = this.viewport_.deviceWidth;
        this.canvas_.style.width = this.viewport_.layoutRect.width + 'px';
        resizedCanvas = true;
      }
      if (this.canvas_.height != this.viewport_.deviceHeight) {
        this.canvas_.height = this.viewport_.deviceHeight;
        this.canvas_.style.height = this.viewport_.layoutRect.height + 'px';
        resizedCanvas = true;
      }

      var ctx = this.canvas_.getContext('2d');

      var vp = this.viewport_;

      if (!resizedCanvas) // Canvas resizing automatically clears the context.
        ctx.clearRect(0, 0, this.canvas_.width, this.canvas_.height);

      ctx.save();

      vp.applyTransformToContext(ctx);
      ctx.lineWidth = vp.getDeviceLineWidthAssumingTransformIsApplied(1.0);

      var quads = this.quads_ || [];

      // Background colors.
      for (var i = 0; i < quads.length; i++) {
        var quad = quads[i];
        if (quad.backgroundImage) {
          if (quad.isRectangle()) {
            var bounds = quad.boundingRect();
            ctx.drawImage(quad.backgroundImage, 0, 0,
                quad.backgroundImage.width, quad.backgroundImage.height,
                bounds.x, bounds.y, bounds.width, bounds.height);
          } else {
            ctx.save();
            var quadBBox = new base.BBox2();
            quadBBox.addQuad(quad);
            var iw = quad.backgroundImage.width;
            var ih = quad.backgroundImage.height;
            drawTexturedTriangle(
                ctx, quad.backgroundImage,
                quad.p1[0], quad.p1[1],
                quad.p2[0], quad.p2[1],
                quad.p4[0], quad.p4[1],
                0, 0, iw, 0, 0, ih);
            drawTexturedTriangle(
                ctx, quad.backgroundImage,
                quad.p2[0], quad.p2[1],
                quad.p3[0], quad.p3[1],
                quad.p4[0], quad.p4[1],
                iw, 0, iw, ih, 0, ih);
            ctx.restore();
          }
        }

        if (quad.backgroundColor) {
          ctx.fillStyle = quad.backgroundColor;
          ctx.beginPath();
          ctx.moveTo(quad.p1[0], quad.p1[1]);
          ctx.lineTo(quad.p2[0], quad.p2[1]);
          ctx.lineTo(quad.p3[0], quad.p3[1]);
          ctx.lineTo(quad.p4[0], quad.p4[1]);
          ctx.closePath();
          ctx.fill();
        }
      }

      // Outlines.
      for (var i = 0; i < quads.length; i++) {
        var quad = quads[i];
        ctx.beginPath();
        ctx.moveTo(quad.p1[0], quad.p1[1]);
        ctx.lineTo(quad.p2[0], quad.p2[1]);
        ctx.lineTo(quad.p3[0], quad.p3[1]);
        ctx.lineTo(quad.p4[0], quad.p4[1]);
        ctx.closePath();
        if (quad.borderColor)
          ctx.strokeStyle = quad.borderColor;
        else
          ctx.strokeStyle = 'rgb(128,128,128)';
        ctx.stroke();
      }

      // Selection outlines.
      ctx.lineWidth = vp.getDeviceLineWidthAssumingTransformIsApplied(8.0);
      var rules = window.getMatchedCSSRules(this.canvas_);

      // TODO(nduca): Figure out how to get these from css.
      for (var i = 0; i < quads.length; i++) {
        var quad = quads[i];
        if (!quad.upperBorderColor)
          continue;
        if (document.activeElement == this.canvas_) {
          var tmp = base.Color.fromString(quad.upperBorderColor).brighten(0.25);
          ctx.strokeStyle = tmp.toString();
        } else {
          ctx.strokeStyle = quad.upperBorderColor;
        }

        ctx.beginPath();
        ctx.moveTo(quad.p1[0], quad.p1[1]);
        ctx.lineTo(quad.p2[0], quad.p2[1]);
        ctx.lineTo(quad.p3[0], quad.p3[1]);
        ctx.lineTo(quad.p4[0], quad.p4[1]);
        ctx.closePath();
        ctx.stroke();
      }

      if (this.viewport.deviceViewport)
        this.drawDeviceViewport_(this.viewport.deviceViewport, ctx);

      ctx.restore();
    },

    selectQuadsAtCanvasClientPoint: function(clientX, clientY) {
      var selectedQuadIndices = this.findQuadsAtCanvasClientPoint(
          clientX, clientY);
      var e = new base.Event('selectionChanged');
      e.selectedQuadIndices = selectedQuadIndices;
      this.dispatchEvent(e);
      this.viewport_.forceRedrawAll();
    },

    findQuadsAtCanvasClientPoint: function(clientX, clientY) {
      var bounds = this.canvas_.getBoundingClientRect();
      var vecInLayout = vec2.createXY(clientX - bounds.left,
                                      clientY - bounds.top);
      var vecInWorldPixels =
          this.viewport_.layoutPixelsToWorldPixels2(vecInLayout);

      var quads = this.quads_;
      var hitIndices = [];
      for (var i = 0; i < quads.length; i++) {
        var hit = quads[i].vecInside(vecInWorldPixels);
        if (hit)
          hitIndices.push(i);
      }
      return hitIndices;
    },

    drawDeviceViewport_: function(deviceViewport, ctx) {
      if (!this.drawDeviceViewportMask_ || !this.viewport_)
        return;
      var vW = deviceViewport.width;
      var vH = deviceViewport.height;
      var vp = this.viewport_;

      ctx.fillStyle = 'rgba(0,0,0,0.2)';

      // Cover above and below the viewport with dark grey.
      ctx.fillRect(vp.worldRect.x,
                   vp.worldRect.y,
                   vp.worldRect.width,
                   -vp.worldRect.y);
      ctx.fillRect(vp.worldRect.x,
                   vH,
                   vp.worldRect.width,
                   vp.worldRect.height - vH);

      // Cover left and right of the viewport with dark grey.
      ctx.fillRect(vp.worldRect.x,
                   0,
                   -vp.worldRect.x,
                   vH);
      ctx.fillRect(vW,
                   0,
                   vp.worldRect.width - vW,
                   vH);

      // Stroke area around viewport.
      ctx.lineWidth = vp.getDeviceLineWidthAssumingTransformIsApplied(2.0);
      ctx.strokeStyle = 'rgba(0,0,255,1)';
      ctx.strokeRect(0,
                     0,
                     deviceViewport.width,
                     deviceViewport.height);
    },

    onMouseDown_: function(e) {
      if (!this.hasEventListener('selectionChanged'))
        return;
      this.selectQuadsAtCanvasClientPoint(e.clientX, e.clientY);
      document.addEventListener('mousemove', this.onMouseMove_);
      document.addEventListener('mouseup', this.onMouseUp_);
      e.preventDefault();
      this.canvas_.focus();
      return true;
    },

    onMouseMove_: function(e) {
      this.selectQuadsAtCanvasClientPoint(e.clientX, e.clientY);
    },

    onMouseUp_: function(e) {
      this.selectQuadsAtCanvasClientPoint(e.clientX, e.clientY);
      document.removeEventListener('mousemove', this.onMouseMove_);
      document.removeEventListener('mouseup', this.onMouseUp_);
    }

  };

  return {
    QuadView: QuadView
  };
});
<|endoftext|>


<commit_before>const React = require('react');
const isWebpackBundle = require('is-webpack-bundle');
const webpackRequireWeak = require('webpack-require-weak');
const {inspect} = require('import-inspector');

function capture(fn) {
  let reported = [];
  let stopInspecting = inspect(metadata => reported.push(metadata));
  let promise = fn();
  stopInspecting();
  return {promise, reported};
}

function load(loader) {
  let {promise, reported} = capture(() => {
    return loader();
  });

  if (reported.length > 1) {
    throw new Error('react-loadable cannot handle more than one import() in each loader');
  }

  let state = {
    loading: true,
    loaded: null,
    error: null
  };

  let metadata = reported[0] || {};

  try {
    if (isWebpackBundle) {
      if (typeof metadata.webpackRequireWeakId === 'function') {
        state.loading = false;
        state.loaded = webpackRequireWeak(metadata.webpackRequireWeakId());
      }
    } else {
      if (typeof metadata.serverSideRequirePath === 'string') {
        state.loading = false;
        state.loaded = module.require(metadata.serverSideRequirePath);
      }
    }
  } catch (err) {
    state.error = err;
  }

  state.promise = promise.then(loaded => {
    state.loading = false;
    state.loaded = loaded;
    return loaded;
  }).catch(err => {
    state.loading = false;
    state.error = err;
    throw err;
  });

  return state;
}

function loadMap(obj) {
  let state = {
    loading: false,
    loaded: {},
    error: null
  };

  let promises = [];

  try {
    Object.keys(obj).forEach(key => {
      let result = load(obj[key]);

      if (!result.loading) {
        state.loaded[key] = result.loaded;
        state.error = result.error;
      } else {
        state.loading = true;
      }

      promises.push(result.promise);

      result.promise.then(res => {
        state.loaded[key] = res;
      }).catch(err => {
        state.error = err;
      });
    });
  } catch (err) {
    error = err;
  }

  state.promise = Promise.all(promises).then(res => {
    state.loading = false;
    return res;
  }).catch(err => {
    state.loading = false;
    throw err;
  });

  return state;
}

function resolve(obj) {
  return obj && obj.__esModule ? obj.default : obj;
}

function render(loaded, props) {
  return React.createElement(resolve(loaded), props);
}

function createLoadableComponent(loadFn, options) {
  if (!options.loading) {
    throw new Error('react-loadable requires a `loading` component')
  }

  let opts = Object.assign({
    loader: null,
    loading: null,
    delay: 200,
    timeout: null,
    render: render
  }, options);

  let res = null;

  return class LoadableComponent extends React.Component {
    constructor(props) {
      super(props);

      if (!res) {
        res = loadFn(opts.loader);
      }

      this.state = {
        error: res.error,
        pastDelay: false,
        timedOut: false,
        loading: res.loading,
        loaded: res.loaded
      };
    }

    static preload() {
      if (!res) {
        res = loadFn(opts.loader);
      }
    }

    componentWillMount() {
      this._mounted = true;

      if (res.resolved) {
        return;
      }

      if (typeof opts.delay === 'number') {
        this._delay = setTimeout(() => {
          this.setState({ pastDelay: true });
        }, opts.delay);
      }

      if (typeof opts.timeout === 'number') {
        this._timeout = setTimeout(() => {
          this.setState({ timedOut: true });
        }, opts.timeout);
      }

      let update = () => {
        if (!this._mounted) {
          return;
        }

        this.setState({
          error: res.error,
          loaded: res.loaded,
          loading: res.loading
        });

        this._clearTimeouts();
      };

      res.promise.then(() => {
        update();
      }).catch(err => {
        update();
        throw err;
      });
    }

    componentWillUnmount() {
      this._mounted = false;
      this._clearTimeouts();
    }

    _clearTimeouts() {
      clearTimeout(this._delay);
      clearTimeout(this._timeout);
    }

    render() {
      if (this.state.loading || this.state.error) {
        return React.createElement(opts.loading, {
          isLoading: this.state.loading,
          pastDelay: this.state.pastDelay,
          timedOut: this.state.timedOut,
          error: this.state.error
        });
      } else if (this.state.loaded) {
        return opts.render(this.state.loaded, this.props);
      } else {
        return null;
      }
    }
  };
}

function Loadable(opts) {
  return createLoadableComponent(load, opts);
}

function LoadableMap(opts) {
  if (typeof opts.render !== 'function') {
    throw new Error('LoadableMap requires a `render(loaded, props)` function');
  }

  return createLoadableComponent(loadMap, opts);
}

Loadable.Map = LoadableMap;

module.exports = Loadable;
<commit_msg>when webpackRequireWeakId set loading to false only if module exist (#60)<commit_after>const React = require('react');
const isWebpackBundle = require('is-webpack-bundle');
const webpackRequireWeak = require('webpack-require-weak');
const {inspect} = require('import-inspector');

function capture(fn) {
  let reported = [];
  let stopInspecting = inspect(metadata => reported.push(metadata));
  let promise = fn();
  stopInspecting();
  return {promise, reported};
}

function load(loader) {
  let {promise, reported} = capture(() => {
    return loader();
  });

  if (reported.length > 1) {
    throw new Error('react-loadable cannot handle more than one import() in each loader');
  }

  let state = {
    loading: true,
    loaded: null,
    error: null
  };

  let metadata = reported[0] || {};

  try {
    if (isWebpackBundle) {
      if (typeof metadata.webpackRequireWeakId === 'function') {
        state.loaded = webpackRequireWeak(metadata.webpackRequireWeakId());
        if (state.loaded) state.loading = false;
      }
    } else {
      if (typeof metadata.serverSideRequirePath === 'string') {
        state.loading = false;
        state.loaded = module.require(metadata.serverSideRequirePath);
      }
    }
  } catch (err) {
    state.error = err;
  }

  state.promise = promise.then(loaded => {
    state.loading = false;
    state.loaded = loaded;
    return loaded;
  }).catch(err => {
    state.loading = false;
    state.error = err;
    throw err;
  });

  return state;
}

function loadMap(obj) {
  let state = {
    loading: false,
    loaded: {},
    error: null
  };

  let promises = [];

  try {
    Object.keys(obj).forEach(key => {
      let result = load(obj[key]);

      if (!result.loading) {
        state.loaded[key] = result.loaded;
        state.error = result.error;
      } else {
        state.loading = true;
      }

      promises.push(result.promise);

      result.promise.then(res => {
        state.loaded[key] = res;
      }).catch(err => {
        state.error = err;
      });
    });
  } catch (err) {
    error = err;
  }

  state.promise = Promise.all(promises).then(res => {
    state.loading = false;
    return res;
  }).catch(err => {
    state.loading = false;
    throw err;
  });

  return state;
}

function resolve(obj) {
  return obj && obj.__esModule ? obj.default : obj;
}

function render(loaded, props) {
  return React.createElement(resolve(loaded), props);
}

function createLoadableComponent(loadFn, options) {
  if (!options.loading) {
    throw new Error('react-loadable requires a `loading` component')
  }

  let opts = Object.assign({
    loader: null,
    loading: null,
    delay: 200,
    timeout: null,
    render: render
  }, options);

  let res = null;

  return class LoadableComponent extends React.Component {
    constructor(props) {
      super(props);

      if (!res) {
        res = loadFn(opts.loader);
      }

      this.state = {
        error: res.error,
        pastDelay: false,
        timedOut: false,
        loading: res.loading,
        loaded: res.loaded
      };
    }

    static preload() {
      if (!res) {
        res = loadFn(opts.loader);
      }
    }

    componentWillMount() {
      this._mounted = true;

      if (res.resolved) {
        return;
      }

      if (typeof opts.delay === 'number') {
        this._delay = setTimeout(() => {
          this.setState({ pastDelay: true });
        }, opts.delay);
      }

      if (typeof opts.timeout === 'number') {
        this._timeout = setTimeout(() => {
          this.setState({ timedOut: true });
        }, opts.timeout);
      }

      let update = () => {
        if (!this._mounted) {
          return;
        }

        this.setState({
          error: res.error,
          loaded: res.loaded,
          loading: res.loading
        });

        this._clearTimeouts();
      };

      res.promise.then(() => {
        update();
      }).catch(err => {
        update();
        throw err;
      });
    }

    componentWillUnmount() {
      this._mounted = false;
      this._clearTimeouts();
    }

    _clearTimeouts() {
      clearTimeout(this._delay);
      clearTimeout(this._timeout);
    }

    render() {
      if (this.state.loading || this.state.error) {
        return React.createElement(opts.loading, {
          isLoading: this.state.loading,
          pastDelay: this.state.pastDelay,
          timedOut: this.state.timedOut,
          error: this.state.error
        });
      } else if (this.state.loaded) {
        return opts.render(this.state.loaded, this.props);
      } else {
        return null;
      }
    }
  };
}

function Loadable(opts) {
  return createLoadableComponent(load, opts);
}

function LoadableMap(opts) {
  if (typeof opts.render !== 'function') {
    throw new Error('LoadableMap requires a `render(loaded, props)` function');
  }

  return createLoadableComponent(loadMap, opts);
}

Loadable.Map = LoadableMap;

module.exports = Loadable;
<|endoftext|>


<commit_before>/* @flow */

import type {WalkFiles} from './fs.js';
import {removeSuffix} from './misc.js';

const minimatch = require('minimatch');
const path = require('path');

const WHITESPACE_RE = /^\s+$/;

export type IgnoreFilter = {
  base: string,
  isNegation: boolean,
  regex: RegExp,
};

export function sortFilter(
  files: WalkFiles,
  filters: Array<IgnoreFilter>,
  keepFiles: Set<string> = new Set(),
  possibleKeepFiles: Set<string> = new Set(),
  ignoreFiles: Set<string> = new Set(),
): {
  keepFiles: Set<string>,
  ignoreFiles: Set<string>,
} {
  for (const file of files) {
    let keep = false;

    // always keep a file if a ! pattern matches it
    for (const filter of filters) {
      if (filter.isNegation && matchesFilter(filter, file.basename, file.relative)) {
        keep = true;
        break;
      }
    }

    //
    if (keep) {
      keepFiles.add(file.relative);
      continue;
    }

    // otherwise don't keep it if a pattern matches it
    keep = true;
    for (const filter of filters) {
      if (!filter.isNegation && matchesFilter(filter, file.basename, file.relative)) {
        keep = false;
        break;
      }
    }

    if (keep) {
      possibleKeepFiles.add(file.relative);
    } else {
      ignoreFiles.add(file.relative);
    }
  }

  // exclude file
  for (const file of possibleKeepFiles) {
    const parts = path.dirname(file).split(path.sep);

    while (parts.length) {
      const folder = parts.join(path.sep);
      if (ignoreFiles.has(folder)) {
        ignoreFiles.add(file);
        break;
      }
      parts.pop();
    }
  }

  //
  for (const file of possibleKeepFiles) {
    if (!ignoreFiles.has(file)) {
      keepFiles.add(file);
    }
  }

  //
  for (const file of keepFiles) {
    const parts = path.dirname(file).split(path.sep);

    while (parts.length) {
      // deregister this folder from being ignored, any files inside
      // will still be marked as ignored
      ignoreFiles.delete(parts.join(path.sep));
      parts.pop();
    }
  }

  return {keepFiles, ignoreFiles};
}

export function matchesFilter(filter: IgnoreFilter, basename: string, loc: string): boolean {
  if (filter.base && filter.base !== '.') {
    loc = path.relative(filter.base, loc);
  }
  return filter.regex.test(loc) ||
         filter.regex.test(`/${loc}`) ||
         filter.regex.test(basename);
}

export function ignoreLinesToRegex(lines: Array<string>, base: string = '.'): Array<IgnoreFilter> {
  return lines
    // create regex
    .map((line): ?IgnoreFilter => {
      // remove empty lines, comments, etc
      if (line === '' || line === '!' || line[0] === '#' || WHITESPACE_RE.test(line)) {
        return null;
      }

      let pattern = line;
      let isNegation = false;

      // hide the fact that it's a negation from minimatch since we'll handle this specifally
      // ourselves
      if (pattern[0] === '!') {
        isNegation = true;
        pattern = pattern.slice(1);
      }

      // remove trailing slash
      pattern = removeSuffix(pattern, '/');

      const regex: ?RegExp = minimatch.makeRe(pattern, {nocase: true});

      if (regex) {
        return {
          base,
          isNegation,
          regex,
        };
      } else {
        return null;
      }
    })

    .filter(Boolean);
}
<commit_msg>Fix typo: specifally -> specifically (#3246)<commit_after>/* @flow */

import type {WalkFiles} from './fs.js';
import {removeSuffix} from './misc.js';

const minimatch = require('minimatch');
const path = require('path');

const WHITESPACE_RE = /^\s+$/;

export type IgnoreFilter = {
  base: string,
  isNegation: boolean,
  regex: RegExp,
};

export function sortFilter(
  files: WalkFiles,
  filters: Array<IgnoreFilter>,
  keepFiles: Set<string> = new Set(),
  possibleKeepFiles: Set<string> = new Set(),
  ignoreFiles: Set<string> = new Set(),
): {
  keepFiles: Set<string>,
  ignoreFiles: Set<string>,
} {
  for (const file of files) {
    let keep = false;

    // always keep a file if a ! pattern matches it
    for (const filter of filters) {
      if (filter.isNegation && matchesFilter(filter, file.basename, file.relative)) {
        keep = true;
        break;
      }
    }

    //
    if (keep) {
      keepFiles.add(file.relative);
      continue;
    }

    // otherwise don't keep it if a pattern matches it
    keep = true;
    for (const filter of filters) {
      if (!filter.isNegation && matchesFilter(filter, file.basename, file.relative)) {
        keep = false;
        break;
      }
    }

    if (keep) {
      possibleKeepFiles.add(file.relative);
    } else {
      ignoreFiles.add(file.relative);
    }
  }

  // exclude file
  for (const file of possibleKeepFiles) {
    const parts = path.dirname(file).split(path.sep);

    while (parts.length) {
      const folder = parts.join(path.sep);
      if (ignoreFiles.has(folder)) {
        ignoreFiles.add(file);
        break;
      }
      parts.pop();
    }
  }

  //
  for (const file of possibleKeepFiles) {
    if (!ignoreFiles.has(file)) {
      keepFiles.add(file);
    }
  }

  //
  for (const file of keepFiles) {
    const parts = path.dirname(file).split(path.sep);

    while (parts.length) {
      // deregister this folder from being ignored, any files inside
      // will still be marked as ignored
      ignoreFiles.delete(parts.join(path.sep));
      parts.pop();
    }
  }

  return {keepFiles, ignoreFiles};
}

export function matchesFilter(filter: IgnoreFilter, basename: string, loc: string): boolean {
  if (filter.base && filter.base !== '.') {
    loc = path.relative(filter.base, loc);
  }
  return filter.regex.test(loc) ||
         filter.regex.test(`/${loc}`) ||
         filter.regex.test(basename);
}

export function ignoreLinesToRegex(lines: Array<string>, base: string = '.'): Array<IgnoreFilter> {
  return lines
    // create regex
    .map((line): ?IgnoreFilter => {
      // remove empty lines, comments, etc
      if (line === '' || line === '!' || line[0] === '#' || WHITESPACE_RE.test(line)) {
        return null;
      }

      let pattern = line;
      let isNegation = false;

      // hide the fact that it's a negation from minimatch since we'll handle this specifically
      // ourselves
      if (pattern[0] === '!') {
        isNegation = true;
        pattern = pattern.slice(1);
      }

      // remove trailing slash
      pattern = removeSuffix(pattern, '/');

      const regex: ?RegExp = minimatch.makeRe(pattern, {nocase: true});

      if (regex) {
        return {
          base,
          isNegation,
          regex,
        };
      } else {
        return null;
      }
    })

    .filter(Boolean);
}
<|endoftext|>


<commit_before>const defaultOptions = {
    enableWarnings: false,
    errorsLog: true
};

//TODO: ad warnings
export default class StateUpdateBuilder {
    constructor(state, options) {
        if (state == undefined)
            console.error('root cannot be null');

        this._options = Object.assign({}, defaultOptions, options);

        this.current = this.extendNode(state);
        this.origin = state;
        this.parent = undefined;
        this.parent = undefined;
        this._updated = false;
        this._lastNode = undefined;
        this._refLabel = undefined;
    }

    //generate a StateUpdateBuilder as passing current root as an
    initChildBuider(newOrigin, lastNode, label) {
        var childBuilder = new StateUpdateBuilder(newOrigin, this._options);

        //propagate parent builder informations
        childBuilder.parent = this;
        childBuilder._lastNode = lastNode;
        childBuilder._refLabel = label;

        return childBuilder;
    }

    //creates new reference for arrays, objects and functions
    extendNode(node) {
        if (Array.isArray(node))
            return [].concat(node);

        if (typeof node === 'object')
            return Object.assign({}, node);

        if (typeof node === 'function')
            return () => node();

        return node
    }

    //traverse single node object
    traverseNode(label) {
        if (this._treeError) return this;

        var node = this.current[label];
        if (checkNodeUndefined.call(this, node, label))
            return this;

        //create new builder with shallow copy of traversed node
        var resultBuilder = this.initChildBuider(node, this.current, label);

        //assign node copy to parent pointer
        this.current[label] = resultBuilder.current;

        //returns new builder
        return resultBuilder;
    }

    //traverse single array object navigate to array instance
    traverseList(label, lambda) {
        if (this._treeError) return this;

        var node = this.current[label];

        if (checkNodeUndefined.call(this, node, label) || checkNodeNotArray.call(this, node, label)) {
            this.propagateError(true);
            return this;
        }

        var choosePath = (el, i) => typeof lambda === 'function' ? lambda(el, i) : true;
        var elemIndex = node.findIndex(choosePath);

        if (checkListItemUndefined.call(this, elemIndex, label)) return this;

        var lastNode = this.extendNode(node);
        //create new builder positioned on item found
        var resultBuilder = this.initChildBuider(node.find(choosePath), lastNode, elemIndex);

        //generate new reference to current node array
        this.current[label] = lastNode;
        this.current[label][elemIndex] = resultBuilder.current;

        return resultBuilder;
    }

    //check "label" node presence
    checkSubtree(label, lambda) {
        if (this._treeError) return this;

        const node = this.current[label];

        if (checkNodeUndefined.call(this, node, label))
            return false;

        if (Array.isArray(node)) {
            var choosePath = (el, i) => typeof lambda === 'function' ? lambda(el, i) : false;
            var elemIndex = node.findIndex(choosePath);
            return elemIndex >= 0;
        }
        if (typeof lambda === 'function')
            return !!lambda(node);

        return true;
    }

    //UPDATE OPERATIONS
    //{$set: any} replace the target entirely.
    set(label, value) {
        if (this._treeError) return this;

        if (this._options.enableWarnings && this.current[label] === undefined && label !== null)
            console.error('SUB - Warning: node "' + label + '" not found');

        this.propagateUpdate(this._updated || this.current[label] !== value);
        this.current[label] = value;

        return this;
    }

    setNode(node) {
        if (this._treeError) return this;

        if (!this._lastNode) {
            this.current = node;
            this.propagateUpdate(this._updated || this.current !== node);
        }
        else {
            this._lastNode[this._refLabel] = node;
            this.propagateUpdate(this._updated || this._lastNode[this._refLabel] !== node);
        }

        return this;
    }

    //{$merge: object} merge the keys of object with the target.
    merge(label, value) {
        if (this._treeError) return this;

        if (this._options.enableWarnings && typeof value !== 'object') {
            console.error('SUB - Warning: "value" is not an object');
            return this;
        }

        var node = this.current[label];

        this.propagateUpdate(this._updated || Object.keys(value).reduce((p, c) => p || node[c] !== value[c], false));

        this.current[label] = Object.assign(node, value);

        return this;
    }

    mergeNode(node) {
        if (this._treeError) return this;

        var elem = this._lastNode ? this._lastNode[this._refLabel] : this.current;
        this.propagateUpdate(this._updated || Object.keys(node).reduce((p, c) => p || elem[c] !== node[c], false));

        if (!this._lastNode) {
            this.current = Object.assign(this.current, node);
        }
        else
            this._lastNode[this._refLabel] = Object.assign(this._lastNode[this._refLabel], node);

        return this;
    }

    //remove child node of current object/array node
    removeNode(label, lambda) {
        var node = this.current[label];

        if (node == undefined) return this;

        if (Array.isArray(node) && typeof lambda === 'function') {
            var elemIndex = node.findIndex(lambda);
            elemIndex >= 0 && this.splice(elemIndex, 1);
            return this;
        }

        this.current[label] = undefined;
        this.propagateUpdate(true);

        return this;
    }

    //{$apply: function} passes in the current value to the function and updates it with the new returned value.
    apply(label, fn) {
        if (this._treeError) return this;

        var node = this.current[label];
        if (checkNodeUndefined.call(this, node, label) || checkNotFunction.call(this, fn))
            return this;

        this.current[label] = fn(this.extendNode(node));

        this.propagateUpdate(this._updated || node !== this.current[label]);

        return this;
    }

    //{$push: array} push() all the items in array on the target.
    push(label, array) {
        if (this._treeError) return this;
        var node = this.current[label];
        if (checkNodeUndefined.call(this, node, label) || checkNodeNotArray.call(this, array, label))
            return this;

        var newNode = this.current[label] = this.extendNode(node);
        Array.prototype.push.apply(newNode, array);
        this.propagateUpdate(true);

        return this; //returns the same builder

    }

    //{$unshift: array} unshift() all the items in array on the target.
    unshift(label, array) {
        if (this._treeError) return this;
        var node = this.current[label];
        if (checkNodeUndefined.call(this, node, label) || checkNodeNotArray.call(this, array, label))
            return this;

        var newNode = this.current[label] = this.extendNode(node);
        Array.prototype.unshift.apply(newNode, array);
        this.propagateUpdate(this._updated || array.length > 0);

        return this; //returns the same builder
    }

    //{$splice: array of arrays} for each item in arrays call splice() on the target with the parameters provided by the item.
    splice(label, ...args) {
        if (this._treeError) return this;
        var node = this.current[label];
        if (checkNodeUndefined.call(this, node, label) || checkNodeNotArray.call(this, node, label))
            return this;

        var newNode = this.current[label] = this.extendNode(node);
        Array.prototype.splice.apply(newNode, args);

        this.propagateUpdate(this._updated || args.length > 0);

        return this; //returns the same builder
    }

    execute() {
        return this.parent
            ? this.parent.execute()
            : this._treeError ? this.origin : this.current;
    }

    checkError() {
        return this._treeError;
    }

    propagateUpdate(update) {
        this._updated = update;
        if (update)
            this.parent && this.parent.propagateUpdate(update);
    };

    propagateError(error) {
        this._treeError = error;
        this.parent && this.parent.propagateError(error);
    };

    resetError() {
        this.propagateError(false);
        return this;
    }

    checkNodeUpdated() {
        return this._updated;
    }

    pruneSubtree(label) {
        if (this._treeError) return this;

        var node = this.current[label];
        if (this._options.enableWarnings && node === undefined && label !== null)
            console.error('SUB - Warning: node "' + label + '" not found');

        if (node != undefined)
            this.current[label] = this.origin[label];
        else {
            if (this._lastNode == undefined) {
                if (this._options.errorsLog)
                    console.error('SUB - Error: cannot prune node root');
            }
            else
                this._lastNode[this._refLabel] = this.origin;
        }
        return this.parent || this;
    }
}

///ERROR CHECK AND NOTIFICATION
function checkNodeUndefined(node, label) {
    if (node != undefined) return false;

    this.propagateError(true);
    if (this._options.errorsLog)
        console.error('SUB - Error: node "' + label + '" not found');
    return true;
}

function checkListItemUndefined(elemIndex, label) {
    if (elemIndex !== -1) return false;

    this.propagateError(true);
    if (this._options.errorsLog)
        console.error('SUB - Error: elem of list "' + label + '" not found');
    return true;
}

function checkNodeNotArray(node, label) {
    if (Array.isArray(node)) return false;

    this.propagateError(true);
    if (this._options.errorsLog)
        console.error('SUB - Error: node "' + label + '" is not an array');
    return true;
}

function checkNotFunction(fn) {
    if (typeof fn === 'function') return false;

    this.propagateError(true);
    if (this._options.errorsLog)
        console.error('SUB - Error: parameter "fn" is not a function');
    return true;
}
<commit_msg>bugfix propagating update on setNode, mergeNode actions. bugfix: child builder current state is not updated correctly after setNode, mergeNode actions<commit_after>const defaultOptions = {
    enableWarnings: false,
    errorsLog: true
};

//TODO: ad warnings
export default class StateUpdateBuilder {
    constructor(state, options) {
        if (state == undefined)
            console.error('root cannot be null');

        this._options = Object.assign({}, defaultOptions, options);

        this.current = this.extendNode(state);
        this.origin = state;
        this.parent = undefined;
        this.parent = undefined;
        this._updated = false;
        this._lastNode = undefined;
        this._refLabel = undefined;
    }

    //generate a StateUpdateBuilder as passing current root as an
    initChildBuider(newOrigin, lastNode, label) {
        var childBuilder = new StateUpdateBuilder(newOrigin, this._options);

        //propagate parent builder informations
        childBuilder.parent = this;
        childBuilder._lastNode = lastNode;
        childBuilder._refLabel = label;

        return childBuilder;
    }

    //creates new reference for arrays, objects and functions
    extendNode(node) {
        if (Array.isArray(node))
            return [].concat(node);

        if (typeof node === 'object')
            return Object.assign({}, node);

        if (typeof node === 'function')
            return () => node();

        return node
    }

    //traverse single node object
    traverseNode(label) {
        if (this._treeError) return this;

        var node = this.current[label];
        if (checkNodeUndefined.call(this, node, label))
            return this;

        //create new builder with shallow copy of traversed node
        var resultBuilder = this.initChildBuider(node, this.current, label);

        //assign node copy to parent pointer
        this.current[label] = resultBuilder.current;

        //returns new builder
        return resultBuilder;
    }

    //traverse single array object navigate to array instance
    traverseList(label, lambda) {
        if (this._treeError) return this;

        var node = this.current[label];

        if (checkNodeUndefined.call(this, node, label) || checkNodeNotArray.call(this, node, label)) {
            this.propagateError(true);
            return this;
        }

        var choosePath = (el, i) => typeof lambda === 'function' ? lambda(el, i) : true;
        var elemIndex = node.findIndex(choosePath);

        if (checkListItemUndefined.call(this, elemIndex, label)) return this;

        var lastNode = this.extendNode(node);
        //create new builder positioned on item found
        var resultBuilder = this.initChildBuider(node.find(choosePath), lastNode, elemIndex);

        //generate new reference to current node array
        this.current[label] = lastNode;
        this.current[label][elemIndex] = resultBuilder.current;

        return resultBuilder;
    }

    //check "label" node presence
    checkSubtree(label, lambda) {
        if (this._treeError) return this;

        const node = this.current[label];

        if (checkNodeUndefined.call(this, node, label))
            return false;

        if (Array.isArray(node)) {
            var choosePath = (el, i) => typeof lambda === 'function' ? lambda(el, i) : false;
            var elemIndex = node.findIndex(choosePath);
            return elemIndex >= 0;
        }
        if (typeof lambda === 'function')
            return !!lambda(node);

        return true;
    }

    //UPDATE OPERATIONS
    //{$set: any} replace the target entirely.
    set(label, value) {
        if (this._treeError) return this;

        if (_DEV_ && this._options.enableWarnings && this.current[label] === undefined && label !== null)
            console.error('SUB - Warning: node "' + label + '" not found');

        this.propagateUpdate(this._updated || this.current[label] !== value);
        this.current[label] = value;

        return this;
    }

    setNode(node) {
        if (this._treeError) return this;

        if (!this._lastNode) {
            this.propagateUpdate(this._updated || this.current !== node);
            this.current = node;
        }
        else {
            this.propagateUpdate(this._updated || this._lastNode[this._refLabel] !== node);
            this._lastNode[this._refLabel] = this.current = node;
        }

        return this;
    }

    //{$merge: object} merge the keys of object with the target.
    merge(label, value) {
        if (this._treeError) return this;

        if (this._options.enableWarnings && typeof value !== 'object') {
            console.error('SUB - Warning: "value" is not an object');
            return this;
        }

        var node = this.current[label];

        this.propagateUpdate(this._updated || Object.keys(value).reduce((p, c) => p || node[c] !== value[c], false));

        this.current[label] = Object.assign(node, value);

        return this;
    }

    mergeNode(node) {
        if (this._treeError) return this;

        var elem = this._lastNode ? this._lastNode[this._refLabel] : this.current;
        this.propagateUpdate(this._updated || Object.keys(node).reduce((p, c) => p || elem[c] !== node[c], false));

        if (!this._lastNode)
            this.current = Object.assign(this.current, node);
        else
            this._lastNode[this._refLabel] = this.current = Object.assign(this._lastNode[this._refLabel], node);

        return this;
    }

    //remove child node of current object/array node
    removeNode(label, lambda) {
        var node = this.current[label];

        if (node == undefined) return this;

        if (Array.isArray(node)) {
            var elemIndex = node.findIndex(lambda);
            this.current[label].splice(elemIndex, 1);
            return this;
        }

        this.current[label] = undefined;
        this.propagateUpdate(true);

        return this;
    }

    //{$apply: function} passes in the current value to the function and updates it with the new returned value.
    apply(label, fn) {
        if (this._treeError) return this;

        var node = this.current[label];
        if (checkNodeUndefined.call(this, node, label) || checkNotFunction.call(this, fn))
            return this;

        this.current[label] = fn(this.extendNode(node));

        this.propagateUpdate(this._updated || node !== this.current[label]);

        return this;
    }

    //{$push: array} push() all the items in array on the target.
    push(label, array) {
        if (this._treeError) return this;
        var node = this.current[label];
        if (checkNodeUndefined.call(this, node, label) || checkNodeNotArray.call(this, array, label))
            return this;

        var newNode = this.current[label] = this.extendNode(node);
        Array.prototype.push.apply(newNode, array);
        this.propagateUpdate(true);

        return this; //returns the same builder

    }

    //{$unshift: array} unshift() all the items in array on the target.
    unshift(label, array) {
        if (this._treeError) return this;
        var node = this.current[label];
        if (checkNodeUndefined.call(this, node, label) || checkNodeNotArray.call(this, array, label))
            return this;

        var newNode = this.current[label] = this.extendNode(node);
        Array.prototype.unshift.apply(newNode, array);
        this.propagateUpdate(this._updated || array.length > 0);

        return this; //returns the same builder
    }

    //{$splice: array of arrays} for each item in arrays call splice() on the target with the parameters provided by the item.
    splice(label, ...args) {
        if (this._treeError) return this;
        var node = this.current[label];
        if (checkNodeUndefined.call(this, node, label) || checkNodeNotArray.call(this, node, label))
            return this;

        var newNode = this.current[label] = this.extendNode(node);
        Array.prototype.splice.apply(newNode, args);

        this.propagateUpdate(this._updated || args.length > 0);

        return this; //returns the same builder
    }

    execute() {
        return this.parent
            ? this.parent.execute()
            : this._treeError ? this.origin : this.current;
    }

    checkError() {
        return this._treeError;
    }

    propagateUpdate(update) {
        this._updated = update;
        if (update)
            this.parent && this.parent.propagateUpdate(update);
    };

    propagateError(error) {
        this._treeError = error;
        this.parent && this.parent.propagateError(error);
    };

    resetError() {
        this.propagateError(false);
        return this;
    }

    //TODO provare checkNodeUpdated, pruneSubtree
    checkNodeUpdated() {
        return this._updated;
    }

    //TODO: remove SUB subtree modifications
    pruneSubtree(label) {
        if (this._treeError) return this;

        var node = this.current[label];
        if (_DEV_ && this._options.enableWarnings && node === undefined && label !== null)
            console.error('SUB - Warning: node "' + label + '" not found');

        if (node != undefined)
            this.current[label] = this.origin[label];
        else {
            if (this._lastNode == undefined) {
                if (this._options.errorsLog)
                    console.error('SUB - Error: cannot prune node root');
            }
            else
                this._lastNode[this._refLabel] = this.origin;
        }
        return this.parent || this;
    }
}

///ERROR CHECK AND NOTIFICATION
function checkNodeUndefined(node, label) {
    if (node != undefined) return false;

    this.propagateError(true);
    if (this._options.errorsLog)
        console.error('SUB - Error: node "' + label + '" not found');
    return true;
}

function checkListItemUndefined(elemIndex, label) {
    if (elemIndex !== -1) return false;

    this.propagateError(true);
    if (this._options.errorsLog)
        console.error('SUB - Error: elem of list "' + label + '" not found');
    return true;
}

function checkNodeNotArray(node, label) {
    if (Array.isArray(node)) return false;

    this.propagateError(true);
    if (this._options.errorsLog)
        console.error('SUB - Error: node "' + label + '" is not an array');
    return true;
}

function checkNotFunction(fn) {
    if (typeof fn === 'function') return false;

    this.propagateError(true);
    if (this._options.errorsLog)
        console.error('SUB - Error: parameter "fn" is not a function');
    return true;
}
<|endoftext|>


<commit_before><commit_msg>Stupid workaround to make UAT test pass<commit_after><|endoftext|>


<commit_before>import { encodeQueryString } from './utils';

import Store from './store';
import Block from './block';

const WIDGET_URL = 'https://widget.wurd.io/widget.js';
const API_URL = 'https://api.wurd.io';

class Wurd {
  /**
   * @param {String} appName
   */
  constructor(appName, options = {}) {
    this.store = new Store();
    this.content = new Block(this, null);

    // Add block shortcut methods to the main Wurd instance
    const methodNames = Object.getOwnPropertyNames(Object.getPrototypeOf(this.content));

    methodNames.forEach(name => {
      this[name] = this.content[name].bind(this.content);
    });

    this.connect(appName, options);
  }

  /**
   * Sets up the default connection/instance
   *
   * @param {String} appName
   * @param {Object} [options]
   * @param {Boolean} [options.lang] Specific language to use
   * @param {Boolean|String} [options.editMode] Options for enabling edit mode: `true` or `'querystring'`
   * @param {Boolean} [options.draft] If true, loads draft content; otherwise loads published content
   * @param {Object} [options.markdown] Enable markdown parsing. Works directly with `marked` npm package
   *                                    or an object of shape {parse: Function, parseInline: Function}
   * @param {Object} [options.blockHelpers] Functions to help accessing content and creating editable regions
   * @param {Object} [options.rawContent] Content to populate the store with
   * @param {Function} [options.onLoad] Callback that runs whenever load() completes. Signature: onLoad(content) => {}
   */
  connect(appName, options = {}) {
    this.app = appName;

    this.draft = false;
    this.editMode = false;

    // Set allowed options
    ['draft', 'lang', 'markdown', 'debug', 'onLoad'].forEach(name => {
      const val = options[name];

      if (typeof val !== 'undefined') this[name] = val;
    });

    // Activate edit mode if required
    switch (options.editMode) {
      // Edit mode always on
      case true:
        this.startEditor();
        break;

      // Activate edit mode if the querystring contains an 'edit' parameter e.g. '?edit'
      case 'querystring':
        if (/[?&]edit(&|$)/.test(location.search)) {
          this.startEditor();
        }
        break;

      default:
        break;
    }

    if (options.rawContent) {
      this.store.save(options.rawContent, { lang: options.lang });
    }

    if (options.storageKey) this.store.storageKey = options.storageKey;
    if (options.ttl) this.store.ttl = options.ttl;

    if (options.blockHelpers) {
      this.setBlockHelpers(options.blockHelpers);
    }

    return this;
  }

  /**
   * Loads sections of content so that items are ready to be accessed with #get(id)
   *
   * @param {String|Array<String>} sectionNames     Top-level sections to load e.g. `main,home`
   */
  load(sectionNames) {
    const {app, store, lang, editMode, debug, onLoad, content} = this;

    if (!app) {
      return Promise.reject(new Error('Use wurd.connect(appName) before wurd.load()'));
    }

    // Normalise string sectionNames to array
    const sections = typeof sectionNames === 'string' ? sectionNames.split(',') : sectionNames;

    // When in editMode we skip the cache completely
    if (editMode) {
      return this._fetchSections(sections)
        .then(result => {
          store.save(result, { lang });

          // Clear the cache so changes are reflected immediately when out of editMode
          store.clear();

          // Pass main content Block to callbacks
          if (onLoad) onLoad(content);

          return content;
        });
    }

    // Check for cached sections
    const cachedContent = store.load(sections, { lang });

    const uncachedSections = sections.filter(section => cachedContent[section] === undefined);

    if (debug) console.info('Wurd: from cache:', sections.filter(section => cachedContent[section] !== undefined));

    // Return now if all content was in cache
    if (uncachedSections.length === 0) {
      // Pass main content Block to callbacks
      if (onLoad) onLoad(content);

      return Promise.resolve(content);
    }

    // Otherwise fetch remaining sections
    return this._fetchSections(uncachedSections)
      .then(result => {
        // Cache for next time
        store.save(result, { lang });

        // Pass main content Block to callbacks
        if (onLoad) onLoad(content);

        return content;
      });
  }

  _fetchSections(sectionNames) {
    const {app, debug} = this;

    // Some sections not in cache; fetch them from server
    if (debug) console.info('Wurd: from server:', sectionNames);

    // Build request URL
    const params = ['draft', 'lang'].reduce((memo, param) => {
      if (this[param]) memo[param] = this[param];

      return memo;
    }, {});

    const url = `${API_URL}/apps/${app}/content/${sectionNames}?${encodeQueryString(params)}`;

    return this._fetch(url)
      .then(result => {
        if (result.error) {
          if (result.error.message) {
            throw new Error(result.error.message);
          } else {
            throw new Error(`Error loading ${sectionNames}`);
          }
        };

        return result;
      });
  }

  _fetch(url) {
    return fetch(url)
      .then(res => {
        if (!res.ok) throw new Error(`Error loading ${url}: ${res.statusText}`);

        return res.json();
      });
  }

  startEditor() {
    const {app, lang} = this;

    // Draft mode is always on if in edit mode
    this.editMode = true;
    this.draft = true;

    const script = document.createElement('script');

    script.src = WIDGET_URL;
    script.async = true;
    script.setAttribute('data-app', app);

    if (lang) {
      script.setAttribute('data-lang', lang);
    }

    const prevScript = document.body.querySelector(`script[src="${WIDGET_URL}"]`);

    if (prevScript) {
      document.body.removeChild(prevScript);
    }

    document.body.appendChild(script);
  }

  setBlockHelpers(helpers) {
    Object.assign(Block.prototype, helpers);
  }

};

const instance = new Wurd();

instance.Wurd = Wurd;

export default instance;
<commit_msg>Make apiUrl and widgetUrl editable<commit_after>import { encodeQueryString } from './utils';

import Store from './store';
import Block from './block';

class Wurd {
  /**
   * @param {String} appName
   */
  constructor(appName, options = {}) {
    this.widgetUrl = 'https://widget.wurd.io/widget.js';
    this.apiUrl = 'https://api.wurd.io';

    this.store = new Store();
    this.content = new Block(this, null);

    // Add block shortcut methods to the main Wurd instance
    const methodNames = Object.getOwnPropertyNames(Object.getPrototypeOf(this.content));

    methodNames.forEach(name => {
      this[name] = this.content[name].bind(this.content);
    });

    this.connect(appName, options);
  }

  /**
   * Sets up the default connection/instance
   *
   * @param {String} appName
   * @param {Object} [options]
   * @param {Boolean} [options.lang] Specific language to use
   * @param {Boolean|String} [options.editMode] Options for enabling edit mode: `true` or `'querystring'`
   * @param {Boolean} [options.draft] If true, loads draft content; otherwise loads published content
   * @param {Object} [options.markdown] Enable markdown parsing. Works directly with `marked` npm package
   *                                    or an object of shape {parse: Function, parseInline: Function}
   * @param {Object} [options.blockHelpers] Functions to help accessing content and creating editable regions
   * @param {Object} [options.rawContent] Content to populate the store with
   * @param {Function} [options.onLoad] Callback that runs whenever load() completes. Signature: onLoad(content) => {}
   */
  connect(appName, options = {}) {
    this.app = appName;

    this.draft = false;
    this.editMode = false;

    // Set allowed options
    ['draft', 'lang', 'markdown', 'debug', 'onLoad'].forEach(name => {
      const val = options[name];

      if (typeof val !== 'undefined') this[name] = val;
    });

    // Activate edit mode if required
    switch (options.editMode) {
      // Edit mode always on
      case true:
        this.startEditor();
        break;

      // Activate edit mode if the querystring contains an 'edit' parameter e.g. '?edit'
      case 'querystring':
        if (/[?&]edit(&|$)/.test(location.search)) {
          this.startEditor();
        }
        break;

      default:
        break;
    }

    if (options.rawContent) {
      this.store.save(options.rawContent, { lang: options.lang });
    }

    if (options.storageKey) this.store.storageKey = options.storageKey;
    if (options.ttl) this.store.ttl = options.ttl;

    if (options.blockHelpers) {
      this.setBlockHelpers(options.blockHelpers);
    }

    return this;
  }

  /**
   * Loads sections of content so that items are ready to be accessed with #get(id)
   *
   * @param {String|Array<String>} sectionNames     Top-level sections to load e.g. `main,home`
   */
  load(sectionNames) {
    const {app, store, lang, editMode, debug, onLoad, content} = this;

    if (!app) {
      return Promise.reject(new Error('Use wurd.connect(appName) before wurd.load()'));
    }

    // Normalise string sectionNames to array
    const sections = typeof sectionNames === 'string' ? sectionNames.split(',') : sectionNames;

    // When in editMode we skip the cache completely
    if (editMode) {
      return this._fetchSections(sections)
        .then(result => {
          store.save(result, { lang });

          // Clear the cache so changes are reflected immediately when out of editMode
          store.clear();

          // Pass main content Block to callbacks
          if (onLoad) onLoad(content);

          return content;
        });
    }

    // Check for cached sections
    const cachedContent = store.load(sections, { lang });

    const uncachedSections = sections.filter(section => cachedContent[section] === undefined);

    if (debug) console.info('Wurd: from cache:', sections.filter(section => cachedContent[section] !== undefined));

    // Return now if all content was in cache
    if (uncachedSections.length === 0) {
      // Pass main content Block to callbacks
      if (onLoad) onLoad(content);

      return Promise.resolve(content);
    }

    // Otherwise fetch remaining sections
    return this._fetchSections(uncachedSections)
      .then(result => {
        // Cache for next time
        store.save(result, { lang });

        // Pass main content Block to callbacks
        if (onLoad) onLoad(content);

        return content;
      });
  }

  _fetchSections(sectionNames) {
    const {app, debug} = this;

    // Some sections not in cache; fetch them from server
    if (debug) console.info('Wurd: from server:', sectionNames);

    // Build request URL
    const params = ['draft', 'lang'].reduce((memo, param) => {
      if (this[param]) memo[param] = this[param];

      return memo;
    }, {});

    const url = `${this.apiUrl}/apps/${app}/content/${sectionNames}?${encodeQueryString(params)}`;

    return this._fetch(url)
      .then(result => {
        if (result.error) {
          if (result.error.message) {
            throw new Error(result.error.message);
          } else {
            throw new Error(`Error loading ${sectionNames}`);
          }
        };

        return result;
      });
  }

  _fetch(url) {
    return fetch(url)
      .then(res => {
        if (!res.ok) throw new Error(`Error loading ${url}: ${res.statusText}`);

        return res.json();
      });
  }

  startEditor() {
    const {app, lang} = this;

    // Draft mode is always on if in edit mode
    this.editMode = true;
    this.draft = true;

    const script = document.createElement('script');

    script.src = this.widgetUrl;
    script.async = true;
    script.setAttribute('data-app', app);

    if (lang) {
      script.setAttribute('data-lang', lang);
    }

    const prevScript = document.body.querySelector(`script[src="${this.widgetUrl}"]`);

    if (prevScript) {
      document.body.removeChild(prevScript);
    }

    document.body.appendChild(script);
  }

  setBlockHelpers(helpers) {
    Object.assign(Block.prototype, helpers);
  }

};

const instance = new Wurd();

instance.Wurd = Wurd;

export default instance;
<|endoftext|>


<commit_before><commit_msg>minor fixes in rga-variant-grid #118<commit_after><|endoftext|>