<commit_before>/* @flow */
import * as React from "react";
import VirtualizedGrid from "./virtualized-grid";
import PlotlyTransform from "@nteract/transform-plotly";
import {
  GraphOcticon as BarGraphOcticon,
  PulseOcticon as LineGraphOcticon,
  DatabaseOcticon,
  TelescopeOcticon,
  Beaker
} from "@nteract/octicons";

type Props = {
  data: Object,
  metadata: Object,
  theme?: string,
  expanded?: boolean,
  height?: number
};

type State = {
  view: "line" | "bar" | "scatter" | "grid"
};

const DataResourceTransformGrid = ({
  data: { data, schema },
  theme,
  expanded,
  height
}) => {
  return (
    <VirtualizedGrid
      data={data}
      schema={schema}
      theme={theme}
      expanded={expanded}
      height={height}
      // style={{ marginRight: "10px" }}
    />
  );
};

type LINE_VIEW = "line";
type BAR_VIEW = "bar";
type SCATTER_VIEW = "scatter";
type GRID_VIEW = "grid";

const viewTypeToPlotlyTraceProps = {
  grid: {}, // avoid our lookup
  line: {},
  bar: { type: "bar" },
  scatter: { mode: "markers" }
};

const plotViewTypes = Object.keys(viewTypeToPlotlyTraceProps);

const DataResourceTransformPlot = ({
  data: { data, schema },
  type: givenType
}) => {
  const figure = { data: [] };
  const traceProps = viewTypeToPlotlyTraceProps[givenType];
  schema.fields.forEach(({ name }, i) => {
    figure.data[i] = { name, y: [], ...traceProps };
  });
  data.forEach((row, j) => {
    schema.fields.forEach(({ name }, i) => {
      figure.data[i].y[j] = row[name];
    });
  });
  return <PlotlyTransform data={figure} />;
};

const MetadataWarning = ({ metadata }) => {
  const warning =
    metadata && metadata.sampled ? (

        NOTE: This data is sampled

    ) : null;

  return (

        This interactive data explorer is in the works.{" "}

          Help us improve it!

        <Beaker
          style={{
            color: "#111",
            verticalAlign: "center",
            textAlign: "center",
            paddingLeft: "10px"
          }}
        />

      {warning ? (

          {warning}

      ) : null}

  );
};

class DataResourceTransform extends React.Component<Props, State> {
  static MIMETYPE = "application/vnd.dataresource+json";

  state = { view: "grid" };

  shouldComponentUpdate(): boolean {
    return true;
  }

  setGrid = () => {
    this.setState({ view: "grid" });
  };

  setLine = () => {
    this.setState({ view: "line" });
  };

  setBar = () => {
    this.setState({ view: "bar" });
  };

  setScatter = () => {
    this.setState({ view: "scatter" });
  };

  render(): ?React$Element<any> {
    const { view } = this.state;

    let display = null;

    if (view === "grid") {
      display = <DataResourceTransformGrid {...this.props} />;
    } else if (plotViewTypes.includes(view)) {
      display = <DataResourceTransformPlot {...this.props} type={view} />;
    }

    return (

        <MetadataWarning metadata={this.props.metadata} />

            {display}

            <IconButton onClick={this.setGrid} message={"Data Table"}>
              <DatabaseOcticon />
            </IconButton>
            <IconButton onClick={this.setLine} message={"Line Graph"}>
              <LineGraphOcticon />
            </IconButton>
            <IconButton onClick={this.setBar} message={"Bar Graph"}>
              <BarGraphOcticon />
            </IconButton>
            <IconButton onClick={this.setScatter} message={"Scatter Plot"}>
              <TelescopeOcticon />
            </IconButton>

    );
  }
}

type IconButtonProps = {
  message: string,
  onClick: () => void,
  children?: React.Node
};

export class IconButton extends React.Component<IconButtonProps> {
  render() {
    const { message, onClick, children } = this.props;
    return (
      <button
        onClick={onClick}
        key={message}
        title={message}
        style={{
          width: "32px",
          height: "32px"
        }}
      >
        {children}
      </button>
    );
  }
}

export default DataResourceTransform;
<commit_msg>set metadata default prop for data resource<commit_after>/* @flow */
import * as React from "react";
import VirtualizedGrid from "./virtualized-grid";
import PlotlyTransform from "@nteract/transform-plotly";
import {
  GraphOcticon as BarGraphOcticon,
  PulseOcticon as LineGraphOcticon,
  DatabaseOcticon,
  TelescopeOcticon,
  Beaker
} from "@nteract/octicons";

type Props = {
  data: Object,
  metadata: Object,
  theme?: string,
  expanded?: boolean,
  height?: number
};

type State = {
  view: "line" | "bar" | "scatter" | "grid"
};

const DataResourceTransformGrid = ({
  data: { data, schema },
  theme,
  expanded,
  height
}) => {
  return (
    <VirtualizedGrid
      data={data}
      schema={schema}
      theme={theme}
      expanded={expanded}
      height={height}
      // style={{ marginRight: "10px" }}
    />
  );
};

type LINE_VIEW = "line";
type BAR_VIEW = "bar";
type SCATTER_VIEW = "scatter";
type GRID_VIEW = "grid";

const viewTypeToPlotlyTraceProps = {
  grid: {}, // avoid our lookup
  line: {},
  bar: { type: "bar" },
  scatter: { mode: "markers" }
};

const plotViewTypes = Object.keys(viewTypeToPlotlyTraceProps);

const DataResourceTransformPlot = ({
  data: { data, schema },
  type: givenType
}) => {
  const figure = { data: [] };
  const traceProps = viewTypeToPlotlyTraceProps[givenType];
  schema.fields.forEach(({ name }, i) => {
    figure.data[i] = { name, y: [], ...traceProps };
  });
  data.forEach((row, j) => {
    schema.fields.forEach(({ name }, i) => {
      figure.data[i].y[j] = row[name];
    });
  });
  return <PlotlyTransform data={figure} />;
};

const MetadataWarning = ({ metadata }) => {
  const warning =
    metadata && metadata.sampled ? (

        NOTE: This data is sampled

    ) : null;

  return (

        This interactive data explorer is in the works.{" "}

          Help us improve it!

        <Beaker
          style={{
            color: "#111",
            verticalAlign: "center",
            textAlign: "center",
            paddingLeft: "10px"
          }}
        />

      {warning ? (

          {warning}

      ) : null}

  );
};

class DataResourceTransform extends React.Component<Props, State> {
  static MIMETYPE = "application/vnd.dataresource+json";

  static defaultProps = {
    metadata: {}
  };

  state = { view: "grid" };

  shouldComponentUpdate(): boolean {
    return true;
  }

  setGrid = () => {
    this.setState({ view: "grid" });
  };

  setLine = () => {
    this.setState({ view: "line" });
  };

  setBar = () => {
    this.setState({ view: "bar" });
  };

  setScatter = () => {
    this.setState({ view: "scatter" });
  };

  render(): ?React$Element<any> {
    const { view } = this.state;

    let display = null;

    if (view === "grid") {
      display = <DataResourceTransformGrid {...this.props} />;
    } else if (plotViewTypes.includes(view)) {
      display = <DataResourceTransformPlot {...this.props} type={view} />;
    }

    return (

        <MetadataWarning metadata={this.props.metadata} />

            {display}

            <IconButton onClick={this.setGrid} message={"Data Table"}>
              <DatabaseOcticon />
            </IconButton>
            <IconButton onClick={this.setLine} message={"Line Graph"}>
              <LineGraphOcticon />
            </IconButton>
            <IconButton onClick={this.setBar} message={"Bar Graph"}>
              <BarGraphOcticon />
            </IconButton>
            <IconButton onClick={this.setScatter} message={"Scatter Plot"}>
              <TelescopeOcticon />
            </IconButton>

    );
  }
}

type IconButtonProps = {
  message: string,
  onClick: () => void,
  children?: React.Node
};

export class IconButton extends React.Component<IconButtonProps> {
  render() {
    const { message, onClick, children } = this.props;
    return (
      <button
        onClick={onClick}
        key={message}
        title={message}
        style={{
          width: "32px",
          height: "32px"
        }}
      >
        {children}
      </button>
    );
  }
}

export default DataResourceTransform;
<|endoftext|>


<commit_before>const command = {
  command: "config",
  description: "set user-level configuration options",
  config: {
    usage: "truffle config --enable-analytics",
    options: [
      {
        option: "--enable-analytics",
        description: "Enable Truffle to send usage data to Google Analytics",
      },
      {
        option: "--disable-analytics",
        description: "Disable Truffle's ability to send usage data to Google Analytics",
      }
    ]
  },
  builder: {},
  /**
  * set user-level options for analytics
  * @param {bool} analyticsBool
  * @param {Object} userConfig
  */
  setAnalytics: function (analyticsBool, userConfig) {
    if(analyticsBool === true) {
      if(!userConfig.get('uniqueId')) {
        let userId = nanoid();
        userConfig.set({ 'uniqueId': userId });
      }
      userConfig.set({ 'enableAnalytics': true });
      userConfig.set({ 'analyticsSet': true });
      userConfig.set({ 'analyticsMessageDateTime': Date.now() });
    } else {
      userConfig.set({ 'enableAnalytics': false });
      userConfig.set({ 'analyticsSet': true });
      userConfig.set({ 'analyticsMessageDateTime': Date.now() });
    }
  },
  /**
  * prompt user to determine values for user-level analytics config options
  * @param {Object} userConfig
  */
  setUserConfigViaPrompt: async function(userConfig){
      if(!userConfig.get('analyticsSet') && process.stdin.isTTY === true) {
        await inquirer.prompt(analyticsInquiry)
        .then(async answer => {
          if(answer.analyticsInquiry === analyticsInquiry[0].choices[0]) {
            userConfig.set({ 'enableAnalytics': true });
            userConfig.set({ 'analyticsSet': true });
            userConfig.set({ 'analyticsMessageDateTime': Date.now() });
          } else {
            userConfig.set({ 'enableAnalytics': false });
            userConfig.set({ 'analyticsSet': true });
            userConfig.set({ 'analyticsMessageDateTime': Date.now() });
          }
        });
      } else if (userConfig.get('analyticsSet') && userConfig.get('enableAnalytics')) {
        await inquirer.prompt(analyticsDisable)
        .then(async answer => {
          if(answer.analyticsDisable) {
            userConfig.set({ 'enableAnalytics': false });
            userConfig.set({ 'analyticsSet': true });
            userConfig.set({ 'analyticsMessageDateTime': Date.now() });
          } else {
            userConfig.set({ 'enableAnalytics': true });
            userConfig.set({ 'analyticsSet': true });
            userConfig.set({ 'analyticsMessageDateTime': Date.now() });
          }
        });
      } else if(userConfig.get('analyticsSet') && !userConfig.get('enableAnalytics')) {
        await inquirer.prompt(analyticsEnable)
        .then(async answer => {
          if(answer.analyticsEnable) {
            userConfig.set({ 'enableAnalytics': false });
            userConfig.set({ 'analyticsSet': true });
            userConfig.set({ 'analyticsMessageDateTime': Date.now() });
          } else {
            userConfig.set({ 'enableAnalytics': true });
            userConfig.set({ 'analyticsSet': true });
            userConfig.set({ 'analyticsMessageDateTime': Date.now() });
          }
        });
      }
  },
  /**
  * run config commands to set user-level config settings
  * @param {Object} options
  * @param {Func} callback
  */
  run: function (options, callback) {
    const Configstore = require('configstore');
    const userConfig = new Configstore('truffle', {}, { globalConfigPath: true });
    const inquirer = require('inquirer');
    const nanoid = require('nanoid');

    const analyticsInquiry = [
      {
        type : "list",
        name : "analyticsInquiry",
        message : "Would you like to enable analytics for your Truffle projects? Doing so will allow us to make sure Truffle is working as expected and address any bugs more efficiently.",
        choices: ["Yes, enable analytics",
         "No, do not enable analytics"],
      }
    ];
    const analyticsDisable = [
      {
        type: "confirm",
        name: "analyticsDisable",
        message: "Analytics are currently enabled. Would you like to disable them?",
        default: false
      }
    ];
    const analyticsEnable = [
       {
        type: 'confirm',
        name: 'analyticsEnable',
        message: "Analytics are currently disabled. Would you like to enable them?",
        default: false
      }
    ];

    if(options.enableAnalytics) {
      this.setAnalytics(true, userConfig);
    } else if (options.disableAnalytics){
      this.setAnalytics(false, userConfig);
    } else {
      this.setUserConfigViaPrompt();
    }

  }
}

module.exports = command;
<commit_msg>refactor config command file<commit_after>const command = {
  command: "config",
  description: "set user-level configuration options",
  config: {
    usage: "truffle config --enable-analytics",
    options: [
      {
        option: "--enable-analytics",
        description: "Enable Truffle to send usage data to Google Analytics",
      },
      {
        option: "--disable-analytics",
        description: "Disable Truffle's ability to send usage data to Google Analytics",
      }
    ]
  },
  builder: {},
  /**
  * run config commands to set user-level config settings
  * @param {Object} options
  * @param {Func} callback
  */
  run: function (options, callback) {
    if(options.enableAnalytics) {
      command.setAnalytics(true);
    } else if (options.disableAnalytics){
      command.setAnalytics(false);
    } else {
      command.setUserConfigViaPrompt();
    }
  },
  /**
  * set user-level options for analytics
  * @param {bool} analyticsBool
  * @param {Object} userConfig
  */
  setAnalytics: function (analyticsBool) {
    const nanoid = require('nanoid');
    const Configstore = require('configstore');
    const userConfig = new Configstore('truffle', {}, { globalConfigPath: true });

    if(analyticsBool === true) {
      if(!userConfig.get('uniqueId')) {
        let userId =  nanoid();
        userConfig.set({ 'uniqueId': userId });
      }
      userConfig.set({ 'enableAnalytics': true });
      userConfig.set({ 'analyticsSet': true });
      userConfig.set({ 'analyticsMessageDateTime': Date.now() });
    } else {
      userConfig.set({ 'enableAnalytics': false });
      userConfig.set({ 'analyticsSet': true });
      userConfig.set({ 'analyticsMessageDateTime': Date.now() });
    }
  },
  /**
  * prompt user to determine values for user-level analytics config options
  * @param {Object} userConfig
  */
  setUserConfigViaPrompt: async function(){
    const Configstore = require('configstore');
    const userConfig = new Configstore('truffle', {}, { globalConfigPath: true });
    const inquirer = require('inquirer');
    const analyticsInquiry = [
      {
        type : "list",
        name : "analyticsInquiry",
        message : "Would you like to enable analytics for your Truffle projects? Doing so will allow us to make sure Truffle is working as expected and address any bugs more efficiently.",
        choices: ["Yes, enable analytics",
         "No, do not enable analytics"],
      }
    ];
    const analyticsDisable = [
      {
        type: "confirm",
        name: "analyticsDisable",
        message: "Analytics are currently enabled. Would you like to disable them?",
        default: false
      }
    ];
    const analyticsEnable = [
       {
        type: 'confirm',
        name: 'analyticsEnable',
        message: "Analytics are currently disabled. Would you like to enable them?",
        default: false
      }
    ];

    if(!userConfig.get('analyticsSet') && process.stdin.isTTY === true) {
      await inquirer.prompt(analyticsInquiry)
      .then(async answer => {
        if(answer.analyticsInquiry === analyticsInquiry[0].choices[0]) {
          command.setAnalytics(true);
        } else {
          command.setAnalytics(false);
        }
      });
    } else if (userConfig.get('analyticsSet') && userConfig.get('enableAnalytics')) {
      await inquirer.prompt(analyticsDisable)
      .then(async answer => {
        if(answer.analyticsDisable) {
         command.setAnalytics(false);
        } else {
          command.setAnalytics(true);
        }
      });
    } else if(userConfig.get('analyticsSet') && !userConfig.get('enableAnalytics')) {
      await inquirer.prompt(analyticsEnable)
      .then(async answer => {
        if(answer.analyticsEnable) {
          command.setAnalytics(true);
        } else {
          command.setAnalytics(false);
        }
      });
    }
  }
}

module.exports = command;
<|endoftext|>


<commit_before>/*
 This file is a part of libertysoil.org website
 Copyright (C) 2015  Loki Education (Social Enterprise)

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU Affero General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU Affero General Public License for more details.

 You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
import React from 'react';
import {Link} from 'react-router';

import Header from '../components/header';
import WhatIsLibertySoil from '../components/WhatIsLibertySoil';
import Reviews from '../components/Reviews';
import Footer from '../components/footer';

let Welcome = () => {
  return

Education change network

Connect with people from around the world to make education more humane.

No action is too small - it is our world, lets work together to build a better future.

Join

      <WhatIsLibertySoil />

Child Friendly Education

LibertySoil aims to make best schooling practises from around the world visible, accessible and actionable. Emotional and social development of the child are often overlooked in traditional school system. Join our growing community and help more children reach better education.

We encourage people to collect, share and discuss resources on teaching and learning, helping to build a better understanding of the diversity within education. We aim to help families and schools solve problems like bullying, academic pressure, depression, anxiety, professional and social isolation, to name just a few. Needless to say, poor early life experiences negatively affect each person and a society as a whole.

<Link to="/">LibertySoil.org</Link> is in alpha stage starting <time dateTime="2015-10-05">October 5th, 2015</time>. Target public beta release date is October 28th, 2015. All LibertySoil.org code is released under the open source AGPL license and is free to use. Contribute on GitHub.

    {/*

Popular Posts

                Some notes on famous experiment

User Name

                  3
                  12
                  3

                Some notes on famous experiment

User Name

                  3
                  12
                  3

Most followed people

User Name

Math teacher

User Name

Math teacher

User Name

Math teacher

User Name

Math teacher

Popular tags

                  Psychology
                  Gaming

*/}

    <Reviews/>

};

export default Welcome;
<commit_msg>Minor adjustment to homepage welcome message text.<commit_after>/*
 This file is a part of libertysoil.org website
 Copyright (C) 2015  Loki Education (Social Enterprise)

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU Affero General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU Affero General Public License for more details.

 You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
import React from 'react';
import {Link} from 'react-router';

import Header from '../components/header';
import WhatIsLibertySoil from '../components/WhatIsLibertySoil';
import Reviews from '../components/Reviews';
import Footer from '../components/footer';

let Welcome = () => {
  return

Education change network

Connect with people from around the world to make education more humane.

No action is too small - it is our world, lets work together to make it better for everyone.

Join

      <WhatIsLibertySoil />

Child Friendly Education

LibertySoil aims to make best schooling practises from around the world visible, accessible and actionable. Emotional and social development of the child are often overlooked in traditional school system. Join our growing community and help more children reach better education.

We encourage people to collect, share and discuss resources on teaching and learning, helping to build a better understanding of the diversity within education. We aim to help families and schools solve problems like bullying, academic pressure, depression, anxiety, professional and social isolation, to name just a few. Needless to say, poor early life experiences negatively affect each person and a society as a whole.

<Link to="/">LibertySoil.org</Link> is in alpha stage starting <time dateTime="2015-10-05">October 5th, 2015</time>. Target public beta release date is October 28th, 2015. All LibertySoil.org code is released under the open source AGPL license and is free to use. Contribute on GitHub.

    {/*

Popular Posts

                Some notes on famous experiment

User Name

                  3
                  12
                  3

                Some notes on famous experiment

User Name

                  3
                  12
                  3

Most followed people

User Name

Math teacher

User Name

Math teacher

User Name

Math teacher

User Name

Math teacher

Popular tags

                  Psychology
                  Gaming

*/}

    <Reviews/>

};

export default Welcome;
<|endoftext|>


<commit_before>import forEach from '../core/for-each'
import forElements from '../core/for-elements'

import remove from '../dom/remove'
import data from '../dom/data'
import find from '../dom/find'
import createElement from '../dom/createElement'
import append from '../dom/append'
import clone from '../dom/clone'
import clone from '../dom/clone'

import style from '../styles/style'
import screenPosition from '../styles/screen-position'
import height from '../styles/height'
import transform from '../styles/transform'
import size from '../styles/size'

import resize from '../events/resize'
import unresize from '../events/unresize'
import load from '../events/load'

import defaultify from '../utils/defaultify'

import ScrollEvents from './ScrollEvents'

let defaults = {
  debug: false,
  offset: 0,
  ease: 0.2,
  stepMinSize: 5,
  snapOffset: 0,
  handle: {
    top: 'top',
    bottom: 'bottom'
  }
}

function randomColor () {
    return '#' + Math.floor(Math.random()*16777215).toString(16)
}

//Scroll manager
export class Wasabi {
  constructor(config) {
    this.config = defaultify(config, defaults)

    this.wrapper = this.scroller ? this.scroller.wrapper : document.body

    if (!this.config.scroller) {
      this.wrapper = document.body
      this.scrollTop = this.previousScrollTop = screenPosition(this.wrapper).top

      this.scrollEventsManager = new ScrollEvents()
      this.scrollEventsCallback = this.onScrollEvent.bind(this)
      this.scrollEventsManager.on(this.scrollEventsCallback)
    }
    else {
        this.scroller = this.config.scroller

        this.wrapper = this.scroller.wrapper
        this.scrollTop = this.previousScrollTop = this.scroller.scroll.y

        this.scrollerCallback = this.onScroller.bind(this)
        this.scroller.on('update', this.scrollerCallback)
    }

    this.resizeCallback = resize(() => {
        requestAnimationFrame(this.refresh.bind(this))
    })

    if (this.config.debug) {
      this.debugWrapper = createElement('

')
      style(this.debugWrapper, {
        'z-index': 10000,
        width: 25,
        height: height(this.wrapper),
        position: 'absolute',
        top: 0,
        right: 0,
        background: '#2d2d2d'
      })
      append(this.wrapper, this.debugWrapper)
    }

    this.currentSnapIndex = 0
    this.running = true
    this.refresh()
    this.update()

    load(find(this.wrapper, 'img'), this.refresh.bind(this))
  }

  refresh() {
    if (this.config.debug) console.log('%c WASABI DEBUG ', 'background: #2d2d2d color: #b0dd44')

    this.zones = []
    this.snaps = []

    this.windowHeight = window.innerHeight
    this.halfHeight = this.windowHeight/2

    if (this.wrapper) this.wrapperHeight = height(this.wrapper)
    if (this.config.debug) remove('#wasabi-debug .wasabi-marker')

    if (typeof this.config.zones == 'string') {
      forElements(this.config.zones, (element) => {
        this.addZone({}, element)
      })
    }
    else {
      let i = this.config.zones.length
      while (i--) {
        let zoneConfig = this.config.zones[i]

        if (zoneConfig.selector) {
          forElements(zoneConfig.selector, (element) => {
            this.addZone(zoneConfig, element)
          })
        }
        else {
          this.addZone(zoneConfig)
        }
      }
    }

    if (this.snaps.length) {
      if (!this.scroller) {
        console.error('snap option needs a SmoothScroller instance')
      }

      this.snaps.sort((a, b) => {
        return a.top - b.top
      })

      this.currentSnap = this.snaps[this.currentSnapIndex]
    }
  }

  addZone(zoneConfig, element) {
    let zone = {},
        top, bottom

    if (element) {
      zone.element = element
      zone.selector = zoneConfig.selector
      top = screenPosition(element).top + this.scrollTop
      bottom = top + height(element)

      zone.parallax = []
      forElements(find(element, '[data-wasabi]'), (pxElement) => {
        let options = eval('('+data(pxElement, 'wasabi')+')')

        let toX = (typeof options.x !== 'undefined') ? options.x : ((options.to && options.to.x) || 0),
            toY = (typeof options.y !== 'undefined') ? options.y : ((options.to && options.to.y) || 0),
            fromX = (options.from && options.from.x) || 0,
            fromY = (options.from && options.from.y) || 0,
            parentSize = size(element.parentNode)

        if (typeof toX == 'string' && toX.indexOf('%') != -1)
            toX = parseInt(toX, 10) * parentSize.width

        if (typeof toY == 'string' && toY.indexOf('%') != -1)
            toY = parseInt(toY, 10) * parentSize.height

        if (typeof fromX == 'string' && fromX.indexOf('%') != -1)
            fromX = parseInt(fromX, 10) * parentSize.width

        if (typeof fromY == 'string' && fromY.indexOf('%') != -1)
            fromY = parseInt(fromY, 10) * parentSize.height

        zone.parallax.push({
            element: pxElement,
            toX: toX,
            toY: toY,
            fromX: fromX,
            fromY: fromY
        })
      })
    }
    else {
      top = zoneConfig.top
      bottom = zoneConfig.bottom
    }

    let offset = defaultify(zoneConfig.offset, this.config.offset)
    zone.offset = {
        top: defaultify(offset.top, offset),
        bottom: defaultify(offset.bottom, offset)
    }

    zone.top = top - zone.offset.top
    zone.bottom = bottom + zone.offset.bottom

    if (this.config.debug) {
      let color = randomColor()

      console.log(zone.selector +' %c ' + color, 'color:'+color)
      console.log(zone.element)

      let topDebug = createElement(`<div class="wasabi-marker"></div>`)
      append(this.debugWrapper, topDebug)
      style(topDebug, {
        position: 'absolute',
        top: zone.top,
        right: 0,
        width: 25,
        height: 2,
        background: color
      })

      let bottomDebug = clone(topDebug)
      append(this.debugWrapper, bottomDebug)
      style(bottomDebug, {
        'z-index': 9999,
        position: 'absolute',
        top: zone.bottom,
        right: 0,
        width: 25,
        height: 2,
        background: color
      })
    }

    zone.size = zone.bottom - zone.top
    zone.handle = zoneConfig.handle || this.config.handle
    zone.progress = zoneConfig.progress || this.config.progress
    zone.snap = zoneConfig.snap || this.config.snap
    zone.handler = zoneConfig.handler || this.config.handler
    zone.enter = zoneConfig.enter || this.config.enter
    zone.leave = zoneConfig.leave || this.config.leave

    if (zoneConfig.tween) {
      zone.tween = zoneConfig.tween
      if (zone.tween.pause) zone.tween.pause()
    }

    if (zoneConfig.progressTween) {
      zone.progressTween = zoneConfig.progressTween
      if (zone.progressTween.pause) zone.progressTween.pause()
    }

    let handles = {}
    let handleForward = zone.handle.forward || zone.handle
    handles.forward = {
      top: handleForward.top || handleForward,
      bottom: handleForward.bottom || handleForward
    }
    let handleBackward = zone.handle.forward || zone.handle
    handles.backward = {
      top: handleBackward.top || handleBackward,
      bottom: handleBackward.bottom || handleBackward
    }

    if (handles.forward.top == 'middle') {
      zone.forwardTop = zone.top + this.halfHeight
    }
    else if (handles.forward.top == 'bottom') {
      zone.forwardTop = zone.top - this.windowHeight
    }
    else {
      zone.forwardTop = zone.top
    }

    if (handles.forward.bottom == 'middle') {
      zone.forwardBottom = zone.bottom + this.halfHeight
    }
    else if (handles.forward.bottom == 'bottom') {
      zone.forwardBottom = zone.bottom - this.windowHeight
    }
    else {
      zone.forwardBottom = zone.bottom
    }

    zone.forwardSize = Math.max(this.config.stepMinSize, zone.forwardBottom - zone.forwardTop)

    if (handles.backward.top == 'middle') {
      zone.backwardTop = zone.top + this.halfHeight
    }
    else if (handles.backward.top == 'bottom') {
      zone.backwardTop = zone.top - this.windowHeight
    }
    else {
      zone.backwardTop = zone.top
    }

    if (handles.backward.bottom == 'middle') {
      zone.backwardBottom = zone.bottom + this.halfHeight
    }
    else if (handles.backward.bottom == 'bottom') {
      zone.backwardBottom = zone.bottom - this.windowHeight
    }
    else {
      zone.backwardBottom = zone.bottom
    }

    zone.backwardSize = Math.max(this.config.stepMinSize, zone.backwardBottom - zone.backwardTop)

    if (zone.snap) this.snaps.push(zone)

    this.zones.push(zone)
  }

  testSnapping(scrollTarget) {
    if (this.scroller.scrollDisabled || !this.snaps.length) return

    let previous = this.snaps[this.currentSnapIndex-1],
        next = this.snaps[this.currentSnapIndex+1]

    if (previous && scrollTarget.y < this.currentSnap.top) {
      --this.currentSnapIndex
      this.currentSnap = previous

      this.scroller.scrollTarget.y = this.currentSnap.top + this.currentSnap.offset.top
      this.scroller.scrollTo({
        x: 0,
        y: (previous.bottom - this.currentSnap.offset.bottom) - Math.min(previous.size, this.windowHeight)-1
      })
    }
    else if (next && scrollTarget.y > this.currentSnap.bottom - this.windowHeight) {
      ++this.currentSnapIndex
      this.currentSnap = next

      this.scroller.scrollTarget.y = this.currentSnap.bottom - this.windowHeight - this.currentSnap.offset.bottom
      this.scroller.scrollTo({
        x: 0,
        y: (next.top + this.currentSnap.offset.top)+1
      })
    }
  }

  onScroller(scrollTarget) {
    this.scrollTop = this.scroller.scroll.y
    this.testSnapping(scrollTarget)
  }

  onScrollEvent(event) {
    this.scrollTop = screenPosition(this.wrapper).top
  }

  update() {
    if (!this.running) return

    let i = this.zones.length,
        direction = this.previousScrollTop < this.scrollTop ? 'forward' : 'backward'

    while (i--) {
      let zone = this.zones[i], entered, progress

      progress = (this.scrollTop - zone[direction+'Top'])/zone[direction+'Size']
      entered = progress >= 0 && progress <= 1

      if (!zone.entered && entered) {
        if (zone.tween) zone.tween.resume()
        if(zone.handler) zone.handler('enter', direction, zone.selector, zone.element)
        if(zone.enter) zone.enter(direction, zone.selector, zone.element)

        if(zone.snap) {
            this.currentSnapIndex = this.snaps.indexOf(zone)
            this.currentSnap = this.snaps[this.currentSnapIndex]
        }
      }
      else if (zone.entered && !entered) {
          if(zone.handler) zone.handler('leave', direction, zone.selector, zone.element)
        if(zone.leave) zone.leave(direction, zone.selector, zone.element)
      }

      forEach(zone.parallax, (item) => {
        transform(item.element, {
          x: item.fromX + (item.toX - item.fromX) * progress,
          y: item.fromY + (item.toY - item.fromY) * progress
        })
      })

      zone.entered = entered
      if (zone.entered) {
        if (zone.progress) zone.progress(direction, progress, zone.selector)
        if (zone.progressTween && zone.progressTween.progress) zone.progressTween.progress(progress)
      }
    }

    this.previousScrollTop = this.scrollTop

    this.updateRequest = requestAnimationFrame(this.update.bind(this))
  }

  kill() {
    this.running = false

    unresize(this.resizeCallback)
    cancelAnimationFrame(this.updateRequest)

    remove(this.debugWrapper)

    if (this.scrollEventsCallback) {
      this.scrollEventsManager.off(this.scrollEventsCallback)
    }
    else if (this.scrollerCallback) {
      this.scroller.off('update', this.scrollerCallback)
    }

    let i = this.zones.length
    while(i--) {
      let zone = this.zones[i]

      if (zone.tween) this.killTimeline(zone.tween)
      if (zone.progressTween) this.killTimeline(zone.progressTween)
    }

    this.zones = this.snaps = null
  }

  concatenateVars(object) {
    if (!object) return

    let keys = Object.keys(object),
        i = keys.length,
        vars = []

    while(i--) {
        if (typeof object[keys[i]] == 'object') {
            vars = vars.concat(this.concatenateVars(object[keys[i]]))
        }
        else {
            let key = keys[i]
            vars.push(key == 'x' || key == 'y' || key == 'scale' || key == 'rotate' ? 'transform' : key)
        }
    }

    return vars
  }

  killTimeline(timeline) {
    let tweens = timeline.getChildren()
    timeline.kill()

    let i = tweens.length, tween
    while(i--) {
      tween = tweens[i]

      if (tween.target) {
        TweenLite.set(tween.target, {
          clearProps: this.concatenateVars(tween.vars).join(',')
        })
      }
    }
  }
}

export default Wasabi
<commit_msg>wasabi - fix imports<commit_after>import forEach from '../core/for-each'
import forElements from '../core/for-elements'

import remove from '../dom/remove'
import data from '../dom/data'
import find from '../dom/find'
import createElement from '../dom/createElement'
import append from '../dom/append'
import clone from '../dom/clone'

import style from '../styles/style'
import screenPosition from '../styles/screen-position'
import height from '../styles/height'
import transform from '../styles/transform'
import size from '../styles/size'

import resize from '../events/resize'
import unresize from '../events/unresize'
import load from '../events/load'

import defaultify from '../utils/defaultify'

import ScrollEvents from './ScrollEvents'

let defaults = {
  debug: false,
  offset: 0,
  ease: 0.2,
  stepMinSize: 5,
  snapOffset: 0,
  handle: {
    top: 'top',
    bottom: 'bottom'
  }
}

function randomColor () {
    return '#' + Math.floor(Math.random()*16777215).toString(16)
}

//Scroll manager
export class Wasabi {
  constructor(config) {
    this.config = defaultify(config, defaults)

    this.wrapper = this.scroller ? this.scroller.wrapper : document.body

    if (!this.config.scroller) {
      this.wrapper = document.body
      this.scrollTop = this.previousScrollTop = screenPosition(this.wrapper).top

      this.scrollEventsManager = new ScrollEvents()
      this.scrollEventsCallback = this.onScrollEvent.bind(this)
      this.scrollEventsManager.on(this.scrollEventsCallback)
    }
    else {
        this.scroller = this.config.scroller

        this.wrapper = this.scroller.wrapper
        this.scrollTop = this.previousScrollTop = this.scroller.scroll.y

        this.scrollerCallback = this.onScroller.bind(this)
        this.scroller.on('update', this.scrollerCallback)
    }

    this.resizeCallback = resize(() => {
        requestAnimationFrame(this.refresh.bind(this))
    })

    if (this.config.debug) {
      this.debugWrapper = createElement('

')
      style(this.debugWrapper, {
        'z-index': 10000,
        width: 25,
        height: height(this.wrapper),
        position: 'absolute',
        top: 0,
        right: 0,
        background: '#2d2d2d'
      })
      append(this.wrapper, this.debugWrapper)
    }

    this.currentSnapIndex = 0
    this.running = true
    this.refresh()
    this.update()

    load(find(this.wrapper, 'img'), this.refresh.bind(this))
  }

  refresh() {
    if (this.config.debug) console.log('%c WASABI DEBUG ', 'background: #2d2d2d color: #b0dd44')

    this.zones = []
    this.snaps = []

    this.windowHeight = window.innerHeight
    this.halfHeight = this.windowHeight/2

    if (this.wrapper) this.wrapperHeight = height(this.wrapper)
    if (this.config.debug) remove('#wasabi-debug .wasabi-marker')

    if (typeof this.config.zones == 'string') {
      forElements(this.config.zones, (element) => {
        this.addZone({}, element)
      })
    }
    else {
      let i = this.config.zones.length
      while (i--) {
        let zoneConfig = this.config.zones[i]

        if (zoneConfig.selector) {
          forElements(zoneConfig.selector, (element) => {
            this.addZone(zoneConfig, element)
          })
        }
        else {
          this.addZone(zoneConfig)
        }
      }
    }

    if (this.snaps.length) {
      if (!this.scroller) {
        console.error('snap option needs a SmoothScroller instance')
      }

      this.snaps.sort((a, b) => {
        return a.top - b.top
      })

      this.currentSnap = this.snaps[this.currentSnapIndex]
    }
  }

  addZone(zoneConfig, element) {
    let zone = {},
        top, bottom

    if (element) {
      zone.element = element
      zone.selector = zoneConfig.selector
      top = screenPosition(element).top + this.scrollTop
      bottom = top + height(element)

      zone.parallax = []
      forElements(find(element, '[data-wasabi]'), (pxElement) => {
        let options = eval('('+data(pxElement, 'wasabi')+')')

        let toX = (typeof options.x !== 'undefined') ? options.x : ((options.to && options.to.x) || 0),
            toY = (typeof options.y !== 'undefined') ? options.y : ((options.to && options.to.y) || 0),
            fromX = (options.from && options.from.x) || 0,
            fromY = (options.from && options.from.y) || 0,
            parentSize = size(element.parentNode)

        if (typeof toX == 'string' && toX.indexOf('%') != -1)
            toX = parseInt(toX, 10) * parentSize.width

        if (typeof toY == 'string' && toY.indexOf('%') != -1)
            toY = parseInt(toY, 10) * parentSize.height

        if (typeof fromX == 'string' && fromX.indexOf('%') != -1)
            fromX = parseInt(fromX, 10) * parentSize.width

        if (typeof fromY == 'string' && fromY.indexOf('%') != -1)
            fromY = parseInt(fromY, 10) * parentSize.height

        zone.parallax.push({
            element: pxElement,
            toX: toX,
            toY: toY,
            fromX: fromX,
            fromY: fromY
        })
      })
    }
    else {
      top = zoneConfig.top
      bottom = zoneConfig.bottom
    }

    let offset = defaultify(zoneConfig.offset, this.config.offset)
    zone.offset = {
        top: defaultify(offset.top, offset),
        bottom: defaultify(offset.bottom, offset)
    }

    zone.top = top - zone.offset.top
    zone.bottom = bottom + zone.offset.bottom

    if (this.config.debug) {
      let color = randomColor()

      console.log(zone.selector +' %c ' + color, 'color:'+color)
      console.log(zone.element)

      let topDebug = createElement(`<div class="wasabi-marker"></div>`)
      append(this.debugWrapper, topDebug)
      style(topDebug, {
        position: 'absolute',
        top: zone.top,
        right: 0,
        width: 25,
        height: 2,
        background: color
      })

      let bottomDebug = clone(topDebug)
      append(this.debugWrapper, bottomDebug)
      style(bottomDebug, {
        'z-index': 9999,
        position: 'absolute',
        top: zone.bottom,
        right: 0,
        width: 25,
        height: 2,
        background: color
      })
    }

    zone.size = zone.bottom - zone.top
    zone.handle = zoneConfig.handle || this.config.handle
    zone.progress = zoneConfig.progress || this.config.progress
    zone.snap = zoneConfig.snap || this.config.snap
    zone.handler = zoneConfig.handler || this.config.handler
    zone.enter = zoneConfig.enter || this.config.enter
    zone.leave = zoneConfig.leave || this.config.leave

    if (zoneConfig.tween) {
      zone.tween = zoneConfig.tween
      if (zone.tween.pause) zone.tween.pause()
    }

    if (zoneConfig.progressTween) {
      zone.progressTween = zoneConfig.progressTween
      if (zone.progressTween.pause) zone.progressTween.pause()
    }

    let handles = {}
    let handleForward = zone.handle.forward || zone.handle
    handles.forward = {
      top: handleForward.top || handleForward,
      bottom: handleForward.bottom || handleForward
    }
    let handleBackward = zone.handle.forward || zone.handle
    handles.backward = {
      top: handleBackward.top || handleBackward,
      bottom: handleBackward.bottom || handleBackward
    }

    if (handles.forward.top == 'middle') {
      zone.forwardTop = zone.top + this.halfHeight
    }
    else if (handles.forward.top == 'bottom') {
      zone.forwardTop = zone.top - this.windowHeight
    }
    else {
      zone.forwardTop = zone.top
    }

    if (handles.forward.bottom == 'middle') {
      zone.forwardBottom = zone.bottom + this.halfHeight
    }
    else if (handles.forward.bottom == 'bottom') {
      zone.forwardBottom = zone.bottom - this.windowHeight
    }
    else {
      zone.forwardBottom = zone.bottom
    }

    zone.forwardSize = Math.max(this.config.stepMinSize, zone.forwardBottom - zone.forwardTop)

    if (handles.backward.top == 'middle') {
      zone.backwardTop = zone.top + this.halfHeight
    }
    else if (handles.backward.top == 'bottom') {
      zone.backwardTop = zone.top - this.windowHeight
    }
    else {
      zone.backwardTop = zone.top
    }

    if (handles.backward.bottom == 'middle') {
      zone.backwardBottom = zone.bottom + this.halfHeight
    }
    else if (handles.backward.bottom == 'bottom') {
      zone.backwardBottom = zone.bottom - this.windowHeight
    }
    else {
      zone.backwardBottom = zone.bottom
    }

    zone.backwardSize = Math.max(this.config.stepMinSize, zone.backwardBottom - zone.backwardTop)

    if (zone.snap) this.snaps.push(zone)

    this.zones.push(zone)
  }

  testSnapping(scrollTarget) {
    if (this.scroller.scrollDisabled || !this.snaps.length) return

    let previous = this.snaps[this.currentSnapIndex-1],
        next = this.snaps[this.currentSnapIndex+1]

    if (previous && scrollTarget.y < this.currentSnap.top) {
      --this.currentSnapIndex
      this.currentSnap = previous

      this.scroller.scrollTarget.y = this.currentSnap.top + this.currentSnap.offset.top
      this.scroller.scrollTo({
        x: 0,
        y: (previous.bottom - this.currentSnap.offset.bottom) - Math.min(previous.size, this.windowHeight)-1
      })
    }
    else if (next && scrollTarget.y > this.currentSnap.bottom - this.windowHeight) {
      ++this.currentSnapIndex
      this.currentSnap = next

      this.scroller.scrollTarget.y = this.currentSnap.bottom - this.windowHeight - this.currentSnap.offset.bottom
      this.scroller.scrollTo({
        x: 0,
        y: (next.top + this.currentSnap.offset.top)+1
      })
    }
  }

  onScroller(scrollTarget) {
    this.scrollTop = this.scroller.scroll.y
    this.testSnapping(scrollTarget)
  }

  onScrollEvent(event) {
    this.scrollTop = screenPosition(this.wrapper).top
  }

  update() {
    if (!this.running) return

    let i = this.zones.length,
        direction = this.previousScrollTop < this.scrollTop ? 'forward' : 'backward'

    while (i--) {
      let zone = this.zones[i], entered, progress

      progress = (this.scrollTop - zone[direction+'Top'])/zone[direction+'Size']
      entered = progress >= 0 && progress <= 1

      if (!zone.entered && entered) {
        if (zone.tween) zone.tween.resume()
        if(zone.handler) zone.handler('enter', direction, zone.selector, zone.element)
        if(zone.enter) zone.enter(direction, zone.selector, zone.element)

        if(zone.snap) {
            this.currentSnapIndex = this.snaps.indexOf(zone)
            this.currentSnap = this.snaps[this.currentSnapIndex]
        }
      }
      else if (zone.entered && !entered) {
          if(zone.handler) zone.handler('leave', direction, zone.selector, zone.element)
        if(zone.leave) zone.leave(direction, zone.selector, zone.element)
      }

      forEach(zone.parallax, (item) => {
        transform(item.element, {
          x: item.fromX + (item.toX - item.fromX) * progress,
          y: item.fromY + (item.toY - item.fromY) * progress
        })
      })

      zone.entered = entered
      if (zone.entered) {
        if (zone.progress) zone.progress(direction, progress, zone.selector)
        if (zone.progressTween && zone.progressTween.progress) zone.progressTween.progress(progress)
      }
    }

    this.previousScrollTop = this.scrollTop

    this.updateRequest = requestAnimationFrame(this.update.bind(this))
  }

  kill() {
    this.running = false

    unresize(this.resizeCallback)
    cancelAnimationFrame(this.updateRequest)

    remove(this.debugWrapper)

    if (this.scrollEventsCallback) {
      this.scrollEventsManager.off(this.scrollEventsCallback)
    }
    else if (this.scrollerCallback) {
      this.scroller.off('update', this.scrollerCallback)
    }

    let i = this.zones.length
    while(i--) {
      let zone = this.zones[i]

      if (zone.tween) this.killTimeline(zone.tween)
      if (zone.progressTween) this.killTimeline(zone.progressTween)
    }

    this.zones = this.snaps = null
  }

  concatenateVars(object) {
    if (!object) return

    let keys = Object.keys(object),
        i = keys.length,
        vars = []

    while(i--) {
        if (typeof object[keys[i]] == 'object') {
            vars = vars.concat(this.concatenateVars(object[keys[i]]))
        }
        else {
            let key = keys[i]
            vars.push(key == 'x' || key == 'y' || key == 'scale' || key == 'rotate' ? 'transform' : key)
        }
    }

    return vars
  }

  killTimeline(timeline) {
    let tweens = timeline.getChildren()
    timeline.kill()

    let i = tweens.length, tween
    while(i--) {
      tween = tweens[i]

      if (tween.target) {
        TweenLite.set(tween.target, {
          clearProps: this.concatenateVars(tween.vars).join(',')
        })
      }
    }
  }
}

export default Wasabi
<|endoftext|>


<commit_before>import SortedIndex from './SortedIndex';
import Bitmaps from './Bitmaps';
import {Transform} from 'vega-dataflow';
import {inherits} from 'vega-util';

/**
 * An indexed multi-dimensional filter.
 * @constructor
 * @param {object} params - The parameters for this operator.
 * @param {Array<function(object): *>} params.fields - An array of dimension accessors to filter.
 * @param {Array} params.query - An array of per-dimension range queries.
 */
export default function CrossFilter(params) {
  Transform.call(this, Bitmaps(), params);
  this.data = [];
  this.index = null;
}

function Dimension(index, field, query) {
  var dim = SortedIndex();
  dim.one = (1 << index);
  dim.zero = ~dim.one;
  dim.field = field;
  dim.range = query.slice();
  dim.add = function(data, curr, k) {
    var dim = this,
        one = dim.one,
        added = dim.insert(dim.field, data, k),
        range = dim.bisect(dim.range, added.value),
        index = added.index,
        lo = range[0],
        hi = range[1],
        n1 = index.length, i;

    for (i=0;  i<lo; ++i) curr[index[i]] |= one;
    for (i=hi; i<n1; ++i) curr[index[i]] |= one;
  };
  return dim;
}

var prototype = inherits(CrossFilter, Transform);

prototype.transform = function(_, pulse) {
  if (!this.index) {
    return this.init(_, pulse);
  } else {
    var init = _.modified('fields')
          || _.fields.some(function(f) { return pulse.modified(f.fields); });

    return init
      ? this.reinit(_, pulse)
      : this.eval(_, pulse);
  }
};

prototype.init = function(_, pulse) {
  var fields = _.fields,
      query = _.query,
      m = query.length,
      dims = (this.index = Array(m)), q;

  // instantiate dimensions
  for (q=0; q<m; ++q) {
    dims[q] = Dimension(q, fields[q], query[q]);
  }

  return this.eval(_, pulse);
};

prototype.reinit = function(_, pulse) {
  var output = pulse.materialize().fork(),
      fields = _.fields,
      query = _.query,
      m = query.length,
      dims = this.index,
      bits = this.value,
      curr = bits.curr(),
      prev = bits.prev(),
      all = bits.all(),
      out = (output.rem = output.add),
      mod = output.mod,
      mods, remMap, modMap, i, n, f, q;

  // set prev to current state
  prev.set(curr);

  // if pulse has remove tuples, process them first
  if (pulse.rem.length) {
    remMap = this.remove(_, pulse, output);
  }

  // if pulse has added tuples, add them to state
  if (pulse.add.length) {
    bits.add(pulse.add);
  }

  // if pulse has modified tuples, create an index map
  if (pulse.mod.length) {
    modMap = {};
    for (mods=pulse.mod, i=0, n=mods.length; i<n; ++i) {
      modMap[mods[i]._index] = 1;
    }
  }

  // re-initialize indices as needed, update curr bitmap
  for (q=0; q<m; ++q) {
    f = fields[q];
    if (!dims[q] || _.modified('fields', q) || pulse.modified(f.fields)) {
      dims[q] = Dimension(q, fields[q], query[q]);
      dims[q].add(pulse.source, curr, 0);
    }
  }

  // visit each tuple
  // if filter state changed, push index to add/rem
  // else if in mod and passes a filter, push index to mod
  for (i=0, n=bits.data().length; i<n; ++i) {
    if (remMap[i]) { // skip if removed tuple
      continue;
    } else if (prev[i] !== curr[i]) { // add if state changed
      out.push(i);
    } else if (modMap[i] && curr[i] !== all) { // otherwise, pass mods through
      mod.push(i);
    }
  }

  bits.mask = (1 << m) - 1;
  return output;
};

prototype.eval = function(_, pulse) {
  var output = pulse.materialize().fork(),
      m = this.index.length,
      mask = 0;

  if (pulse.rem.length) {
    this.remove(_, pulse, output);
    mask |= (1 << m) - 1;
  }

  if (_.modified('query') && !_.modified('fields')) {
    mask |= this.update(_, pulse, output);
  }

  if (pulse.add.length) {
    this.insert(_, pulse, output);
    mask |= (1 << m) - 1;
  }

  if (pulse.mod.length) {
    this.modify(pulse, output);
    mask |= (1 << m) - 1;
  }

  this.value.mask = mask;
  return output;
};

prototype.insert = function(_, pulse, output) {
  var tuples = pulse.add,
      bits = this.value,
      dims = this.index,
      out = output.add,
      k = bits.size(),
      n = k + tuples.length,
      m = dims.length, j;

  // resize bitmaps and add tuples as needed
  bits.resize(n, m);
  bits.add(tuples);

  var curr = bits.curr(),
      prev = bits.prev(),
      all  = bits.all();

  // add to dimensional indices
  for (j=0; j<m; ++j) {
    dims[j].add(tuples, curr, k);
  }

  // set previous filters, output if passes at least one filter
  for (; k<n; ++k) {
    prev[k] = all;
    if (curr[k] !== all) out.push(k);
  }
};

prototype.modify = function(pulse, output) {
  var out = output.mod,
      bits = this.value,
      curr = bits.curr(),
      all  = bits.all(),
      tuples = pulse.mod,
      i, n, k;

  for (i=0, n=tuples.length; i<n; ++i) {
    k = tuples[i]._index;
    if (curr[k] !== all) out.push(k);
  }
};

prototype.remove = function(_, pulse, output) {
  var dims = this.index,
      bits = this.value,
      curr = bits.curr(),
      prev = bits.prev(),
      all  = bits.all(),
      map = {},
      out = output.rem,
      tuples = pulse.rem,
      i, j, n, m, k, f;

  // process tuples, output if passes at least one filter
  for (i=0, n=tuples.length; i<n; ++i) {
    k = tuples[i]._index;
    map[k] = 1; // build index map
    prev[k] = (f = curr[k]);
    curr[k] = all;
    if (f !== all) out.push(k);
  }

  // remove from dimensional indices
  for (j=0, m=dims.length; j<m; ++j) {
    dims[j].remove(n, map);
  }

  return (this.reindex(pulse, n, map), map);
};

// reindex filters and indices after propagation completes
prototype.reindex = function(pulse, num, map) {
  var bits = this.value,
      dims = this.index;

  pulse.runAfter(function() {
    var indexMap = bits.remove(num, map);
    dims.forEach(function(dim) {
      dim.reindex(indexMap);
    });
  });
};

prototype.update = function(_, pulse, output) {
  var dims = this.index,
      query = _.query,
      stamp = pulse.stamp,
      m = dims.length,
      mask = 0, i, q;

  // survey how many queries have changed
  output.filters = 0;
  for (q=0; q<m; ++q) {
    if (_.modified('query', q)) { i = q; ++mask; }
  }

  if (mask === 1) {
    // only one query changed, use more efficient update
    mask = dims[i].one;
    this.incrementOne(dims[i], query[i], output.add, output.rem);
  } else {
    // multiple queries changed, perform full record keeping
    for (q=0, mask=0; q<m; ++q) {
      if (!_.modified('query', q)) continue;
      mask |= dims[q].one;
      this.incrementAll(dims[q], query[q], stamp, output.add);
      output.rem = output.add; // duplicate add/rem for downstream resolve
    }
  }

  return mask;
};

prototype.incrementAll = function(dim, query, stamp, out) {
  var bits = this.value,
      seen = bits.seen(),
      curr = bits.curr(),
      prev = bits.prev(),
      index = dim.index(),
      old = dim.bisect(dim.range),
      range = dim.bisect(query),
      lo1 = range[0],
      hi1 = range[1],
      lo0 = old[0],
      hi0 = old[1],
      one = dim.one,
      i, j, k;

  // Fast incremental update based on previous lo index.
  if (lo1 < lo0) {
    for (i = lo1, j = Math.min(lo0, hi1); i < j; ++i) {
      k = index[i];
      if (seen[k] !== stamp) {
        prev[k] = curr[k];
        seen[k] = stamp;
        out.push(k);
      }
      curr[k] ^= one;
    }
  } else if (lo1 > lo0) {
    for (i = lo0, j = Math.min(lo1, hi0); i < j; ++i) {
      k = index[i];
      if (seen[k] !== stamp) {
        prev[k] = curr[k];
        seen[k] = stamp;
        out.push(k);
      }
      curr[k] ^= one;
    }
  }

  // Fast incremental update based on previous hi index.
  if (hi1 > hi0) {
    for (i = Math.max(lo1, hi0), j = hi1; i < j; ++i) {
      k = index[i];
      if (seen[k] !== stamp) {
        prev[k] = curr[k];
        seen[k] = stamp;
        out.push(k);
      }
      curr[k] ^= one;
    }
  } else if (hi1 < hi0) {
    for (i = Math.max(lo0, hi1), j = hi0; i < j; ++i) {
      k = index[i];
      if (seen[k] !== stamp) {
        prev[k] = curr[k];
        seen[k] = stamp;
        out.push(k);
      }
      curr[k] ^= one;
    }
  }

  dim.range = query.slice();
};

prototype.incrementOne = function(dim, query, add, rem) {
  var bits = this.value,
      curr = bits.curr(),
      index = dim.index(),
      old = dim.bisect(dim.range),
      range = dim.bisect(query),
      lo1 = range[0],
      hi1 = range[1],
      lo0 = old[0],
      hi0 = old[1],
      one = dim.one,
      i, j, k;

  // Fast incremental update based on previous lo index.
  if (lo1 < lo0) {
    for (i = lo1, j = Math.min(lo0, hi1); i < j; ++i) {
      k = index[i];
      curr[k] ^= one;
      add.push(k);
    }
  } else if (lo1 > lo0) {
    for (i = lo0, j = Math.min(lo1, hi0); i < j; ++i) {
      k = index[i];
      curr[k] ^= one;
      rem.push(k);
    }
  }

  // Fast incremental update based on previous hi index.
  if (hi1 > hi0) {
    for (i = Math.max(lo1, hi0), j = hi1; i < j; ++i) {
      k = index[i];
      curr[k] ^= one;
      add.push(k);
    }
  } else if (hi1 < hi0) {
    for (i = Math.max(lo0, hi1), j = hi0; i < j; ++i) {
      k = index[i];
      curr[k] ^= one;
      rem.push(k);
    }
  }

  dim.range = query.slice();
};
<commit_msg>Remove dead code.<commit_after>import SortedIndex from './SortedIndex';
import Bitmaps from './Bitmaps';
import {Transform} from 'vega-dataflow';
import {inherits} from 'vega-util';

/**
 * An indexed multi-dimensional filter.
 * @constructor
 * @param {object} params - The parameters for this operator.
 * @param {Array<function(object): *>} params.fields - An array of dimension accessors to filter.
 * @param {Array} params.query - An array of per-dimension range queries.
 */
export default function CrossFilter(params) {
  Transform.call(this, Bitmaps(), params);
  this.index = null;
}

function Dimension(index, field, query) {
  var dim = SortedIndex();
  dim.one = (1 << index);
  dim.zero = ~dim.one;
  dim.field = field;
  dim.range = query.slice();
  dim.add = function(data, curr, k) {
    var dim = this,
        one = dim.one,
        added = dim.insert(dim.field, data, k),
        range = dim.bisect(dim.range, added.value),
        index = added.index,
        lo = range[0],
        hi = range[1],
        n1 = index.length, i;

    for (i=0;  i<lo; ++i) curr[index[i]] |= one;
    for (i=hi; i<n1; ++i) curr[index[i]] |= one;
  };
  return dim;
}

var prototype = inherits(CrossFilter, Transform);

prototype.transform = function(_, pulse) {
  if (!this.index) {
    return this.init(_, pulse);
  } else {
    var init = _.modified('fields')
          || _.fields.some(function(f) { return pulse.modified(f.fields); });

    return init
      ? this.reinit(_, pulse)
      : this.eval(_, pulse);
  }
};

prototype.init = function(_, pulse) {
  var fields = _.fields,
      query = _.query,
      m = query.length,
      dims = (this.index = Array(m)), q;

  // instantiate dimensions
  for (q=0; q<m; ++q) {
    dims[q] = Dimension(q, fields[q], query[q]);
  }

  return this.eval(_, pulse);
};

prototype.reinit = function(_, pulse) {
  var output = pulse.materialize().fork(),
      fields = _.fields,
      query = _.query,
      m = query.length,
      dims = this.index,
      bits = this.value,
      curr = bits.curr(),
      prev = bits.prev(),
      all = bits.all(),
      out = (output.rem = output.add),
      mod = output.mod,
      mods, remMap, modMap, i, n, f, q;

  // set prev to current state
  prev.set(curr);

  // if pulse has remove tuples, process them first
  if (pulse.rem.length) {
    remMap = this.remove(_, pulse, output);
  }

  // if pulse has added tuples, add them to state
  if (pulse.add.length) {
    bits.add(pulse.add);
  }

  // if pulse has modified tuples, create an index map
  if (pulse.mod.length) {
    modMap = {};
    for (mods=pulse.mod, i=0, n=mods.length; i<n; ++i) {
      modMap[mods[i]._index] = 1;
    }
  }

  // re-initialize indices as needed, update curr bitmap
  for (q=0; q<m; ++q) {
    f = fields[q];
    if (!dims[q] || _.modified('fields', q) || pulse.modified(f.fields)) {
      dims[q] = Dimension(q, fields[q], query[q]);
      dims[q].add(pulse.source, curr, 0);
    }
  }

  // visit each tuple
  // if filter state changed, push index to add/rem
  // else if in mod and passes a filter, push index to mod
  for (i=0, n=bits.data().length; i<n; ++i) {
    if (remMap[i]) { // skip if removed tuple
      continue;
    } else if (prev[i] !== curr[i]) { // add if state changed
      out.push(i);
    } else if (modMap[i] && curr[i] !== all) { // otherwise, pass mods through
      mod.push(i);
    }
  }

  bits.mask = (1 << m) - 1;
  return output;
};

prototype.eval = function(_, pulse) {
  var output = pulse.materialize().fork(),
      m = this.index.length,
      mask = 0;

  if (pulse.rem.length) {
    this.remove(_, pulse, output);
    mask |= (1 << m) - 1;
  }

  if (_.modified('query') && !_.modified('fields')) {
    mask |= this.update(_, pulse, output);
  }

  if (pulse.add.length) {
    this.insert(_, pulse, output);
    mask |= (1 << m) - 1;
  }

  if (pulse.mod.length) {
    this.modify(pulse, output);
    mask |= (1 << m) - 1;
  }

  this.value.mask = mask;
  return output;
};

prototype.insert = function(_, pulse, output) {
  var tuples = pulse.add,
      bits = this.value,
      dims = this.index,
      out = output.add,
      k = bits.size(),
      n = k + tuples.length,
      m = dims.length, j;

  // resize bitmaps and add tuples as needed
  bits.resize(n, m);
  bits.add(tuples);

  var curr = bits.curr(),
      prev = bits.prev(),
      all  = bits.all();

  // add to dimensional indices
  for (j=0; j<m; ++j) {
    dims[j].add(tuples, curr, k);
  }

  // set previous filters, output if passes at least one filter
  for (; k<n; ++k) {
    prev[k] = all;
    if (curr[k] !== all) out.push(k);
  }
};

prototype.modify = function(pulse, output) {
  var out = output.mod,
      bits = this.value,
      curr = bits.curr(),
      all  = bits.all(),
      tuples = pulse.mod,
      i, n, k;

  for (i=0, n=tuples.length; i<n; ++i) {
    k = tuples[i]._index;
    if (curr[k] !== all) out.push(k);
  }
};

prototype.remove = function(_, pulse, output) {
  var dims = this.index,
      bits = this.value,
      curr = bits.curr(),
      prev = bits.prev(),
      all  = bits.all(),
      map = {},
      out = output.rem,
      tuples = pulse.rem,
      i, j, n, m, k, f;

  // process tuples, output if passes at least one filter
  for (i=0, n=tuples.length; i<n; ++i) {
    k = tuples[i]._index;
    map[k] = 1; // build index map
    prev[k] = (f = curr[k]);
    curr[k] = all;
    if (f !== all) out.push(k);
  }

  // remove from dimensional indices
  for (j=0, m=dims.length; j<m; ++j) {
    dims[j].remove(n, map);
  }

  return (this.reindex(pulse, n, map), map);
};

// reindex filters and indices after propagation completes
prototype.reindex = function(pulse, num, map) {
  var bits = this.value,
      dims = this.index;

  pulse.runAfter(function() {
    var indexMap = bits.remove(num, map);
    dims.forEach(function(dim) {
      dim.reindex(indexMap);
    });
  });
};

prototype.update = function(_, pulse, output) {
  var dims = this.index,
      query = _.query,
      stamp = pulse.stamp,
      m = dims.length,
      mask = 0, i, q;

  // survey how many queries have changed
  output.filters = 0;
  for (q=0; q<m; ++q) {
    if (_.modified('query', q)) { i = q; ++mask; }
  }

  if (mask === 1) {
    // only one query changed, use more efficient update
    mask = dims[i].one;
    this.incrementOne(dims[i], query[i], output.add, output.rem);
  } else {
    // multiple queries changed, perform full record keeping
    for (q=0, mask=0; q<m; ++q) {
      if (!_.modified('query', q)) continue;
      mask |= dims[q].one;
      this.incrementAll(dims[q], query[q], stamp, output.add);
      output.rem = output.add; // duplicate add/rem for downstream resolve
    }
  }

  return mask;
};

prototype.incrementAll = function(dim, query, stamp, out) {
  var bits = this.value,
      seen = bits.seen(),
      curr = bits.curr(),
      prev = bits.prev(),
      index = dim.index(),
      old = dim.bisect(dim.range),
      range = dim.bisect(query),
      lo1 = range[0],
      hi1 = range[1],
      lo0 = old[0],
      hi0 = old[1],
      one = dim.one,
      i, j, k;

  // Fast incremental update based on previous lo index.
  if (lo1 < lo0) {
    for (i = lo1, j = Math.min(lo0, hi1); i < j; ++i) {
      k = index[i];
      if (seen[k] !== stamp) {
        prev[k] = curr[k];
        seen[k] = stamp;
        out.push(k);
      }
      curr[k] ^= one;
    }
  } else if (lo1 > lo0) {
    for (i = lo0, j = Math.min(lo1, hi0); i < j; ++i) {
      k = index[i];
      if (seen[k] !== stamp) {
        prev[k] = curr[k];
        seen[k] = stamp;
        out.push(k);
      }
      curr[k] ^= one;
    }
  }

  // Fast incremental update based on previous hi index.
  if (hi1 > hi0) {
    for (i = Math.max(lo1, hi0), j = hi1; i < j; ++i) {
      k = index[i];
      if (seen[k] !== stamp) {
        prev[k] = curr[k];
        seen[k] = stamp;
        out.push(k);
      }
      curr[k] ^= one;
    }
  } else if (hi1 < hi0) {
    for (i = Math.max(lo0, hi1), j = hi0; i < j; ++i) {
      k = index[i];
      if (seen[k] !== stamp) {
        prev[k] = curr[k];
        seen[k] = stamp;
        out.push(k);
      }
      curr[k] ^= one;
    }
  }

  dim.range = query.slice();
};

prototype.incrementOne = function(dim, query, add, rem) {
  var bits = this.value,
      curr = bits.curr(),
      index = dim.index(),
      old = dim.bisect(dim.range),
      range = dim.bisect(query),
      lo1 = range[0],
      hi1 = range[1],
      lo0 = old[0],
      hi0 = old[1],
      one = dim.one,
      i, j, k;

  // Fast incremental update based on previous lo index.
  if (lo1 < lo0) {
    for (i = lo1, j = Math.min(lo0, hi1); i < j; ++i) {
      k = index[i];
      curr[k] ^= one;
      add.push(k);
    }
  } else if (lo1 > lo0) {
    for (i = lo0, j = Math.min(lo1, hi0); i < j; ++i) {
      k = index[i];
      curr[k] ^= one;
      rem.push(k);
    }
  }

  // Fast incremental update based on previous hi index.
  if (hi1 > hi0) {
    for (i = Math.max(lo1, hi0), j = hi1; i < j; ++i) {
      k = index[i];
      curr[k] ^= one;
      add.push(k);
    }
  } else if (hi1 < hi0) {
    for (i = Math.max(lo0, hi1), j = hi0; i < j; ++i) {
      k = index[i];
      curr[k] ^= one;
      rem.push(k);
    }
  }

  dim.range = query.slice();
};
<|endoftext|>


<commit_before>define('parsley/utils', function () {
  return {
    // Parsley DOM-API
    // returns object from dom attributes and values
    // if attr is given, returns bool if attr present in DOM or not
    attr: function ($element, namespace, checkAttr) {
      var attribute,
        obj = {},
        regex = new RegExp('^' + namespace, 'i');

      if ('undefined' === typeof $element || 'undefined' === typeof $element[0])
        return {};

      for (var i in $element[0].attributes) {
        attribute = $element[0].attributes[i];
        if ('undefined' !== typeof attribute && null !== attribute && attribute.specified && regex.test(attribute.name)) {
          if ('undefined' !== typeof checkAttr && new RegExp(checkAttr, 'i').test(attribute.name))
              return true;

          obj[this.camelize(attribute.name.replace(namespace, ''))] = this.deserializeValue(attribute.value);
        }
      }

      return 'undefined' === typeof checkAttr ? obj : false;
    },

    // Recursive object / array getter
    get: function (obj, path, placeholder) {
      var i = 0,
      paths = (path || '').split('.');

      while (this.isObject(obj) || this.isArray(obj)) {
        obj = obj[paths[i++]];
        if (i === paths.length)
          return obj || placeholder;
      }

      return placeholder;
    },

    // {foo: bar, bar: baz} => [{key: foo, value: bar}, {key: bar, value: baz}]
    keyValue: function (object) {
      var keyValue = [];

      for (var key in object)
        keyValue.push({
          key: key,
          value: object[key]
        });

      return 1 === keyValue.length ? keyValue[0] : keyValue;
    },

    makeObject: function () {
      var object = {};
      for (var i = 0; i < arguments.length; i += 2)
        object[arguments[i]] = arguments[i+1];

      return object;
    },

    hash: function (length) {
      return new String(Math.random()).substring(2, length ? length + 2 : 9);
    },

    /** Third party functions **/
    // Underscore isArray
    isArray: function (mixed) {
      return Object.prototype.toString.call(mixed) === '[object Array]';
    },

    // Underscore isObject
    isObject: function (mixed) {
      return mixed === Object(mixed);
    },

    // Zepto deserialize function
    deserializeValue: function (value) {
      var num
      try {
        return value ?
          value == "true" ||
          (value == "false" ? false :
          value == "null" ? null :
          !isNaN(num = Number(value)) ? num :
          /^[\[\{]/.test(value) ? $.parseJSON(value) :
          value)
          : value;
      } catch (e) { return value; }
    },

    // Zepto camelize function
    camelize: function (str) {
      return str.replace(/-+(.)?/g, function(match, chr) {
        return chr ? chr.toUpperCase() : '';
      });
    },

    // Zepto dasherize function
    dasherize: function (str) {
      return str.replace(/::/g, '/')
             .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
             .replace(/([a-z\d])([A-Z])/g, '$1_$2')
             .replace(/_/g, '-')
             .toLowerCase();
    }
  };
});
<commit_msg>- removed deprecated ParsleyUtils methods<commit_after>define('parsley/utils', function () {
  return {
    // Parsley DOM-API
    // returns object from dom attributes and values
    // if attr is given, returns bool if attr present in DOM or not
    attr: function ($element, namespace, checkAttr) {
      var attribute,
        obj = {},
        regex = new RegExp('^' + namespace, 'i');

      if ('undefined' === typeof $element || 'undefined' === typeof $element[0])
        return {};

      for (var i in $element[0].attributes) {
        attribute = $element[0].attributes[i];
        if ('undefined' !== typeof attribute && null !== attribute && attribute.specified && regex.test(attribute.name)) {
          if ('undefined' !== typeof checkAttr && new RegExp(checkAttr, 'i').test(attribute.name))
              return true;

          obj[this.camelize(attribute.name.replace(namespace, ''))] = this.deserializeValue(attribute.value);
        }
      }

      return 'undefined' === typeof checkAttr ? obj : false;
    },

    // Recursive object / array getter
    get: function (obj, path, placeholder) {
      var i = 0,
      paths = (path || '').split('.');

      while (this.isObject(obj) || this.isArray(obj)) {
        obj = obj[paths[i++]];
        if (i === paths.length)
          return obj || placeholder;
      }

      return placeholder;
    },

    hash: function (length) {
      return new String(Math.random()).substring(2, length ? length + 2 : 9);
    },

    /** Third party functions **/
    // Underscore isArray
    isArray: function (mixed) {
      return Object.prototype.toString.call(mixed) === '[object Array]';
    },

    // Underscore isObject
    isObject: function (mixed) {
      return mixed === Object(mixed);
    },

    // Zepto deserialize function
    deserializeValue: function (value) {
      var num
      try {
        return value ?
          value == "true" ||
          (value == "false" ? false :
          value == "null" ? null :
          !isNaN(num = Number(value)) ? num :
          /^[\[\{]/.test(value) ? $.parseJSON(value) :
          value)
          : value;
      } catch (e) { return value; }
    },

    // Zepto camelize function
    camelize: function (str) {
      return str.replace(/-+(.)?/g, function(match, chr) {
        return chr ? chr.toUpperCase() : '';
      });
    },

    // Zepto dasherize function
    dasherize: function (str) {
      return str.replace(/::/g, '/')
             .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
             .replace(/([a-z\d])([A-Z])/g, '$1_$2')
             .replace(/_/g, '-')
             .toLowerCase();
    }
  };
});
<|endoftext|>


<commit_before>/**
 * Patterns checklist - Easily (un)check all checkboxes
 *
 * Copyright 2012-2013 Simplon B.V. - Simplon B.V. - Wichert Akkerman
 * Copyright 2012-2013 Florian Friesdorf
 */
define([
    "jquery",
    "../core/parser",
    "../registry"
], function($, Parser, registry) {
    var parser = new Parser("checklist");
    parser.add_argument("select", ".functions .select-all");
    parser.add_argument("deselect", ".functions .deselect-all");

    var _ = {
        name: "checklist",
        trigger: ".pat-checklist",
        jquery_plugin: true,

        init: function($el, opts) {
            return $el.each(function() {
                var $trigger = $(this),
                    options = parser.parse($trigger, opts, false);

                $trigger.data("patternChecklist", options);
                $trigger.find(options.select)
                    .on("click.checklist", {trigger: $trigger}, _.onSelectAll);
                $trigger.find(options.deselect)
                    .on("click.checklist", {trigger: $trigger}, _.onDeselectAll);
                $trigger.on("change.checklist", "input[type=checkbox]", {trigger: $trigger}, _.onChange);
            });
        },

        destroy: function($el) {
            return $el.each(function() {
                var $trigger = $(this),
                    options = $trigger.data("patternChecklist");
                $trigger.find(options.select).off("click.checklist");
                $trigger.find(options.deselect).off("click.checklist");
                $trigger.off("change.checklist", "input[type=checkbox]");
                $trigger.data("patternChecklist", null);
            });
        },

        onChange: function(event) {
            var $trigger = event.data.trigger,
                options = $trigger.data("patternChecklist"),
                deselect = $trigger.find(options.deselect),
                select = $trigger.find(options.select);

            if (($trigger.find("input[type=checkbox]:visible:checked").length===0) &&
                (!deselect.prop("disabled"))) {
                deselect.attr({disabled: "disabled"});
            } else if (deselect.prop("disabled")) {
                deselect.prop("disabled", false);
            }

            if (($trigger.find("input[type=checkbox]:visible:not(:checked)").length===0) &&
                (!select.prop("disabled"))) {
                select.attr({disabled: "disabled"});
            } else if (select.prop("disabled")) {
                select.prop("disabled", false);
            }
        },

        onSelectAll: function(event) {
            var $trigger = event.data.trigger,
                options = $trigger.data("patternChecklist");
            $trigger.find("input[type=checkbox]:not(:checked)").prop("checked", true).trigger("change");
            $trigger.find(options.deselect).prop("disabled", false);
            $trigger.find(options.select).attr({disabled: "disabled"});
            $trigger.change();
            event.preventDefault();
        },

        onDeselectAll: function(event) {
            var $trigger = event.data.trigger,
                options = $trigger.data("patternChecklist");
            $trigger.find("input[type=checkbox]:checked").prop("checked", false).trigger("change");
            $trigger.find(options.select).prop("disabled", false);
            $trigger.find(options.deselect).attr({disabled: "disabled"});
            $trigger.change();
            event.preventDefault();
        }
    };

    registry.register(_);
    return _;
});

// jshint indent: 4, browser: true, jquery: true, quotmark: double
// vim: sw=4 expandtab
<commit_msg>fix namespacing for pat-checklist<commit_after>/**
 * Patterns checklist - Easily (un)check all checkboxes
 *
 * Copyright 2012-2013 Simplon B.V. - Simplon B.V. - Wichert Akkerman
 * Copyright 2012-2013 Florian Friesdorf
 */
define([
    "jquery",
    "../core/parser",
    "../registry"
], function($, Parser, registry) {
    var parser = new Parser("checklist");
    parser.add_argument("select", ".functions .select-all");
    parser.add_argument("deselect", ".functions .deselect-all");

    var _ = {
        name: "checklist",
        trigger: ".pat-checklist",
        jquery_plugin: true,

        init: function($el, opts) {
            return $el.each(function() {
                var $trigger = $(this),
                    options = parser.parse($trigger, opts, false);

                $trigger.data("patternChecklist", options);
                $trigger.find(options.select)
                    .on("click.pat-checklist", {trigger: $trigger}, _.onSelectAll);
                $trigger.find(options.deselect)
                    .on("click.pat-checklist", {trigger: $trigger}, _.onDeselectAll);
                $trigger.on("change.pat-checklist", "input[type=checkbox]", {trigger: $trigger}, _.onChange);
            });
        },

        destroy: function($el) {
            return $el.each(function() {
                var $trigger = $(this),
                    options = $trigger.data("patternChecklist");
                $trigger.find(options.select).off(".pat-checklist");
                $trigger.find(options.deselect).off(".pat-checklist");
                $trigger.off(".pat-checklist", "input[type=checkbox]");
                $trigger.data("patternChecklist", null);
            });
        },

        onChange: function(event) {
            var $trigger = event.data.trigger,
                options = $trigger.data("patternChecklist"),
                deselect = $trigger.find(options.deselect),
                select = $trigger.find(options.select);

            if (($trigger.find("input[type=checkbox]:visible:checked").length===0) &&
                (!deselect.prop("disabled"))) {
                deselect.attr({disabled: "disabled"});
            } else if (deselect.prop("disabled")) {
                deselect.prop("disabled", false);
            }

            if (($trigger.find("input[type=checkbox]:visible:not(:checked)").length===0) &&
                (!select.prop("disabled"))) {
                select.attr({disabled: "disabled"});
            } else if (select.prop("disabled")) {
                select.prop("disabled", false);
            }
        },

        onSelectAll: function(event) {
            var $trigger = event.data.trigger,
                options = $trigger.data("patternChecklist");
            $trigger.find("input[type=checkbox]:not(:checked)").prop("checked", true).trigger("change");
            $trigger.find(options.deselect).prop("disabled", false);
            $trigger.find(options.select).attr({disabled: "disabled"});
            $trigger.change();
            event.preventDefault();
        },

        onDeselectAll: function(event) {
            var $trigger = event.data.trigger,
                options = $trigger.data("patternChecklist");
            $trigger.find("input[type=checkbox]:checked").prop("checked", false).trigger("change");
            $trigger.find(options.select).prop("disabled", false);
            $trigger.find(options.deselect).attr({disabled: "disabled"});
            $trigger.change();
            event.preventDefault();
        }
    };

    registry.register(_);
    return _;
});

// jshint indent: 4, browser: true, jquery: true, quotmark: double
// vim: sw=4 expandtab
<|endoftext|>


<commit_before>define([
    'require',
    '../logging',
    '../patterns'
], function(require) {
    var log = require('../logging').getLogger('edit');

    // create a div after the textarea
    // copy the textarea's content unquoted to the div
    // hide the textarea
    // copy content back before form is serialized
    var text2div = function($el) {
        // hide textarea
        $el.hide();

        // make sure textarea has an id
        // XXX: generate something proper
        var id = $el.attr('id');
        if (!id) {
            id = "my-id-that-should-be-replaced-by-something-unique";
            $el.attr({id: id});
        }

        // create contenteditable div
        var editid = 'edit-' + id,
            $edit = $('
').insertAfter($el);
        $edit.html($el.val());
        $edit.attr({style: 'min-height: 50px'});

        // ensure form is ajaxified and copy content back before serialize
        var ajaxify = require('../patterns').ajaxify.init,
            $form    = $el.parents('form');
        ajaxify($form);
        $form.on('form-pre-serialize', function() {
            $el.html($edit.html());
        });

        return $edit;
    };

    // utility method for determining if something is contenteditable
    var is_contenteditable = function(el) {
        return $(el).is("[contenteditable=true]") || (
            $(el).parents("[contenteditable=true]").length > 0
        );
    };

    // simply replaces
    // rather than toggles, but
    // theres no reason you couldn't have
    // it do both!
    var wrap_selection = function(wrap_html){
        var selection_node = $(window.getSelection().anchorNode);
        if(is_contenteditable(selection_node)) {
            // You just want to unwrap if your
            // parent is already selected
            if(selection_node.parent().is(wrap_html)) {
                selection_node.unwrap();
            }
            else {
                selection_node.wrap("<" + wrap_html + ">");
            }
        }
        // wrap() normally breaks contentEditable
        // this is a hacky replacement
        selection_node.attr('contenteditable', true);
    };

    /*
     * controls and functions to handle them
     */

    var ctrls = {
        b: {
            cmd: 'bold',
            selector: '.strong'
        },
        i: {
            cmd: 'italic',
            selector: '.emphasised'
        },
        ol: {
            cmd: 'insertorderedlist',
            selector: '.list-ordered'
        },
        ul: {
            cmd: 'insertunorderedlist',
            selector: '.list-unordered'
        }
    };

    // generate a cmd function to be used as an event handler
    var cmdfn = function(ctrl, opts) {
        opts = opts || {};
        return function(ev) {
            var $ctrl = $(ev.target);

            // execute command and log about it
            log.debug('exec:', ctrl.cmd, 'triggered by', $ctrl);
            document.execCommand(ctrl.cmd, opts.showui || false, opts.val || '');

            // remove selected if control is in a exclusive group
            $ctrl.parents('.exclusive').each(function() {
                $(this).find('.selected').each(function() {
                    // don't remove selected for the clicked control
                    // it is toggle later on
                    if (this !== ev.target) $(this).removeClass('selected');
                });
            });

            // toggle selected
            $ctrl.toggleClass('selected');
        };
    };

    var initctrls = function(selector) {
        var $ctrls = $(selector);
        for (var tag in ctrls) {
            var ctrl = ctrls[tag],
                $ctrl = $ctrls.find(ctrl.selector);
            if ($ctrl.length === 0) continue;
            log.debug('found control:', tag, $ctrl);
            $ctrl.on('click', cmdfn(ctrl));
        }
        return $ctrls;
    };

    var updatectrls = function($ctrls) {
        // unselect all controls - XXX: is there seriously no better way?
        //$ctrls.find('.selected').removeClass('selected');

        for (var tag in ctrls) {
            var ctrl = ctrls[tag];
            $ctrls.find(ctrl.selector)[
                document.queryCommandState(ctrl.cmd)
                    ? 'addClass'
                    : 'removeClass'
            ]('selected');
        }
    };

    var init = function($el, opts) {
        var $edit = text2div($el),
            $ctrls = initctrls('.editor-controls');

        $edit.on('keyup mouseup', function() {
            updatectrls($ctrls);
        });

        var buttons  = {};
        buttons.clear               = $ctrls.find('.clear');
        buttons.inserth1            = $ctrls.find('.header_1');
        buttons.inserth2            = $ctrls.find('.header_2');
        buttons.inserth3            = $ctrls.find('.header_3');
        buttons.upload_image        = $ctrls.find('.upload_image');
        buttons.link_image          = $ctrls.find('.link_image');

        var button_handler = {
            'insertparagraph'       : function(){ return 0; },
            'inserth1'              : function(){ wrap_selection('h1') },
            'inserth2'              : function(){ wrap_selection('h2') },
            'inserth3'              : function(){ wrap_selection('h3') },
            'clear'                 : function(){
                var selection_node = $(window.getSelection().anchorNode);
                document.execCommand('removeformat');
                if (is_contenteditable(selection_node)) {
                    selection_node.unwrap();
                    if (!$(selection_node).parent().is("p")) {
                        $(selection_node).wrap('
');
                    }
                }
            },
            'upload_image'          : function(){ document.execCommand(); },
            'link_image'            : function(){
                var source = prompt('URL of Image');
                if(source) {
                    document.execCommand('insertImage', false, source);
                }
            }
        };

        // lame helper that
        // toggles the class,
        // triggers the handler
        var button_click = function(element) {
            buttons[element].toggleClass('selected');
            button_handler[element]();
        };

        // bind click to button_click()/1
        for (var key in buttons) {
            buttons[key].click(function(element){
                return function() {
                    log.debug('clicked', element);
                    button_click(element);
                };
            }(key));
        }

    };

    var pattern = {
        markup_trigger: 'form textarea.edit',
        initialised_class: 'edit',
        init: init
    };
    return pattern;
});
<commit_msg>we need filtering to avoid loading/saving malicious stuff<commit_after>define([
    'require',
    '../logging',
    '../patterns'
], function(require) {
    var log = require('../logging').getLogger('edit');

    // create a div after the textarea
    // copy the textarea's content unquoted to the div
    // hide the textarea
    // copy content back before form is serialized
    var text2div = function($el) {
        // hide textarea
        $el.hide();

        // make sure textarea has an id
        // XXX: generate something proper
        var id = $el.attr('id');
        if (!id) {
            id = "my-id-that-should-be-replaced-by-something-unique";
            $el.attr({id: id});
        }

        // create contenteditable div
        var editid = 'edit-' + id,
            $edit = $('
').insertAfter($el);
        // XXX: filter to avoid scripting attacks
        $edit.html($el.val());
        $edit.attr({style: 'min-height: 50px'});

        // ensure form is ajaxified and copy content back before serialize
        var ajaxify = require('../patterns').ajaxify.init,
            $form    = $el.parents('form');
        ajaxify($form);
        $form.on('form-pre-serialize', function() {
            $el.html($edit.html());
        });

        return $edit;
    };

    // utility method for determining if something is contenteditable
    var is_contenteditable = function(el) {
        return $(el).is("[contenteditable=true]") || (
            $(el).parents("[contenteditable=true]").length > 0
        );
    };

    // simply replaces
    // rather than toggles, but
    // theres no reason you couldn't have
    // it do both!
    var wrap_selection = function(wrap_html){
        var selection_node = $(window.getSelection().anchorNode);
        if(is_contenteditable(selection_node)) {
            // You just want to unwrap if your
            // parent is already selected
            if(selection_node.parent().is(wrap_html)) {
                selection_node.unwrap();
            }
            else {
                selection_node.wrap("<" + wrap_html + ">");
            }
        }
        // wrap() normally breaks contentEditable
        // this is a hacky replacement
        selection_node.attr('contenteditable', true);
    };

    /*
     * controls and functions to handle them
     */

    var ctrls = {
        b: {
            cmd: 'bold',
            selector: '.strong'
        },
        i: {
            cmd: 'italic',
            selector: '.emphasised'
        },
        ol: {
            cmd: 'insertorderedlist',
            selector: '.list-ordered'
        },
        ul: {
            cmd: 'insertunorderedlist',
            selector: '.list-unordered'
        }
    };

    // generate a cmd function to be used as an event handler
    var cmdfn = function(ctrl, opts) {
        opts = opts || {};
        return function(ev) {
            var $ctrl = $(ev.target);

            // execute command and log about it
            log.debug('exec:', ctrl.cmd, 'triggered by', $ctrl);
            document.execCommand(ctrl.cmd, opts.showui || false, opts.val || '');

            // remove selected if control is in a exclusive group
            $ctrl.parents('.exclusive').each(function() {
                $(this).find('.selected').each(function() {
                    // don't remove selected for the clicked control
                    // it is toggle later on
                    if (this !== ev.target) $(this).removeClass('selected');
                });
            });

            // toggle selected
            $ctrl.toggleClass('selected');
        };
    };

    var initctrls = function(selector) {
        var $ctrls = $(selector);
        for (var tag in ctrls) {
            var ctrl = ctrls[tag],
                $ctrl = $ctrls.find(ctrl.selector);
            if ($ctrl.length === 0) continue;
            log.debug('found control:', tag, $ctrl);
            $ctrl.on('click', cmdfn(ctrl));
        }
        return $ctrls;
    };

    var updatectrls = function($ctrls) {
        // unselect all controls - XXX: is there seriously no better way?
        //$ctrls.find('.selected').removeClass('selected');

        for (var tag in ctrls) {
            var ctrl = ctrls[tag];
            $ctrls.find(ctrl.selector)[
                document.queryCommandState(ctrl.cmd)
                    ? 'addClass'
                    : 'removeClass'
            ]('selected');
        }
    };

    var init = function($el, opts) {
        var $edit = text2div($el),
            $ctrls = initctrls('.editor-controls');

        $edit.on('keyup mouseup', function() {
            updatectrls($ctrls);
        });

        var buttons  = {};
        buttons.clear               = $ctrls.find('.clear');
        buttons.inserth1            = $ctrls.find('.header_1');
        buttons.inserth2            = $ctrls.find('.header_2');
        buttons.inserth3            = $ctrls.find('.header_3');
        buttons.upload_image        = $ctrls.find('.upload_image');
        buttons.link_image          = $ctrls.find('.link_image');

        var button_handler = {
            'insertparagraph'       : function(){ return 0; },
            'inserth1'              : function(){ wrap_selection('h1') },
            'inserth2'              : function(){ wrap_selection('h2') },
            'inserth3'              : function(){ wrap_selection('h3') },
            'clear'                 : function(){
                var selection_node = $(window.getSelection().anchorNode);
                document.execCommand('removeformat');
                if (is_contenteditable(selection_node)) {
                    selection_node.unwrap();
                    if (!$(selection_node).parent().is("p")) {
                        $(selection_node).wrap('
');
                    }
                }
            },
            'upload_image'          : function(){ document.execCommand(); },
            'link_image'            : function(){
                var source = prompt('URL of Image');
                if(source) {
                    document.execCommand('insertImage', false, source);
                }
            }
        };

        // lame helper that
        // toggles the class,
        // triggers the handler
        var button_click = function(element) {
            buttons[element].toggleClass('selected');
            button_handler[element]();
        };

        // bind click to button_click()/1
        for (var key in buttons) {
            buttons[key].click(function(element){
                return function() {
                    log.debug('clicked', element);
                    button_click(element);
                };
            }(key));
        }

    };

    var pattern = {
        markup_trigger: 'form textarea.edit',
        initialised_class: 'edit',
        init: init
    };
    return pattern;
});
<|endoftext|>