<commit_before>import $ from 'jquery';
import { throttle } from 'lodash/function';
import noop from '../common/noop.js';

function OptionList(options) {
  this.options = options;
  this.channels = {
    select: noop,
    activate: noop,
  };
  this.lastMouseX = NaN;
  this.lastMouseY = NaN;
  this.init();
}

OptionList.prototype.onlyIfMousePositionChanged = function onlyIfMousePositionChanged(callback) {
  return event => {
    // workaround to prevent scripted scrolling from triggering mousemove events
    const {lastMouseX: previousX, lastMouseY: previousY} = this;
    const {pageX: currentX, pageY: currentY} = event;
    return (currentX !== previousX || currentY !== previousY) ? callback(event) : noop();
  };
};

OptionList.prototype.on = function on(channel, callback) {
  this.channels[channel] = callback ? callback : noop;
  return this;
};

OptionList.prototype.init = function init() {
  const $items = $('<div/>')
    .addClass('ui-virtual-select--items')
    .css('overflow-y', 'scroll')
    .on('scroll', throttle(() => {
      this.render(this.renderedState);
    }, 10))
    .on('mousemove', event => {
      this.lastMouseX = event.pageX;
      this.lastMouseY = event.pageY;
    })
    .on('mousedown', event => {
      /* prevent blur event when clicking options */
      if ($.contains($items.get(0), event.target)) {
        event.preventDefault();
      }
    })
    .hide();

  const $canvas = $('<div/>')
    .addClass('ui-virtual-select--canvas')
    .appendTo($items)
    .on('mousemove', '.ui-virtual-select--item', this.onlyIfMousePositionChanged(event => {
      const index = $(event.currentTarget).data('index');
      if (index !== this.renderedState.activeItemIndex) {
        this.channels.activate(index);
      }
    }))
    .on('click', '.ui-virtual-select--item', event => {
      const index = $(event.currentTarget).data('index');
      this.channels.select(index);
    });

  this.element = this.$items = $items;
  this.$canvas = $canvas;
};

function calculateItemsElementHeight(options) {
  const {maxVisibleItems, dataProvider, itemHeight} = options;
  return Math.min(maxVisibleItems, dataProvider.items.length) * itemHeight;
}

// FIXME: one of these two functions doesn't do what it says. but which one?
function calculateFirstRenderedItemIndex(options, scrollPosition) {
  const {itemHeight, maxVisibleItems} = options;
  return Math.max(Math.floor(scrollPosition / itemHeight) - maxVisibleItems, 0);
}
function calculateFirstVisibleItemIndex(options, scrollPosition) {
  const {itemHeight, maxVisibleItems} = options;
  return Math.max(Math.floor(scrollPosition / itemHeight) - maxVisibleItems, 0);
}

function calculateCanvasElementHeight(options, scrollPosition) {
  const firstVisibleItemIndex = calculateFirstVisibleItemIndex(options, scrollPosition);
  const {dataProvider, itemHeight} = options;
  return dataProvider.items.length * itemHeight - firstVisibleItemIndex * itemHeight;
}

function calculateCanvasElementMarginTop(options, scrollPosition) {
  const firstVisibleItemIndex = calculateFirstVisibleItemIndex(options, scrollPosition);
  return firstVisibleItemIndex * options.itemHeight;
}

function calculateCanvasSize(options) {
  const {dataProvider, maxVisibleItems, itemHeight} = options;
  return Math.min(dataProvider.items.length, maxVisibleItems) * itemHeight;
}

function getItemsToRender(options, scrollPosition) {
  const firstRenderedItemIndex = calculateFirstRenderedItemIndex(options, scrollPosition);
  return options.dataProvider.get(firstRenderedItemIndex, firstRenderedItemIndex + options.maxRenderedItems);
}

OptionList.prototype.render = function init(state) {
  const self = this;

  // toggle open state and class
  if (state.open) {
    this.$items.show();
  } else {
    this.$items.hide();
  }

  if (state.open) {
    // adjust first item
    const scrollPosition = this.$items.scrollTop();
    const firstRenderedItemIndex = calculateFirstRenderedItemIndex(this.options, scrollPosition);

    // update items height
    const itemsElementHeight = calculateItemsElementHeight(this.options);
    this.$items.css({
      height: `${itemsElementHeight}px`,
    });

    // update canvas size
    const canvasElementMarginTop = calculateCanvasElementMarginTop(this.options, scrollPosition);
    const canvasElementHeight = calculateCanvasElementHeight(this.options, scrollPosition);
    this.$canvas.css({
      'height': `${canvasElementHeight}px`,
      'margin-top': `${canvasElementMarginTop}px`,
    });

    // adjust scroll position
    if (state.activeItemIndex !== this.renderedState.activeItemIndex || !this.renderedState.open) {
      const canvasSize = calculateCanvasSize(this.options);
      const targetScrollPosition = state.activeItemIndex * this.options.itemHeight;
      const a1 = Math.ceil(scrollPosition / this.options.itemHeight) * this.options.itemHeight;
      const a2 = Math.floor(scrollPosition / this.options.itemHeight) * this.options.itemHeight + canvasSize;
      if (targetScrollPosition <= a1 || !this.renderedState.open) {
        this.$items.scrollTop(targetScrollPosition);
      } else if (targetScrollPosition >= a2) {
        this.$items.scrollTop(targetScrollPosition - canvasSize + this.options.itemHeight);
      }
    }

    // get items to render
    const items = getItemsToRender(this.options, scrollPosition);

    // create dom elements if necessary
    items.forEach((item, index) => {
      let $itemElement = this.$canvas.children('.ui-virtual-select--item').eq(index);
      if ($itemElement.length === 0) {
        $itemElement = $('<div/>').addClass('ui-virtual-select--item').appendTo(this.$canvas);
      }
      // TODO Optimize?
      $itemElement
        .data('item', item)
        .data('offset', firstRenderedItemIndex)
        .data('index', firstRenderedItemIndex + index);
    });

    // remove excess dom elements
    this.$canvas.children('.ui-virtual-select--item').slice(items.length).remove();

    // update text
    this.$canvas.children('.ui-virtual-select--item').each((index, element) => {
      const $itemElement = $(element);
      const item = $itemElement.data('item');
      const displayText = self.options.dataProvider.displayText(item, state.extendedModeEnabled);
      if ($itemElement.text() !== displayText) {
        $itemElement.text(displayText).attr('title', displayText);
      }
    });
  }

  // change active class
  this.$canvas.children('.ui-virtual-select--item').each((index, element) => {
    const $itemElement = $(element);
    const itemIndex = $itemElement.data('index');
    const hasActiveClass = $itemElement.hasClass('active');
    if (itemIndex === state.activeItemIndex && !hasActiveClass) {
      $itemElement.addClass('active');
    }
    if (itemIndex !== state.activeItemIndex && hasActiveClass) {
      $itemElement.removeClass('active');
    }
  });

  // update state with rendered one
  this.renderedState = state;
// this.renderedState = $.extend({}, state);
};

export default OptionList;
<commit_msg>Use mousedown instead of click for IE8 support<commit_after>import $ from 'jquery';
import { throttle } from 'lodash/function';
import noop from '../common/noop.js';

function OptionList(options) {
  this.options = options;
  this.channels = {
    select: noop,
    activate: noop,
  };
  this.lastMouseX = NaN;
  this.lastMouseY = NaN;
  this.init();
}

OptionList.prototype.onlyIfMousePositionChanged = function onlyIfMousePositionChanged(callback) {
  return event => {
    // workaround to prevent scripted scrolling from triggering mousemove events
    const {lastMouseX: previousX, lastMouseY: previousY} = this;
    const {pageX: currentX, pageY: currentY} = event;
    return (currentX !== previousX || currentY !== previousY) ? callback(event) : noop();
  };
};

OptionList.prototype.on = function on(channel, callback) {
  this.channels[channel] = callback ? callback : noop;
  return this;
};

OptionList.prototype.init = function init() {
  const $items = $('<div/>')
    .addClass('ui-virtual-select--items')
    .css('overflow-y', 'scroll')
    .on('scroll', throttle(() => {
      this.render(this.renderedState);
    }, 10))
    .on('mousemove', event => {
      this.lastMouseX = event.pageX;
      this.lastMouseY = event.pageY;
    })
    .on('mousedown', event => {
      /* prevent blur event when clicking options */
      if ($.contains($items.get(0), event.target)) {
        event.preventDefault();
      }
    })
    .hide();

  const $canvas = $('<div/>')
    .addClass('ui-virtual-select--canvas')
    .appendTo($items)
    .on('mousemove', '.ui-virtual-select--item', this.onlyIfMousePositionChanged(event => {
      const index = $(event.currentTarget).data('index');
      if (index !== this.renderedState.activeItemIndex) {
        this.channels.activate(index);
      }
    }))
    .on('mousedown', '.ui-virtual-select--item', event => {
      const index = $(event.currentTarget).data('index');
      this.channels.select(index);
    });

  this.element = this.$items = $items;
  this.$canvas = $canvas;
};

function calculateItemsElementHeight(options) {
  const {maxVisibleItems, dataProvider, itemHeight} = options;
  return Math.min(maxVisibleItems, dataProvider.items.length) * itemHeight;
}

// FIXME: one of these two functions doesn't do what it says. but which one?
function calculateFirstRenderedItemIndex(options, scrollPosition) {
  const {itemHeight, maxVisibleItems} = options;
  return Math.max(Math.floor(scrollPosition / itemHeight) - maxVisibleItems, 0);
}
function calculateFirstVisibleItemIndex(options, scrollPosition) {
  const {itemHeight, maxVisibleItems} = options;
  return Math.max(Math.floor(scrollPosition / itemHeight) - maxVisibleItems, 0);
}

function calculateCanvasElementHeight(options, scrollPosition) {
  const firstVisibleItemIndex = calculateFirstVisibleItemIndex(options, scrollPosition);
  const {dataProvider, itemHeight} = options;
  return dataProvider.items.length * itemHeight - firstVisibleItemIndex * itemHeight;
}

function calculateCanvasElementMarginTop(options, scrollPosition) {
  const firstVisibleItemIndex = calculateFirstVisibleItemIndex(options, scrollPosition);
  return firstVisibleItemIndex * options.itemHeight;
}

function calculateCanvasSize(options) {
  const {dataProvider, maxVisibleItems, itemHeight} = options;
  return Math.min(dataProvider.items.length, maxVisibleItems) * itemHeight;
}

function getItemsToRender(options, scrollPosition) {
  const firstRenderedItemIndex = calculateFirstRenderedItemIndex(options, scrollPosition);
  return options.dataProvider.get(firstRenderedItemIndex, firstRenderedItemIndex + options.maxRenderedItems);
}

OptionList.prototype.render = function init(state) {
  const self = this;

  // toggle open state and class
  if (state.open) {
    this.$items.show();
  } else {
    this.$items.hide();
  }

  if (state.open) {
    // adjust first item
    const scrollPosition = this.$items.scrollTop();
    const firstRenderedItemIndex = calculateFirstRenderedItemIndex(this.options, scrollPosition);

    // update items height
    const itemsElementHeight = calculateItemsElementHeight(this.options);
    this.$items.css({
      height: `${itemsElementHeight}px`,
    });

    // update canvas size
    const canvasElementMarginTop = calculateCanvasElementMarginTop(this.options, scrollPosition);
    const canvasElementHeight = calculateCanvasElementHeight(this.options, scrollPosition);
    this.$canvas.css({
      'height': `${canvasElementHeight}px`,
      'margin-top': `${canvasElementMarginTop}px`,
    });

    // adjust scroll position
    if (state.activeItemIndex !== this.renderedState.activeItemIndex || !this.renderedState.open) {
      const canvasSize = calculateCanvasSize(this.options);
      const targetScrollPosition = state.activeItemIndex * this.options.itemHeight;
      const a1 = Math.ceil(scrollPosition / this.options.itemHeight) * this.options.itemHeight;
      const a2 = Math.floor(scrollPosition / this.options.itemHeight) * this.options.itemHeight + canvasSize;
      if (targetScrollPosition <= a1 || !this.renderedState.open) {
        this.$items.scrollTop(targetScrollPosition);
      } else if (targetScrollPosition >= a2) {
        this.$items.scrollTop(targetScrollPosition - canvasSize + this.options.itemHeight);
      }
    }

    // get items to render
    const items = getItemsToRender(this.options, scrollPosition);

    // create dom elements if necessary
    items.forEach((item, index) => {
      let $itemElement = this.$canvas.children('.ui-virtual-select--item').eq(index);
      if ($itemElement.length === 0) {
        $itemElement = $('<div/>').addClass('ui-virtual-select--item').appendTo(this.$canvas);
      }
      // TODO Optimize?
      $itemElement
        .data('item', item)
        .data('offset', firstRenderedItemIndex)
        .data('index', firstRenderedItemIndex + index);
    });

    // remove excess dom elements
    this.$canvas.children('.ui-virtual-select--item').slice(items.length).remove();

    // update text
    this.$canvas.children('.ui-virtual-select--item').each((index, element) => {
      const $itemElement = $(element);
      const item = $itemElement.data('item');
      const displayText = self.options.dataProvider.displayText(item, state.extendedModeEnabled);
      if ($itemElement.text() !== displayText) {
        $itemElement.text(displayText).attr('title', displayText);
      }
    });
  }

  // change active class
  this.$canvas.children('.ui-virtual-select--item').each((index, element) => {
    const $itemElement = $(element);
    const itemIndex = $itemElement.data('index');
    const hasActiveClass = $itemElement.hasClass('active');
    if (itemIndex === state.activeItemIndex && !hasActiveClass) {
      $itemElement.addClass('active');
    }
    if (itemIndex !== state.activeItemIndex && hasActiveClass) {
      $itemElement.removeClass('active');
    }
  });

  // update state with rendered one
  this.renderedState = state;
// this.renderedState = $.extend({}, state);
};

export default OptionList;
<|endoftext|>


<commit_before>import axios from 'axios'

const WORKSPACE = __WORKSPACE__
const ENDPOINT  = __API__

const GeoAPI = {

    /**
    * Parse XML from GeoServer
    */

    workspace: WORKSPACE,
    restricted: false,
    layers: [],
    menu: [],

    createUrl({layerName, styleName, clickData, featureCount}) {
        return `?LAYERS=${layerName}&QUERY_LAYERS=${layerName}&STYLES=${styleName},&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetFeatureInfo&BBOX=${clickData.BBOX}&FEATURE_COUNT=${featureCount}&HEIGHT=${clickData.HEIGHT}&WIDTH=${clickData.WIDTH}&FORMAT=image%2Fpng&INFO_FORMAT=application%2Fjson&SRS=EPSG%3A4326&X=${clickData.X}&Y=${clickData.Y}&CQL_FILTER=1%3D1%3B1%3D1`
    },

    /**
    * Call GeoServer and get XML data for places
    * @param callback function to call when data is fully loaded
    */
    getContent(callback) {
        axios
            .get(ENDPOINT + '?request=GetCapabilities')
            .then((response) => {
                callback({
                    xmlData: response
                })
            })
            .catch((error) => {
                return console.log(error)
            })
    },

    /**
    * Call GeoServer and get layer feature data
    * @param callback function to call when data is fully loaded
    */
    getLayerData(callback, url) {
        axios
            .get(ENDPOINT + url)
            .then((response) => {
                callback(response.data)
            })
            .catch((error) => {
                return console.log(error)
            })
    },

    /**
    * Call GeoServer and get layer feature data
    * @param callback function to call when data is fully loaded
    */
    getLayersData(callback, urls) {
        axios.all(urls.map(l => axios.get(ENDPOINT+l)))
        .then(axios.spread(function (...res) {
            // all requests are now complete
            let responses = res.map( r => r.data)
            callback(responses)
        }))
        .catch((error) => {
            return console.log(error)
        })
    },

     /**
    * Call GeoServer and get polygon data
    * @param callback function to call when data is fully loaded
    */
    getPolygonData(callback, coordinates, activeLayers) {
        const PREFIX = 'plataforma:'
        const layers = [
            {
                'name': 'Escolas',
                'url': 'educ_escolas_busca_pol_4326',
            },
            {
                'name': 'População',
                'url': 'se_setores_2010_busca_pol_4326',
            },
            {
                'name': 'Bombeiros',
                'url': 'bombeiro_busca_pol_4326',
            },
            {
                'name': 'Guarda Municipal',
                'url': 'guarda_municipal_busca_pol_4326',
            },
            {
                'name': 'Batalhões Policiais',
                'url': 'policia_batalhao_sede_busca_pol_4326',
            },
            {
                'name': 'Delegacias Policiais',
                'url': 'policia_dps_busca_pol_4326',
            },
            {
                'name': 'Hospitais',
                'url': 'saude_estabelecimentos_cnes_busca_pol_4326',
            },
            {
                'name': 'Estações de BRT',
                'url': 'trans_brt_estacoes_busca_pol_4326',
            },
            {
                'name': 'Estações de Metrô',
                'url': 'trans_metro_estacoes_busca_pol_4326',
            },
            {
                'name': 'Estações de Ônibus',
                'url': 'trans_onibus_por_embarque_busca_pol_4326',
            },
            {
                'name': 'Estações de Trem',
                'url': 'trans_trem_estacoes_busca_pol_4326',
            },
            {
                'name': 'Estações de VLT',
                'url': 'trans_vlt_estacoes_busca_pol_4326',
            },
        ]
        coordinates = coordinates[0]
        coordinates = coordinates.map((c) => {
            return c.lng + ' ' + c.lat
        })
        coordinates.push(coordinates[0])

        coordinates = coordinates.join(',')
        //http://localhost:3000/geoserver/plataforma/wms?service=WFS&version=1.0.0&request=GetFeature&typeName=plataforma%3Aeduc_escolas&outputFormat=application%2Fjson&SRS=EPSG%3A4326&cql_filter=INTERSECTS(geom,%20POLYGON((-22.105998799750566%20-43.2696533203125,-22.344995208437894%20-42.94006347656251,-21.937950226141925%20-41.98974609375,-22.105998799750566%20-43.2696533203125)))

        const urls = layers.map( l =>
            ENDPOINT+`?service=WFS&version=1.0.0&request=GetFeature&typeName=${PREFIX+l.url}&outputFormat=application%2Fjson&cql_filter=INTERSECTS(geom,  POLYGON((${coordinates})))`
        )
        axios.all(urls.map(l => axios.get(l)))
        .then(axios.spread(function (...res) {
            // all requests are now complete
            let responses = res.map( r => {
                let copy = r.data.features.slice()
                let subs
                let category
                if (copy.length > 0){
                    subs = copy[0].id.split('.')[0]
                    let result = layers.filter(l => l.url === subs)
                    category = result[0].name
                }
                return r.data.features.map( f => {
                    return {
                        category,
                        "geometry": f.geometry,
                        "id": f.id,
                        "properties": f.properties,
                    }
                })
            })
            callback(responses)
        }))
        .catch((error) => {
            return console.log(error)
        })
    }
}

export default GeoAPI
<commit_msg>Adding default values, to prevent geoserver calls with undefined values<commit_after>import axios from 'axios'

const WORKSPACE = __WORKSPACE__
const ENDPOINT  = __API__

const GeoAPI = {

    /**
    * Parse XML from GeoServer
    */

    workspace: WORKSPACE,
    restricted: false,
    layers: [],
    menu: [],

    createUrl({layerName = "", styleName = "", clickData = "", featureCount = ""}) {
        return `?LAYERS=${layerName}&QUERY_LAYERS=${layerName}&STYLES=${styleName},&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetFeatureInfo&BBOX=${clickData.BBOX}&FEATURE_COUNT=${featureCount}&HEIGHT=${clickData.HEIGHT}&WIDTH=${clickData.WIDTH}&FORMAT=image%2Fpng&INFO_FORMAT=application%2Fjson&SRS=EPSG%3A4326&X=${clickData.X}&Y=${clickData.Y}&CQL_FILTER=1%3D1%3B1%3D1`
    },

    /**
    * Call GeoServer and get XML data for places
    * @param callback function to call when data is fully loaded
    */
    getContent(callback) {
        axios
            .get(ENDPOINT + '?request=GetCapabilities')
            .then((response) => {
                callback({
                    xmlData: response
                })
            })
            .catch((error) => {
                return console.log(error)
            })
    },

    /**
    * Call GeoServer and get layer feature data
    * @param callback function to call when data is fully loaded
    */
    getLayerData(callback, url) {
        axios
            .get(ENDPOINT + url)
            .then((response) => {
                callback(response.data)
            })
            .catch((error) => {
                return console.log(error)
            })
    },

    /**
    * Call GeoServer and get layer feature data
    * @param callback function to call when data is fully loaded
    */
    getLayersData(callback, urls) {
        axios.all(urls.map(l => axios.get(ENDPOINT+l)))
        .then(axios.spread(function (...res) {
            // all requests are now complete
            let responses = res.map( r => r.data)
            callback(responses)
        }))
        .catch((error) => {
            return console.log(error)
        })
    },

     /**
    * Call GeoServer and get polygon data
    * @param callback function to call when data is fully loaded
    */
    getPolygonData(callback, coordinates, activeLayers) {
        const PREFIX = 'plataforma:'
        const layers = [
            {
                'name': 'Escolas',
                'url': 'educ_escolas_busca_pol_4326',
            },
            {
                'name': 'População',
                'url': 'se_setores_2010_busca_pol_4326',
            },
            {
                'name': 'Bombeiros',
                'url': 'bombeiro_busca_pol_4326',
            },
            {
                'name': 'Guarda Municipal',
                'url': 'guarda_municipal_busca_pol_4326',
            },
            {
                'name': 'Batalhões Policiais',
                'url': 'policia_batalhao_sede_busca_pol_4326',
            },
            {
                'name': 'Delegacias Policiais',
                'url': 'policia_dps_busca_pol_4326',
            },
            {
                'name': 'Hospitais',
                'url': 'saude_estabelecimentos_cnes_busca_pol_4326',
            },
            {
                'name': 'Estações de BRT',
                'url': 'trans_brt_estacoes_busca_pol_4326',
            },
            {
                'name': 'Estações de Metrô',
                'url': 'trans_metro_estacoes_busca_pol_4326',
            },
            {
                'name': 'Estações de Ônibus',
                'url': 'trans_onibus_por_embarque_busca_pol_4326',
            },
            {
                'name': 'Estações de Trem',
                'url': 'trans_trem_estacoes_busca_pol_4326',
            },
            {
                'name': 'Estações de VLT',
                'url': 'trans_vlt_estacoes_busca_pol_4326',
            },
        ]
        coordinates = coordinates[0]
        coordinates = coordinates.map((c) => {
            return c.lng + ' ' + c.lat
        })
        coordinates.push(coordinates[0])

        coordinates = coordinates.join(',')
        //http://localhost:3000/geoserver/plataforma/wms?service=WFS&version=1.0.0&request=GetFeature&typeName=plataforma%3Aeduc_escolas&outputFormat=application%2Fjson&SRS=EPSG%3A4326&cql_filter=INTERSECTS(geom,%20POLYGON((-22.105998799750566%20-43.2696533203125,-22.344995208437894%20-42.94006347656251,-21.937950226141925%20-41.98974609375,-22.105998799750566%20-43.2696533203125)))

        const urls = layers.map( l =>
            ENDPOINT+`?service=WFS&version=1.0.0&request=GetFeature&typeName=${PREFIX+l.url}&outputFormat=application%2Fjson&cql_filter=INTERSECTS(geom,  POLYGON((${coordinates})))`
        )
        axios.all(urls.map(l => axios.get(l)))
        .then(axios.spread(function (...res) {
            // all requests are now complete
            let responses = res.map( r => {
                let copy = r.data.features.slice()
                let subs
                let category
                if (copy.length > 0){
                    subs = copy[0].id.split('.')[0]
                    let result = layers.filter(l => l.url === subs)
                    category = result[0].name
                }
                return r.data.features.map( f => {
                    return {
                        category,
                        "geometry": f.geometry,
                        "id": f.id,
                        "properties": f.properties,
                    }
                })
            })
            callback(responses)
        }))
        .catch((error) => {
            return console.log(error)
        })
    }
}

export default GeoAPI
<|endoftext|>


<commit_before>/*
 * takeout
 *
 *
 * Copyright (c) 2014 Garrett Nay
 * Licensed under the MIT license.
 */

(function (factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define(['jquery'], factory);
  } else if (typeof exports === 'object') {
    // Node/CommonJS
    factory(require('jquery'));
  } else {
    // Browser globals
    factory(jQuery);
  }
}(function ($) {

  $.fn.takeout = function (options) {

    if (options === 'undo') {
      return this.each(function () {
        var $this = $(this),
            placeholderRef = $this.data('takeout-placeholder'),
            $placeholder,
            position,
            offset;

        if (!placeholderRef) {
          throw new Error('Element does not have a reference to a placeholder.');
        }

        $placeholder = $('.takeout-placeholder').filter(function () {
          return this === placeholderRef;
        });

        if (!$placeholder.length) {
          throw new Error('Referenced placeholder does not exist in the document.');
        }

        position = $placeholder.css('position');
        offset = $placeholder.offset();

        $placeholder.replaceWith($this);

        $this.css('position', position);

        if (position !== 'static') {
          $this.offset(offset);
        }
      });
    } else {
      return this.each(function () {

        var $this = $(this),
            height = $this.height(),
            width = $this.width(),
            offset = $this.offset(),
            $placeholder = $('

')
              .height(height)
              .width(width);

        $this.replaceWith($placeholder)
          .appendTo('body')
          .offset(offset)
          .data('takeout-placeholder', $placeholder.get(0));

      });
    }
  };

}));
<commit_msg>refactor(takeout.js): accept options in first or second parameter<commit_after>/*
 * takeout
 *
 *
 * Copyright (c) 2014 Garrett Nay
 * Licensed under the MIT license.
 */

(function (factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define(['jquery'], factory);
  } else if (typeof exports === 'object') {
    // Node/CommonJS
    factory(require('jquery'));
  } else {
    // Browser globals
    factory(jQuery);
  }
}(function ($) {

  $.fn.takeout = function () {

    var command, options;

    if (typeof arguments[0] === 'string') {
      command = arguments[0];
      options = arguments[1];
    } else {
      options = arguments[0];
    }

    if (command === 'undo') {
      return this.each(function () {
        var $this = $(this),
            placeholderRef = $this.data('takeout-placeholder'),
            $placeholder,
            position,
            offset;

        if (!placeholderRef) {
          throw new Error('Element does not have a reference to a placeholder.');
        }

        $placeholder = $('.takeout-placeholder').filter(function () {
          return this === placeholderRef;
        });

        if (!$placeholder.length) {
          throw new Error('Referenced placeholder does not exist in the document.');
        }

        position = $placeholder.css('position');
        offset = $placeholder.offset();

        $placeholder.replaceWith($this);

        $this.css('position', position);

        if (position !== 'static') {
          $this.offset(offset);
        }
      });
    } else {
      return this.each(function () {

        var $this = $(this),
            height = $this.height(),
            width = $this.width(),
            offset = $this.offset(),
            $placeholder = $('

')
              .height(height)
              .width(width);

        $this.replaceWith($placeholder)
          .appendTo('body')
          .offset(offset)
          .data('takeout-placeholder', $placeholder.get(0));

      });
    }
  };

}));
<|endoftext|>


<commit_before>import { Component } from 'react';
import PropTypes from 'prop-types';
import cn from 'classnames';
import { DateTime } from 'luxon';
import { connect } from 'react-redux';

import Grid from '@material-ui/core/Grid';
import Card from '@material-ui/core/Card';
import CardHeader from '@material-ui/core/CardHeader';
import CardContent from '@material-ui/core/CardContent';
import Typography from '@material-ui/core/Typography';
import AttachIcon from '@material-ui/icons/AttachFile';
import { withStyles } from '@material-ui/core/styles';
import IconCloudDownload from '@material-ui/icons/CloudDownloadOutlined';
import Tooltip from '@material-ui/core/Tooltip';

import { makeUnsearchable, truncatePath } from '../utils';

import { fetchDoc } from '../actions';

const styles = theme => ({
    card: {
        cursor: 'pointer',
        marginTop: theme.spacing.unit,
        borderLeft: '3px solid transparent',
        transition: theme.transitions.create('border', {
            duration: theme.transitions.duration.short,
        }),
    },
    selected: {
        borderLeft: `3px solid ${theme.palette.secondary.main}`,
    },
    spaceBottom: {
        marginBottom: theme.spacing.unit,
    },
    spaceTop: {
        marginTop: theme.spacing.unit,
    },
    path: {
        // overflow: 'hidden',
        // whiteSpace: 'nowrap',
        marginTop: theme.spacing.unit * 2,
    },
    text: {
        cursor: 'text',
        display: 'inline',
        fontFamily: theme.typography.fontFamilyMono,
        fontSize: '.7rem',
        color: '#555',
    },
});

function timeMs() {
    return new Date().getTime();
}

const documentViewUrl = item => `doc/${item._collection}/${item._id}`;

class ResultItem extends Component {
    static propTypes = {
        classes: PropTypes.object.isRequired,
    };

    handleClick = e => {
        const modifier = e.metaKey || e.ctrlKey || e.shiftKey || e.altKey;

        if (!modifier) {
            e.preventDefault();
            this.onPreview();
        }
    };

    onPreview = () => this.props.dispatch(fetchDoc(this.props.url));

    componentDidUpdate(prevProps) {
        if (this.props.url === this.props.doc.url && 'scrollIntoView' in this.node) {
            this.node.scrollIntoView({ behavior: 'smooth', block: 'center' });
        }
    }

    render() {
        const { hit, url, classes, doc, index } = this.props;

        const isSelected = url === doc.url;
        const unsearchable = !!doc.url;

        const fields = hit._source || {};
        const highlight = hit.highlight || {};

        const icon = fields.attachments ? (
            <AttachIcon style={{ fontSize: 18 }} />
        ) : null;

        const text = (highlight.text || []).map((hi, n) => (
            <div key={`${hit._url}${n}`}>

        ));

        let wordCount = null;

        if (fields['word-count']) {
            wordCount = fields['word-count'] + ' words';
        }

        let downloadUrl = `${this.props.url}/raw/${fields.filename}`;

        return (

 (this.node = node)}
                className={cn(classes.card, { [classes.selected]: isSelected })}
                onMouseDown={() => {
                    this.willFocus = !(this.tUp && timeMs() - this.tUp < 300);
                }}
                onMouseMove={() => {
                    this.willFocus = false;
                }}
                onMouseUp={() => {
                    if (this.willFocus) {
                        this.tUp = timeMs();
                        this.onPreview(url);
                    }
                }}>
                <Card>
                    <CardHeader
                        title={

                                {index}. {fields.filename}

                        }
                        action={icon}
                        subheader={truncatePath(fields.path)}
                    />
                    <CardContent>
                        <Grid container alignItems="flex-end">
                            <Grid item md={4}>
                                <Typography variant="caption">
                                    {wordCount}
                                </Typography>

                                {fields.date && (
                                    <Typography variant="caption">
                                        Modified:{' '}
                                        {DateTime.fromISO(fields.date)
                                            .toLocaleString(DateTime.DATE_FULL)
                                            .replace(/\s/g, ' ')}
                                    </Typography>
                                )}

                                {fields['date-created'] && (
                                    <Typography variant="caption">
                                        Created:
                                        {DateTime.fromISO(
                                            fields['date-created']
                                        ).toLocaleString(DateTime.DATE_FULL)}
                                    </Typography>
                                )}

                                <Typography variant="caption">
                                    <Tooltip title="Download original file">

                                            <IconCloudDownload color="action" />

                                    </Tooltip>
                                </Typography>
                            </Grid>
                            <Grid item md={8}>

{text}

                            </Grid>{' '}
                        </Grid>
                    </CardContent>
                </Card>

        );
    }
}

const mapStateToProps = ({ doc }) => ({ doc });
export default withStyles(styles)(connect(mapStateToProps)(ResultItem));
<commit_msg>combine highlights from all fields and sources<commit_after>import { Component } from 'react';
import PropTypes from 'prop-types';
import cn from 'classnames';
import { DateTime } from 'luxon';
import { connect } from 'react-redux';

import Grid from '@material-ui/core/Grid';
import Card from '@material-ui/core/Card';
import CardHeader from '@material-ui/core/CardHeader';
import CardContent from '@material-ui/core/CardContent';
import Typography from '@material-ui/core/Typography';
import AttachIcon from '@material-ui/icons/AttachFile';
import { withStyles } from '@material-ui/core/styles';
import IconCloudDownload from '@material-ui/icons/CloudDownloadOutlined';
import Tooltip from '@material-ui/core/Tooltip';

import { makeUnsearchable, truncatePath } from '../utils';

import { fetchDoc } from '../actions';

const styles = theme => ({
    card: {
        cursor: 'pointer',
        marginTop: theme.spacing.unit,
        borderLeft: '3px solid transparent',
        transition: theme.transitions.create('border', {
            duration: theme.transitions.duration.short,
        }),
    },
    selected: {
        borderLeft: `3px solid ${theme.palette.secondary.main}`,
    },
    spaceBottom: {
        marginBottom: theme.spacing.unit,
    },
    spaceTop: {
        marginTop: theme.spacing.unit,
    },
    path: {
        // overflow: 'hidden',
        // whiteSpace: 'nowrap',
        marginTop: theme.spacing.unit * 2,
    },
    text: {
        cursor: 'text',
        display: 'inline',
        fontFamily: theme.typography.fontFamilyMono,
        fontSize: '.7rem',
        color: '#555',
    },
});

function timeMs() {
    return new Date().getTime();
}

function combineHighlights(highlight) {
    var list = [];
    for (const key in highlight) {
        if (highlight.hasOwnProperty(key)) {
            list = list.concat(highlight[key]);
        }
    }
    return list;
}

const documentViewUrl = item => `doc/${item._collection}/${item._id}`;

class ResultItem extends Component {
    static propTypes = {
        classes: PropTypes.object.isRequired,
    };

    handleClick = e => {
        const modifier = e.metaKey || e.ctrlKey || e.shiftKey || e.altKey;

        if (!modifier) {
            e.preventDefault();
            this.onPreview();
        }
    };

    onPreview = () => this.props.dispatch(fetchDoc(this.props.url));

    componentDidUpdate(prevProps) {
        if (this.props.url === this.props.doc.url && 'scrollIntoView' in this.node) {
            this.node.scrollIntoView({ behavior: 'smooth', block: 'center' });
        }
    }

    render() {
        const { hit, url, classes, doc, index } = this.props;

        const isSelected = url === doc.url;
        const unsearchable = !!doc.url;

        const fields = hit._source || {};
        const highlight = hit.highlight || {};

        const icon = fields.attachments ? (
            <AttachIcon style={{ fontSize: 18 }} />
        ) : null;

        const text = combineHighlights(highlight).map((hi, n) => (
            <div key={`${hit._url}${n}`}>

        ));

        let wordCount = null;

        if (fields['word-count']) {
            wordCount = fields['word-count'] + ' words';
        }

        let downloadUrl = `${this.props.url}/raw/${fields.filename}`;

        return (

 (this.node = node)}
                className={cn(classes.card, { [classes.selected]: isSelected })}
                onMouseDown={() => {
                    this.willFocus = !(this.tUp && timeMs() - this.tUp < 300);
                }}
                onMouseMove={() => {
                    this.willFocus = false;
                }}
                onMouseUp={() => {
                    if (this.willFocus) {
                        this.tUp = timeMs();
                        this.onPreview(url);
                    }
                }}>
                <Card>
                    <CardHeader
                        title={

                                {index}. {fields.filename}

                        }
                        action={icon}
                        subheader={truncatePath(fields.path)}
                    />
                    <CardContent>
                        <Grid container alignItems="flex-end">
                            <Grid item md={4}>
                                <Typography variant="caption">
                                    {wordCount}
                                </Typography>

                                {fields.date && (
                                    <Typography variant="caption">
                                        Modified:{' '}
                                        {DateTime.fromISO(fields.date)
                                            .toLocaleString(DateTime.DATE_FULL)
                                            .replace(/\s/g, ' ')}
                                    </Typography>
                                )}

                                {fields['date-created'] && (
                                    <Typography variant="caption">
                                        Created:
                                        {DateTime.fromISO(
                                            fields['date-created']
                                        ).toLocaleString(DateTime.DATE_FULL)}
                                    </Typography>
                                )}

                                <Typography variant="caption">
                                    <Tooltip title="Download original file">

                                            <IconCloudDownload color="action" />

                                    </Tooltip>
                                </Typography>
                            </Grid>
                            <Grid item md={8}>

{text}

                            </Grid>{' '}
                        </Grid>
                    </CardContent>
                </Card>

        );
    }
}

const mapStateToProps = ({ doc }) => ({ doc });
export default withStyles(styles)(connect(mapStateToProps)(ResultItem));
<|endoftext|>


<commit_before>export default function Templar(dom, tmpl, context) {
	let node = dom.importNode(tmpl.content, true)
	let dataPoints = [...node.querySelectorAll('[data-bind]')]

	function bindToElem(elem) {
		let binds = [...elem.dataset.bind.split(" ")]
		let attrReg = /^\[(.+)\]\:(.+)$/i

		binds.forEach((v) => {
			let matches = v.match(attrReg)

			// Attr binding?
			if(matches) {
				if( elem.hasAttribute(matches[1]) ) {
					let data = getData(matches[2], context)
					elem.setAttribute(matches[1], data)
				}
			}
			else {
				elem.textContent = getData(v, context)
			}
		})
	}

	function getData(name, context) {
		if( context.hasOwnProperty(name) )
			return context[name]
		else
			return ""
	}

	dataPoints.forEach(bindToElem)

	return node
}
<commit_msg>added default value for context<commit_after>export default function Templar(dom, tmpl, context={}) {
	let node = dom.importNode(tmpl.content, true)
	let dataPoints = [...node.querySelectorAll('[data-bind]')]

	function bindToElem(elem) {
		let binds = [...elem.dataset.bind.split(" ")]
		let attrReg = /^\[(.+)\]\:(.+)$/i

		binds.forEach((v) => {
			let matches = v.match(attrReg)

			// Attr binding?
			if(matches) {
				if( elem.hasAttribute(matches[1]) ) {
					let data = getData(matches[2], context)
					elem.setAttribute(matches[1], data)
				}
			}
			else {
				elem.textContent = getData(v, context)
			}
		})
	}

	function getData(name, context) {
		if( context.hasOwnProperty(name) )
			return context[name]
		else
			return ""
	}

	dataPoints.forEach(bindToElem)

	return node
}
<|endoftext|>


<commit_before>'use strict';

import React, {
    Component,
    View,
    Text,
    StyleSheet,
    TouchableOpacity
} from 'react-native';

import {AnimatedCircularProgress} from 'react-native-circular-progress';
var Icon = require('react-native-vector-icons/Ionicons');

class DailySteps extends Component {
    constructor(props) {
        super(props);

        this._onPressButton = this._onPressButton.bind(this);
    }

    renderSummary() {
        return (
            <TouchableOpacity disabled={this.props.fill===0} onPress={this._onPressButton}>
                <View>
                    <AnimatedCircularProgress
                        size={40}
                        width={5}
                        fill={this.props.fill}
                        tintColor="#fe751f"
                        backgroundColor="#d2d2d2"
                        rotation={360}
                    >
                        {
                            (fill) => (

                                <Text style={styles.fill}>
                                    {this.props.day}
                                </Text>

                            )
                        }
                    </AnimatedCircularProgress>
                </View>
            </TouchableOpacity>
        )
    }

    renderDay() {
        return (
            <AnimatedCircularProgress
                size={270}
                width={20}
                fill={this.props.fill}
                tintColor="#fe751f"
                backgroundColor="#d2d2d2"
                rotation={360}
            >
                {
                    (fill) => (
                        <View style={styles.dayFill}>
                            <Icon name='android-walk' size={40} color='#e74c3c'/>
                            <Text style={styles.steps}>
                                { this.props.steps } Steps
                            </Text>
                        </View>
                    )
                }
            </AnimatedCircularProgress>
        )
    }

    render() {

        if (this.props.isSummary) {
            return (<View style={styles.container}>
                    {this.renderDay()}
                </View>
            )
        } else {
            return (
                <View style={styles.container}>
                    {this.renderSummary()}
                </View>
            )
        }
    }

    _onPressButton() {
        this.props.onSelectDay(this.props.name);
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        alignItems: 'center'
    },
    fill: {
        position: 'absolute',
        top: 12,
        left: 15
    },
    dayFill: {
        backgroundColor: 'transparent',
        position: 'absolute',
        top: 90,
        left: 80,
        alignItems: 'center',
        justifyContent: 'center',
    },
    steps: {
        backgroundColor: 'transparent',
        fontSize: 30,
        textAlign: 'center',
        color: '#e74c3c',
        fontWeight: '100'
    }
});

export default DailySteps;<commit_msg>Make daily & summary Step widget<commit_after>'use strict';

import React, {
    Component,
    View,
    Text,
    StyleSheet,
    TouchableOpacity
} from 'react-native';

import {AnimatedCircularProgress} from 'react-native-circular-progress';
var Icon = require('react-native-vector-icons/Ionicons');

const tintColor = "#fe751f";
const backgroundColor = "#d2d2d2";
const rotation = 360;
const summaryDim = {
    size:40,
    width:5
};
const dayDim = {
    size:270,
    width: 20,
    iconSize:40
};

class DailySteps extends Component {
    constructor(props) {
        super(props);

        this._onPressButton = this._onPressButton.bind(this);
    }

    renderSummary() {
        return (
            <TouchableOpacity disabled={this.props.fill===0} onPress={this._onPressButton}>
                <View>
                    <AnimatedCircularProgress
                        size={summaryDim.size}
                        width={summaryDim.width}
                        fill={this.props.fill}
                        tintColor={tintColor}
                        backgroundColor={backgroundColor}
                        rotation={rotation}
                    >
                        {
                            (fill) => (

                                <Text style={styles.fill}>
                                    {this.props.day}
                                </Text>

                            )
                        }
                    </AnimatedCircularProgress>
                </View>
            </TouchableOpacity>
        )
    }

    renderDay() {
        return (
            <AnimatedCircularProgress
                size={dayDim.size}
                width={dayDim.width}
                fill={this.props.fill}
                tintColor={tintColor}
                backgroundColor={backgroundColor}
                rotation={rotation}
            >
                {
                    (fill) => (
                        <View style={styles.dayFill}>
                            <Icon name='android-walk' size={dayDim.iconSize} color='#e74c3c'/>
                            <Text style={styles.steps}>
                                { this.props.steps } Steps
                            </Text>
                        </View>
                    )
                }
            </AnimatedCircularProgress>
        )
    }

    render() {

        if (this.props.isSummary) {
            return (<View style={styles.container}>
                    {this.renderDay()}
                </View>
            )
        } else {
            return (
                <View style={styles.container}>
                    {this.renderSummary()}
                </View>
            )
        }
    }

    _onPressButton() {
        this.props.onSelectDay(this.props.name);
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        alignItems: 'center'
    },
    fill: {
        position: 'absolute',
        top: 12,
        left: 15
    },
    dayFill: {
        backgroundColor: 'transparent',
        position: 'absolute',
        top: 90,
        left: 80,
        alignItems: 'center',
        justifyContent: 'center',
    },
    steps: {
        backgroundColor: 'transparent',
        fontSize: 30,
        textAlign: 'center',
        color: '#e74c3c',
        fontWeight: '100'
    }
});

export default DailySteps;<|endoftext|>


<commit_before>import { QIcon } from '../icon'
import { QCheckbox } from '../checkbox'
import { QSlideTransition } from '../slide-transition'
import { QSpinner } from '../spinner'
import Ripple from '../../directives/ripple'

export default {
  name: 'q-tree',
  directives: {
    Ripple
  },
  props: {
    nodes: Array,
    nodeKey: {
      type: String,
      default: 'id'
    },

    color: {
      type: String,
      default: 'grey'
    },
    controlColor: String,
    textColor: String,
    dark: Boolean,

    icon: String,

    tickStrategy: {
      type: String,
      validator: v => ['none', 'strict', 'leaf', 'leaf-filtered'].includes(v)
    },
    ticked: Array, // sync
    expanded: Array, // sync
    selected: {}, // sync

    defaultExpandAll: Boolean,
    accordion: Boolean,

    filter: String,
    filterMethod: {
      type: Function,
      default (node, filter) {
        return node.label && node.label.indexOf(filter) > -1
      }
    },

    noNodesLabel: String,
    noResultsLabel: String
  },
  computed: {
    hasRipple () {
      return __THEME__ === 'mat' && !this.noRipple
    },
    classes () {
      return [
        `text-${this.color}`,
        { 'q-tree-dark': this.dark }
      ]
    },
    hasSelection () {
      return this.selected !== void 0
    },
    computedIcon () {
      return this.icon || this.$q.icon.tree.icon
    },
    computedControlColor () {
      return this.controlColor || this.color
    },
    contentClass () {
      return `text-${this.textColor || (this.dark ? 'white' : 'black')}`
    },
    meta () {
      const meta = {}

      const travel = (node, parent) => {
        const tickStrategy = node.tickStrategy || (parent ? parent.tickStrategy : this.tickStrategy)
        const
          key = node[this.nodeKey],
          isParent = node.children && node.children.length > 0,
          isLeaf = !isParent,
          selectable = !node.disabled && this.hasSelection && node.selectable !== false,
          expandable = !node.disabled && node.expandable !== false,
          hasTicking = tickStrategy !== 'none',
          strictTicking = tickStrategy === 'strict',
          leafFilteredTicking = tickStrategy === 'leaf-filtered',
          leafTicking = tickStrategy === 'leaf' || tickStrategy === 'leaf-filtered'

        let tickable = !node.disabled && node.tickable !== false
        if (leafTicking && tickable && parent && !parent.tickable) {
          tickable = false
        }

        let lazy = node.lazy
        if (lazy && this.lazy[key]) {
          lazy = this.lazy[key]
        }

        const m = {
          key,
          parent,
          isParent,
          isLeaf,
          lazy,
          disabled: node.disabled,
          link: selectable || (expandable && (isParent || lazy === true)),
          children: [],
          matchesFilter: this.filter ? this.filterMethod(node, this.filter) : true,

          selected: key === this.selected && selectable,
          selectable,
          expanded: isParent ? this.innerExpanded.includes(key) : false,
          expandable,
          noTick: node.noTick || (!strictTicking && lazy && lazy !== 'loaded'),
          tickable,
          tickStrategy,
          hasTicking,
          strictTicking,
          leafFilteredTicking,
          leafTicking,
          ticked: strictTicking
            ? this.innerTicked.includes(key)
            : (isLeaf ? this.innerTicked.includes(key) : false)
        }

        meta[key] = m

        if (isParent) {
          m.children = node.children.map(n => travel(n, m))

          if (this.filter) {
            if (!m.matchesFilter) {
              m.matchesFilter = m.children.some(n => n.matchesFilter)
            }
            if (
              m.matchesFilter &&
              !m.noTick &&
              !m.disabled &&
              m.tickable &&
              leafFilteredTicking &&
              m.children.every(n => !n.matchesFilter || n.noTick || !n.tickable)
            ) {
              m.tickable = false
            }
          }

          if (m.matchesFilter) {
            if (!m.noTick && !strictTicking && m.children.every(n => n.noTick)) {
              m.noTick = true
            }

            if (leafTicking) {
              m.ticked = false
              m.indeterminate = m.children.some(node => node.indeterminate)

              if (!m.indeterminate) {
                const sel = m.children
                  .reduce((acc, meta) => meta.ticked ? acc + 1 : acc, 0)

                if (sel === m.children.length) {
                  m.ticked = true
                }
                else if (sel > 0) {
                  m.indeterminate = true
                }
              }
            }
          }
        }

        return m
      }

      this.nodes.forEach(node => travel(node, null))
      return meta
    }
  },
  data () {
    return {
      lazy: {},
      innerTicked: this.ticked || [],
      innerExpanded: this.expanded || []
    }
  },
  watch: {
    ticked (val) {
      this.innerTicked = val
    },
    expanded (val) {
      this.innerExpanded = val
    }
  },
  methods: {
    getNodeByKey (key) {
      const reduce = [].reduce

      const find = (result, node) => {
        if (result || !node) {
          return result
        }
        if (Array.isArray(node)) {
          return reduce.call(Object(node), find, result)
        }
        if (node[this.nodeKey] === key) {
          return node
        }
        if (node.children) {
          return find(null, node.children)
        }
      }

      return find(null, this.nodes)
    },
    getTickedNodes () {
      return this.innerTicked.map(key => this.getNodeByKey(key))
    },
    getExpandedNodes () {
      return this.innerExpanded.map(key => this.getNodeByKey(key))
    },
    isExpanded (key) {
      return key && this.meta[key]
        ? this.meta[key].expanded
        : false
    },
    collapseAll () {
      if (this.expanded !== void 0) {
        this.$emit('update:expanded', [])
      }
      else {
        this.innerExpanded = []
      }
    },
    expandAll () {
      const
        expanded = this.innerExpanded,
        travel = node => {
          if (node.children && node.children.length > 0) {
            if (node.expandable !== false && node.disabled !== true) {
              expanded.push(node[this.nodeKey])
              node.children.forEach(travel)
            }
          }
        }

      this.nodes.forEach(travel)

      if (this.expanded !== void 0) {
        this.$emit('update:expanded', expanded)
      }
      else {
        this.innerExpanded = expanded
      }
    },
    setExpanded (key, state, node = this.getNodeByKey(key), meta = this.meta[key]) {
      if (meta.lazy && meta.lazy !== 'loaded') {
        if (meta.lazy === 'loading') {
          return
        }

        this.$set(this.lazy, key, 'loading')
        this.$emit('lazy-load', {
          node,
          key,
          done: children => {
            this.lazy[key] = 'loaded'
            if (children) {
              node.children = children
            }
            this.$nextTick(() => {
              const m = this.meta[key]
              if (m && m.isParent) {
                this.__setExpanded(key, true)
              }
            })
          },
          fail: () => {
            this.$delete(this.lazy, key)
          }
        })
      }
      else if (meta.isParent && meta.expandable) {
        this.__setExpanded(key, state)
      }
    },
    __setExpanded (key, state) {
      let target = this.innerExpanded
      const emit = this.expanded !== void 0

      if (emit) {
        target = target.slice()
      }

      if (state) {
        if (this.accordion) {
          if (this.meta[key]) {
            const collapse = []
            if (this.meta[key].parent) {
              this.meta[key].parent.children.forEach(m => {
                if (m.key !== key && m.expandable) {
                  collapse.push(m.key)
                }
              })
            }
            else {
              this.nodes.forEach(node => {
                const k = node[this.nodeKey]
                if (k !== key) {
                  collapse.push(k)
                }
              })
            }
            if (collapse.length > 0) {
              target = target.filter(k => !collapse.includes(k))
            }
          }
        }

        target = target.concat([ key ])
          .filter((key, index, self) => self.indexOf(key) === index)
      }
      else {
        target = target.filter(k => k !== key)
      }

      if (emit) {
        this.$emit(`update:expanded`, target)
      }
    },
    isTicked (key) {
      return key && this.meta[key]
        ? this.meta[key].ticked
        : false
    },
    setTicked (keys, state) {
      let target = this.innerTicked
      const emit = this.ticked !== void 0

      if (emit) {
        target = target.slice()
      }

      if (state) {
        target = target.concat(keys)
          .filter((key, index, self) => self.indexOf(key) === index)
      }
      else {
        target = target.filter(k => !keys.includes(k))
      }

      if (emit) {
        this.$emit(`update:ticked`, target)
      }
    },
    __getSlotScope (node, meta, key) {
      const scope = { tree: this, node, key, color: this.color, dark: this.dark }

      Object.defineProperty(scope, 'expanded', {
        get: () => { return meta.expanded },
        set: val => { val !== meta.expanded && this.setExpanded(key, val) }
      })
      Object.defineProperty(scope, 'ticked', {
        get: () => { return meta.ticked },
        set: val => { val !== meta.ticked && this.setTicked([ key ], val) }
      })

      return scope
    },
    __getChildren (h, nodes) {
      return (
        this.filter
          ? nodes.filter(n => this.meta[n[this.nodeKey]].matchesFilter)
          : nodes
      ).map(child => this.__getNode(h, child))
    },
    __getNodeMedia (h, node) {
      if (node.icon) {
        return h(QIcon, {
          staticClass: `q-tree-icon q-mr-sm`,
          props: { name: node.icon }
        })
      }
      if (node.img || node.avatar) {
        return h('img', {
          staticClass: `q-tree-img q-mr-sm`,
          'class': { avatar: node.avatar },
          domProps: { src: node.img || node.avatar }
        })
      }
    },
    __getNode (h, node) {
      const
        key = node[this.nodeKey],
        meta = this.meta[key],
        header = node.header
          ? this.$scopedSlots[`header-${node.header}`] || this.$scopedSlots['default-header']
          : this.$scopedSlots['default-header']

      const children = meta.isParent
        ? this.__getChildren(h, node.children)
        : []

      const isParent = children.length > 0 || (meta.lazy && meta.lazy !== 'loaded')

      let
        body = node.body
          ? this.$scopedSlots[`body-${node.body}`] || this.$scopedSlots['default-body']
          : this.$scopedSlots['default-body'],
        slotScope = header || body
          ? this.__getSlotScope(node, meta, key)
          : null

      if (body) {
        body = h('div', { staticClass: 'q-tree-node-body relative-position' }, [
          h('div', { 'class': this.contentClass }, [
            body(slotScope)
          ])
        ])
      }

      return h('div', {
        key,
        staticClass: 'q-tree-node',
        'class': { 'q-tree-node-parent': isParent }
      }, [
        h('div', {
          staticClass: 'q-tree-node-header relative-position row no-wrap items-center',
          'class': {
            'q-tree-node-link': meta.link,
            'q-tree-node-selected': meta.selected,
            disabled: meta.disabled
          },
          on: { click: () => { this.__onClick(node, meta) } },
          directives: __THEME__ === 'mat' && meta.selectable
            ? [{ name: 'ripple' }]
            : null
        }, [
          meta.lazy === 'loading'
            ? h(QSpinner, {
              staticClass: 'q-tree-node-header-media q-mr-xs',
              props: { color: this.computedControlColor }
            })
            : (
              isParent
                ? h(QIcon, {
                  staticClass: 'q-tree-arrow q-mr-xs transition-generic',
                  'class': { 'rotate-90': meta.expanded },
                  props: { name: this.computedIcon },
                  nativeOn: this.hasSelection
                    ? { click: e => { this.__onExpandClick(node, meta, e) } }
                    : undefined
                })
                : null
            ),

          h('span', { 'staticClass': 'row no-wrap items-center', 'class': this.contentClass }, [
            meta.hasTicking && !meta.noTick
              ? h(QCheckbox, {
                staticClass: 'q-mr-xs',
                props: {
                  value: meta.indeterminate ? null : meta.ticked,
                  color: this.computedControlColor,
                  dark: this.dark,
                  keepColor: true,
                  disable: !meta.tickable
                },
                on: {
                  input: v => {
                    this.__onTickedClick(node, meta, v)
                  }
                }
              })
              : null,
            header
              ? header(slotScope)
              : [
                this.__getNodeMedia(h, node),
                h('span', node.label)
              ]
          ])
        ]),

        isParent
          ? h(QSlideTransition, [
            h('div', {
              directives: [{ name: 'show', value: meta.expanded }],
              staticClass: 'q-tree-node-collapsible',
              'class': `text-${this.color}`
            }, [
              body,
              h('div', {
                staticClass: 'q-tree-children',
                'class': { disabled: meta.disabled }
              }, children)
            ])
          ])
          : body
      ])
    },
    __onClick (node, meta) {
      if (this.hasSelection) {
        meta.selectable && this.$emit('update:selected', meta.key)
      }
      else {
        this.__onExpandClick(node, meta)
      }

      if (typeof node.handler === 'function') {
        node.handler(node)
      }
    },
    __onExpandClick (node, meta, e) {
      if (e !== void 0) {
        e.stopPropagation()
      }
      this.setExpanded(meta.key, !meta.expanded, node, meta)
    },
    __onTickedClick (node, meta, state) {
      if (meta.indeterminate && state) {
        state = false
      }
      if (meta.strictTicking) {
        this.setTicked([ meta.key ], state)
      }
      else if (meta.leafTicking) {
        const keys = []
        const travel = meta => {
          if (meta.isParent) {
            if (!state && !meta.noTick && meta.tickable) {
              keys.push(meta.key)
            }
            if (meta.leafTicking) {
              meta.children.forEach(travel)
            }
          }
          else if (!meta.noTick && meta.tickable && (!meta.leafFilteredTicking || meta.matchesFilter)) {
            keys.push(meta.key)
          }
        }
        travel(meta)
        this.setTicked(keys, state)
      }
    }
  },
  render (h) {
    const children = this.__getChildren(h, this.nodes)

    return h(
      'div', {
        staticClass: 'q-tree relative-position',
        'class': this.classes
      },
      children.length === 0
        ? (
          this.filter
            ? this.noResultsLabel || this.$q.i18n.tree.noResults
            : this.noNodesLabel || this.$q.i18n.tree.noNodes
        )
        : children
    )
  },
  created () {
    if (this.defaultExpandAll) {
      this.expandAll()
    }
  }
}
<commit_msg>fix 1397 - Cannot unselect a node in QTree (#1398)<commit_after>import { QIcon } from '../icon'
import { QCheckbox } from '../checkbox'
import { QSlideTransition } from '../slide-transition'
import { QSpinner } from '../spinner'
import Ripple from '../../directives/ripple'

export default {
  name: 'q-tree',
  directives: {
    Ripple
  },
  props: {
    nodes: Array,
    nodeKey: {
      type: String,
      default: 'id'
    },

    color: {
      type: String,
      default: 'grey'
    },
    controlColor: String,
    textColor: String,
    dark: Boolean,

    icon: String,

    tickStrategy: {
      type: String,
      validator: v => ['none', 'strict', 'leaf', 'leaf-filtered'].includes(v)
    },
    ticked: Array, // sync
    expanded: Array, // sync
    selected: {}, // sync

    defaultExpandAll: Boolean,
    accordion: Boolean,

    filter: String,
    filterMethod: {
      type: Function,
      default (node, filter) {
        return node.label && node.label.indexOf(filter) > -1
      }
    },

    noNodesLabel: String,
    noResultsLabel: String
  },
  computed: {
    hasRipple () {
      return __THEME__ === 'mat' && !this.noRipple
    },
    classes () {
      return [
        `text-${this.color}`,
        { 'q-tree-dark': this.dark }
      ]
    },
    hasSelection () {
      return this.selected !== void 0
    },
    computedIcon () {
      return this.icon || this.$q.icon.tree.icon
    },
    computedControlColor () {
      return this.controlColor || this.color
    },
    contentClass () {
      return `text-${this.textColor || (this.dark ? 'white' : 'black')}`
    },
    meta () {
      const meta = {}

      const travel = (node, parent) => {
        const tickStrategy = node.tickStrategy || (parent ? parent.tickStrategy : this.tickStrategy)
        const
          key = node[this.nodeKey],
          isParent = node.children && node.children.length > 0,
          isLeaf = !isParent,
          selectable = !node.disabled && this.hasSelection && node.selectable !== false,
          expandable = !node.disabled && node.expandable !== false,
          hasTicking = tickStrategy !== 'none',
          strictTicking = tickStrategy === 'strict',
          leafFilteredTicking = tickStrategy === 'leaf-filtered',
          leafTicking = tickStrategy === 'leaf' || tickStrategy === 'leaf-filtered'

        let tickable = !node.disabled && node.tickable !== false
        if (leafTicking && tickable && parent && !parent.tickable) {
          tickable = false
        }

        let lazy = node.lazy
        if (lazy && this.lazy[key]) {
          lazy = this.lazy[key]
        }

        const m = {
          key,
          parent,
          isParent,
          isLeaf,
          lazy,
          disabled: node.disabled,
          link: selectable || (expandable && (isParent || lazy === true)),
          children: [],
          matchesFilter: this.filter ? this.filterMethod(node, this.filter) : true,

          selected: key === this.selected && selectable,
          selectable,
          expanded: isParent ? this.innerExpanded.includes(key) : false,
          expandable,
          noTick: node.noTick || (!strictTicking && lazy && lazy !== 'loaded'),
          tickable,
          tickStrategy,
          hasTicking,
          strictTicking,
          leafFilteredTicking,
          leafTicking,
          ticked: strictTicking
            ? this.innerTicked.includes(key)
            : (isLeaf ? this.innerTicked.includes(key) : false)
        }

        meta[key] = m

        if (isParent) {
          m.children = node.children.map(n => travel(n, m))

          if (this.filter) {
            if (!m.matchesFilter) {
              m.matchesFilter = m.children.some(n => n.matchesFilter)
            }
            if (
              m.matchesFilter &&
              !m.noTick &&
              !m.disabled &&
              m.tickable &&
              leafFilteredTicking &&
              m.children.every(n => !n.matchesFilter || n.noTick || !n.tickable)
            ) {
              m.tickable = false
            }
          }

          if (m.matchesFilter) {
            if (!m.noTick && !strictTicking && m.children.every(n => n.noTick)) {
              m.noTick = true
            }

            if (leafTicking) {
              m.ticked = false
              m.indeterminate = m.children.some(node => node.indeterminate)

              if (!m.indeterminate) {
                const sel = m.children
                  .reduce((acc, meta) => meta.ticked ? acc + 1 : acc, 0)

                if (sel === m.children.length) {
                  m.ticked = true
                }
                else if (sel > 0) {
                  m.indeterminate = true
                }
              }
            }
          }
        }

        return m
      }

      this.nodes.forEach(node => travel(node, null))
      return meta
    }
  },
  data () {
    return {
      lazy: {},
      innerTicked: this.ticked || [],
      innerExpanded: this.expanded || []
    }
  },
  watch: {
    ticked (val) {
      this.innerTicked = val
    },
    expanded (val) {
      this.innerExpanded = val
    }
  },
  methods: {
    getNodeByKey (key) {
      const reduce = [].reduce

      const find = (result, node) => {
        if (result || !node) {
          return result
        }
        if (Array.isArray(node)) {
          return reduce.call(Object(node), find, result)
        }
        if (node[this.nodeKey] === key) {
          return node
        }
        if (node.children) {
          return find(null, node.children)
        }
      }

      return find(null, this.nodes)
    },
    getTickedNodes () {
      return this.innerTicked.map(key => this.getNodeByKey(key))
    },
    getExpandedNodes () {
      return this.innerExpanded.map(key => this.getNodeByKey(key))
    },
    isExpanded (key) {
      return key && this.meta[key]
        ? this.meta[key].expanded
        : false
    },
    collapseAll () {
      if (this.expanded !== void 0) {
        this.$emit('update:expanded', [])
      }
      else {
        this.innerExpanded = []
      }
    },
    expandAll () {
      const
        expanded = this.innerExpanded,
        travel = node => {
          if (node.children && node.children.length > 0) {
            if (node.expandable !== false && node.disabled !== true) {
              expanded.push(node[this.nodeKey])
              node.children.forEach(travel)
            }
          }
        }

      this.nodes.forEach(travel)

      if (this.expanded !== void 0) {
        this.$emit('update:expanded', expanded)
      }
      else {
        this.innerExpanded = expanded
      }
    },
    setExpanded (key, state, node = this.getNodeByKey(key), meta = this.meta[key]) {
      if (meta.lazy && meta.lazy !== 'loaded') {
        if (meta.lazy === 'loading') {
          return
        }

        this.$set(this.lazy, key, 'loading')
        this.$emit('lazy-load', {
          node,
          key,
          done: children => {
            this.lazy[key] = 'loaded'
            if (children) {
              node.children = children
            }
            this.$nextTick(() => {
              const m = this.meta[key]
              if (m && m.isParent) {
                this.__setExpanded(key, true)
              }
            })
          },
          fail: () => {
            this.$delete(this.lazy, key)
          }
        })
      }
      else if (meta.isParent && meta.expandable) {
        this.__setExpanded(key, state)
      }
    },
    __setExpanded (key, state) {
      let target = this.innerExpanded
      const emit = this.expanded !== void 0

      if (emit) {
        target = target.slice()
      }

      if (state) {
        if (this.accordion) {
          if (this.meta[key]) {
            const collapse = []
            if (this.meta[key].parent) {
              this.meta[key].parent.children.forEach(m => {
                if (m.key !== key && m.expandable) {
                  collapse.push(m.key)
                }
              })
            }
            else {
              this.nodes.forEach(node => {
                const k = node[this.nodeKey]
                if (k !== key) {
                  collapse.push(k)
                }
              })
            }
            if (collapse.length > 0) {
              target = target.filter(k => !collapse.includes(k))
            }
          }
        }

        target = target.concat([ key ])
          .filter((key, index, self) => self.indexOf(key) === index)
      }
      else {
        target = target.filter(k => k !== key)
      }

      if (emit) {
        this.$emit(`update:expanded`, target)
      }
    },
    isTicked (key) {
      return key && this.meta[key]
        ? this.meta[key].ticked
        : false
    },
    setTicked (keys, state) {
      let target = this.innerTicked
      const emit = this.ticked !== void 0

      if (emit) {
        target = target.slice()
      }

      if (state) {
        target = target.concat(keys)
          .filter((key, index, self) => self.indexOf(key) === index)
      }
      else {
        target = target.filter(k => !keys.includes(k))
      }

      if (emit) {
        this.$emit(`update:ticked`, target)
      }
    },
    __getSlotScope (node, meta, key) {
      const scope = { tree: this, node, key, color: this.color, dark: this.dark }

      Object.defineProperty(scope, 'expanded', {
        get: () => { return meta.expanded },
        set: val => { val !== meta.expanded && this.setExpanded(key, val) }
      })
      Object.defineProperty(scope, 'ticked', {
        get: () => { return meta.ticked },
        set: val => { val !== meta.ticked && this.setTicked([ key ], val) }
      })

      return scope
    },
    __getChildren (h, nodes) {
      return (
        this.filter
          ? nodes.filter(n => this.meta[n[this.nodeKey]].matchesFilter)
          : nodes
      ).map(child => this.__getNode(h, child))
    },
    __getNodeMedia (h, node) {
      if (node.icon) {
        return h(QIcon, {
          staticClass: `q-tree-icon q-mr-sm`,
          props: { name: node.icon }
        })
      }
      if (node.img || node.avatar) {
        return h('img', {
          staticClass: `q-tree-img q-mr-sm`,
          'class': { avatar: node.avatar },
          domProps: { src: node.img || node.avatar }
        })
      }
    },
    __getNode (h, node) {
      const
        key = node[this.nodeKey],
        meta = this.meta[key],
        header = node.header
          ? this.$scopedSlots[`header-${node.header}`] || this.$scopedSlots['default-header']
          : this.$scopedSlots['default-header']

      const children = meta.isParent
        ? this.__getChildren(h, node.children)
        : []

      const isParent = children.length > 0 || (meta.lazy && meta.lazy !== 'loaded')

      let
        body = node.body
          ? this.$scopedSlots[`body-${node.body}`] || this.$scopedSlots['default-body']
          : this.$scopedSlots['default-body'],
        slotScope = header || body
          ? this.__getSlotScope(node, meta, key)
          : null

      if (body) {
        body = h('div', { staticClass: 'q-tree-node-body relative-position' }, [
          h('div', { 'class': this.contentClass }, [
            body(slotScope)
          ])
        ])
      }

      return h('div', {
        key,
        staticClass: 'q-tree-node',
        'class': { 'q-tree-node-parent': isParent }
      }, [
        h('div', {
          staticClass: 'q-tree-node-header relative-position row no-wrap items-center',
          'class': {
            'q-tree-node-link': meta.link,
            'q-tree-node-selected': meta.selected,
            disabled: meta.disabled
          },
          on: { click: () => { this.__onClick(node, meta) } },
          directives: __THEME__ === 'mat' && meta.selectable
            ? [{ name: 'ripple' }]
            : null
        }, [
          meta.lazy === 'loading'
            ? h(QSpinner, {
              staticClass: 'q-tree-node-header-media q-mr-xs',
              props: { color: this.computedControlColor }
            })
            : (
              isParent
                ? h(QIcon, {
                  staticClass: 'q-tree-arrow q-mr-xs transition-generic',
                  'class': { 'rotate-90': meta.expanded },
                  props: { name: this.computedIcon },
                  nativeOn: this.hasSelection
                    ? { click: e => { this.__onExpandClick(node, meta, e) } }
                    : undefined
                })
                : null
            ),

          h('span', { 'staticClass': 'row no-wrap items-center', 'class': this.contentClass }, [
            meta.hasTicking && !meta.noTick
              ? h(QCheckbox, {
                staticClass: 'q-mr-xs',
                props: {
                  value: meta.indeterminate ? null : meta.ticked,
                  color: this.computedControlColor,
                  dark: this.dark,
                  keepColor: true,
                  disable: !meta.tickable
                },
                on: {
                  input: v => {
                    this.__onTickedClick(node, meta, v)
                  }
                }
              })
              : null,
            header
              ? header(slotScope)
              : [
                this.__getNodeMedia(h, node),
                h('span', node.label)
              ]
          ])
        ]),

        isParent
          ? h(QSlideTransition, [
            h('div', {
              directives: [{ name: 'show', value: meta.expanded }],
              staticClass: 'q-tree-node-collapsible',
              'class': `text-${this.color}`
            }, [
              body,
              h('div', {
                staticClass: 'q-tree-children',
                'class': { disabled: meta.disabled }
              }, children)
            ])
          ])
          : body
      ])
    },
    __onClick (node, meta) {
      if (this.hasSelection) {
        if (meta.selectable) {
          this.$emit('update:selected', meta.key !== this.selected ? meta.key : null)
        }
      }
      else {
        this.__onExpandClick(node, meta)
      }

      if (typeof node.handler === 'function') {
        node.handler(node)
      }
    },
    __onExpandClick (node, meta, e) {
      if (e !== void 0) {
        e.stopPropagation()
      }
      this.setExpanded(meta.key, !meta.expanded, node, meta)
    },
    __onTickedClick (node, meta, state) {
      if (meta.indeterminate && state) {
        state = false
      }
      if (meta.strictTicking) {
        this.setTicked([ meta.key ], state)
      }
      else if (meta.leafTicking) {
        const keys = []
        const travel = meta => {
          if (meta.isParent) {
            if (!state && !meta.noTick && meta.tickable) {
              keys.push(meta.key)
            }
            if (meta.leafTicking) {
              meta.children.forEach(travel)
            }
          }
          else if (!meta.noTick && meta.tickable && (!meta.leafFilteredTicking || meta.matchesFilter)) {
            keys.push(meta.key)
          }
        }
        travel(meta)
        this.setTicked(keys, state)
      }
    }
  },
  render (h) {
    const children = this.__getChildren(h, this.nodes)

    return h(
      'div', {
        staticClass: 'q-tree relative-position',
        'class': this.classes
      },
      children.length === 0
        ? (
          this.filter
            ? this.noResultsLabel || this.$q.i18n.tree.noResults
            : this.noNodesLabel || this.$q.i18n.tree.noNodes
        )
        : children
    )
  },
  created () {
    if (this.defaultExpandAll) {
      this.expandAll()
    }
  }
}
<|endoftext|>


<commit_before>/** index.js
* @file: /config/index.js
* @description: Handles passport authentication
* @parameters: Object(app), Object(passport)
* @exports: Passport authentication
*/
var passport = require('passport')
var FacebookStrategy = require('./facebook')
var ObjectID = require('mongodb').ObjectID

module.exports = function (app, utils) {
  passport.use(FacebookStrategy({
    facebook: {
      app_id: utils.config.facebook.app_id,
      app_secret: utils.config.facebook.app_secret,
      callback: utils.config.facebook.callback
    },
    dbinstance: utils.dbinstance
  }))

  passport.serializeUser(function (user, done) {
    //console.log(user)
    done(null, user.id)
  })

  // TODO error handling etc
  passport.deserializeUser(function (id, done) {
    var usersdb = utils.dbinstance.collection('users')

    usersdb.find({_id: new ObjectID(id)}, ['_id', 'name', 'fb_photo', 'vegosvar_photo', 'active_photo', 'info']).toArray(function (error, result) {
      done(error, result[0])
    })
  })
}<commit_msg>Integrate instagram auth and remove duplicated config<commit_after>/** index.js
* @file: /config/index.js
* @description: Handles passport authentication
* @parameters: Object(app), Object(passport)
* @exports: Passport authentication
*/
var ObjectID = require('mongodb').ObjectID
var passport = require('passport')

module.exports = function (app, resources) {
  var FacebookStrategy = require('./facebook')(resources)
  var InstagramStrategy = require('./instagram')(resources)

  /* Facebook */
  passport.use(FacebookStrategy)

  /* Instagram (for admin) */
  passport.use(InstagramStrategy)

  passport.serializeUser(function (req, user, done) {
    done(null, user.id)
  })

  // TODO error handling etc
  passport.deserializeUser(function (req, id, done) {
    var usersdb = resources.collections.users

    usersdb.find({_id: new ObjectID(id)}, ['_id', 'name', 'fb_photo', 'vegosvar_photo', 'active_photo', 'info']).toArray(function (error, result) {
      done(error, result[0])
    })
  })

}<|endoftext|>


<commit_before>export const state = () => ({
  bio: 'Nicola is a frontend developer specialized in javascript development. He works for the most important swiss agencies.',
  menu: [
    {
      label: '2017-
-2011',
      slug: 'intro'
    },
    {
      label: 'About',
      slug: 'about'
    },
    {
      label: 'CV',
      slug: 'cv'
    },
    {
      label: 'Works',
      slug: 'works'
    },
    {
      label: 'Awards',
      slug: 'awards'
    },
    {
      label: 'Contact',
      slug: 'contact'
    }
  ],
  works: {
    years: [
      {
        label: '2019',
        content: [
          {
            label: 'Durisch+Nolli',
            image: '/images/durischnolli.jpg',
            href: 'https://durischnolli.ch'
          }
        ]
      },
      {
        label: '2018',
        content: [
          {
            label: 'Mistretta Coiffure',
            image: './images/mistretta.jpg',
            href: 'https://mistretta.ch'
          },
          {
            label: 'Axure Broker',
            image: './images/axure.jpg',
            href: 'https://axure-broker.ch'
          },
          {
            label: 'Charly Zenger',
            image: './images/charlyzenger.jpg',
            href: 'https://charlyzenger.ch'
          }
        ]
      },
      {
        label: '2017',
        content: [
          {
            label: 'H-Farm',
            image: './images/hfarm.jpg',
            href: 'https://h-farm.com'
          }
        ]
      }
    ]
  },
  awards: [
    {
      title: 'CSS Design Awards',
      lenght: 2,
      type: 'WSOTD'
    },
    {
      title: 'Awwwards',
      lenght: 10,
      type: 'SOTD'
    },
    {
      title: 'FWA',
      lenght: 1,
      type: 'FWAOTD'
    }
  ],
  contacts: [
    {
      label: 'Github',
      href: 'https://github.com/nicoladl'
    },
    {
      label: 'LinkedIn',
      href: 'https://www.linkedin.com/in/nicoladelazzari/'
    },
    {
      label: 'Twitter',
      href: 'https://twitter.com/nicoladelazzari'
    }
  ]
})
<commit_msg>fix image path<commit_after>export const state = () => ({
  bio: 'Nicola is a frontend developer specialized in javascript development. He works for the most important swiss agencies.',
  menu: [
    {
      label: '2017-
-2011',
      slug: 'intro'
    },
    {
      label: 'About',
      slug: 'about'
    },
    {
      label: 'CV',
      slug: 'cv'
    },
    {
      label: 'Works',
      slug: 'works'
    },
    {
      label: 'Awards',
      slug: 'awards'
    },
    {
      label: 'Contact',
      slug: 'contact'
    }
  ],
  works: {
    years: [
      {
        label: '2019',
        content: [
          {
            label: 'Durisch+Nolli',
            image: './images/durischnolli.jpg',
            href: 'https://durischnolli.ch'
          }
        ]
      },
      {
        label: '2018',
        content: [
          {
            label: 'Mistretta Coiffure',
            image: './images/mistretta.jpg',
            href: 'https://mistretta.ch'
          },
          {
            label: 'Axure Broker',
            image: './images/axure.jpg',
            href: 'https://axure-broker.ch'
          },
          {
            label: 'Charly Zenger',
            image: './images/charlyzenger.jpg',
            href: 'https://charlyzenger.ch'
          }
        ]
      },
      {
        label: '2017',
        content: [
          {
            label: 'H-Farm',
            image: './images/hfarm.jpg',
            href: 'https://h-farm.com'
          }
        ]
      }
    ]
  },
  awards: [
    {
      title: 'CSS Design Awards',
      lenght: 2,
      type: 'WSOTD'
    },
    {
      title: 'Awwwards',
      lenght: 10,
      type: 'SOTD'
    },
    {
      title: 'FWA',
      lenght: 1,
      type: 'FWAOTD'
    }
  ],
  contacts: [
    {
      label: 'Github',
      href: 'https://github.com/nicoladl'
    },
    {
      label: 'LinkedIn',
      href: 'https://www.linkedin.com/in/nicoladelazzari/'
    },
    {
      label: 'Twitter',
      href: 'https://twitter.com/nicoladelazzari'
    }
  ]
})
<|endoftext|>


<commit_before>/**
 * Binds a TinyMCE widget to <textarea> elements.
 */
angular.module('ui.tinymce', [])
  .value('uiTinymceConfig', {})
  .directive('uiTinymce', ['$rootScope', '$compile', '$timeout', '$window', '$sce', 'uiTinymceConfig', function($rootScope, $compile, $timeout, $window, $sce, uiTinymceConfig) {
    uiTinymceConfig = uiTinymceConfig || {};
    var generatedIds = 0;
    var ID_ATTR = 'ui-tinymce';
    if (uiTinymceConfig.baseUrl) {
      tinymce.baseURL = uiTinymceConfig.baseUrl;
    }

    return {
      require: ['ngModel', '^?form'],
      link: function(scope, element, attrs, ctrls) {
        if (!$window.tinymce) {
          return;
        }

        var ngModel = ctrls[0],
          form = ctrls[1] || null;

        var expression, options, tinyInstance,
          updateView = function(editor) {
            var content = editor.getContent({format: options.format}).trim();
            content = $sce.trustAsHtml(content);

            ngModel.$setViewValue(content);
            if (!$rootScope.$$phase) {
              scope.$apply();
            }
          };

        function toggleDisable(disabled) {
          if (disabled) {
            ensureInstance();

            if (tinyInstance) {
              tinyInstance.getBody().setAttribute('contenteditable', false);
            }
          } else {
            ensureInstance();

            if (tinyInstance) {
              tinyInstance.getBody().setAttribute('contenteditable', true);
            }
          }
        }

        // generate an ID
        attrs.$set('id', ID_ATTR + '-' + generatedIds++);

        expression = {};

        angular.extend(expression, scope.$eval(attrs.uiTinymce));

        options = {
          // Update model when calling setContent
          // (such as from the source editor popup)
          setup: function(ed) {
            ed.on('init', function() {
              ngModel.$render();
              ngModel.$setPristine();
              if (form) {
                form.$setPristine();
              }
            });

            // Update model on button click
            ed.on('ExecCommand', function() {
              ed.save();
              updateView(ed);
            });

            // Update model on change
            ed.on('change', function(e) {
              ed.save();
              updateView(ed);
            });

            ed.on('blur', function() {
              element[0].blur();
            });

            // Update model when an object has been resized (table, image)
            ed.on('ObjectResized', function() {
              ed.save();
              updateView(ed);
            });

            ed.on('remove', function() {
              element.remove();
            });

            if (expression.setup) {
              expression.setup(ed, {
                updateView: updateView
              });
            }
          },
          format: 'raw',
          selector: '#' + attrs.id
        };
        // extend options with initial uiTinymceConfig and
        // options from directive attribute value
        angular.extend(options, uiTinymceConfig, expression);
        // Wrapped in $timeout due to $tinymce:refresh implementation, requires
        // element to be present in DOM before instantiating editor when
        // re-rendering directive
        $timeout(function() {
          tinymce.init(options);
          toggleDisable(scope.$eval(attrs.ngDisabled));
        });

        ngModel.$formatters.unshift(function(modelValue) {
          return modelValue ? $sce.trustAsHtml(modelValue) : '';
        });

        ngModel.$parsers.unshift(function(viewValue) {
          return viewValue ? $sce.getTrustedHtml(viewValue) : '';
        });

        ngModel.$render = function() {
          ensureInstance();

          var viewValue = ngModel.$viewValue ?
            $sce.getTrustedHtml(ngModel.$viewValue) : '';

          // instance.getDoc() check is a guard against null value
          // when destruction & recreation of instances happen
          if (tinyInstance &&
            tinyInstance.getDoc()
          ) {
            tinyInstance.setContent(viewValue);
            // Triggering change event due to TinyMCE not firing event &
            // becoming out of sync for change callbacks
            tinyInstance.fire('change');
          }
        };

        attrs.$observe('disabled', toggleDisable);

        // This block is because of TinyMCE not playing well with removal and
        // recreation of instances, requiring instances to have different
        // selectors in order to render new instances properly
        scope.$on('$tinymce:refresh', function(e, id) {
          var eid = attrs.id;
          if (angular.isUndefined(id) || id === eid) {
            var parentElement = element.parent();
            var clonedElement = element.clone();
            clonedElement.removeAttr('id');
            clonedElement.removeAttr('style');
            clonedElement.removeAttr('aria-hidden');
            tinymce.execCommand('mceRemoveEditor', false, eid);
            parentElement.append($compile(clonedElement)(scope));
          }
        });

        scope.$on('$destroy', function() {
          ensureInstance();

          if (tinyInstance) {
            tinyInstance.remove();
            tinyInstance = null;
          }
        });

        function ensureInstance() {
          if (!tinyInstance) {
            tinyInstance = tinymce.get(attrs.id);
          }
        }
      }
    };
  }]);
<commit_msg>Updating model on paste<commit_after>/**
 * Binds a TinyMCE widget to <textarea> elements.
 */
angular.module('ui.tinymce', [])
  .value('uiTinymceConfig', {})
  .directive('uiTinymce', ['$rootScope', '$compile', '$timeout', '$window', '$sce', 'uiTinymceConfig', function($rootScope, $compile, $timeout, $window, $sce, uiTinymceConfig) {
    uiTinymceConfig = uiTinymceConfig || {};
    var generatedIds = 0;
    var ID_ATTR = 'ui-tinymce';
    if (uiTinymceConfig.baseUrl) {
      tinymce.baseURL = uiTinymceConfig.baseUrl;
    }

    return {
      require: ['ngModel', '^?form'],
      link: function(scope, element, attrs, ctrls) {
        if (!$window.tinymce) {
          return;
        }

        var ngModel = ctrls[0],
          form = ctrls[1] || null;

        var expression, options, tinyInstance,
          updateView = function(editor) {
            var content = editor.getContent({format: options.format}).trim();
            content = $sce.trustAsHtml(content);

            ngModel.$setViewValue(content);
            if (!$rootScope.$$phase) {
              scope.$apply();
            }
          };

        function toggleDisable(disabled) {
          if (disabled) {
            ensureInstance();

            if (tinyInstance) {
              tinyInstance.getBody().setAttribute('contenteditable', false);
            }
          } else {
            ensureInstance();

            if (tinyInstance) {
              tinyInstance.getBody().setAttribute('contenteditable', true);
            }
          }
        }

        // generate an ID
        attrs.$set('id', ID_ATTR + '-' + generatedIds++);

        expression = {};

        angular.extend(expression, scope.$eval(attrs.uiTinymce));

        options = {
          // Update model when calling setContent
          // (such as from the source editor popup)
          setup: function(ed) {
            ed.on('init', function() {
              ngModel.$render();
              ngModel.$setPristine();
              if (form) {
                form.$setPristine();
              }
            });

            // Update model on button click
            ed.on('ExecCommand', function() {
              ed.save();
              updateView(ed);
            });

            // Update model on change
            ed.on('change', function(e) {
              ed.save();
              updateView(ed);
            });

            // Update model on paste
            ed.on('paste', function(e) {
              $timeout(function() {
                updateView(ed);
                ed.save();
              });
            });

            ed.on('blur', function() {
              element[0].blur();
            });

            // Update model when an object has been resized (table, image)
            ed.on('ObjectResized', function() {
              ed.save();
              updateView(ed);
            });

            ed.on('remove', function() {
              element.remove();
            });

            if (expression.setup) {
              expression.setup(ed, {
                updateView: updateView
              });
            }
          },
          format: 'raw',
          selector: '#' + attrs.id
        };
        // extend options with initial uiTinymceConfig and
        // options from directive attribute value
        angular.extend(options, uiTinymceConfig, expression);
        // Wrapped in $timeout due to $tinymce:refresh implementation, requires
        // element to be present in DOM before instantiating editor when
        // re-rendering directive
        $timeout(function() {
          tinymce.init(options);
          toggleDisable(scope.$eval(attrs.ngDisabled));
        });

        ngModel.$formatters.unshift(function(modelValue) {
          return modelValue ? $sce.trustAsHtml(modelValue) : '';
        });

        ngModel.$parsers.unshift(function(viewValue) {
          return viewValue ? $sce.getTrustedHtml(viewValue) : '';
        });

        ngModel.$render = function() {
          ensureInstance();

          var viewValue = ngModel.$viewValue ?
            $sce.getTrustedHtml(ngModel.$viewValue) : '';

          // instance.getDoc() check is a guard against null value
          // when destruction & recreation of instances happen
          if (tinyInstance &&
            tinyInstance.getDoc()
          ) {
            tinyInstance.setContent(viewValue);
            // Triggering change event due to TinyMCE not firing event &
            // becoming out of sync for change callbacks
            tinyInstance.fire('change');
          }
        };

        attrs.$observe('disabled', toggleDisable);

        // This block is because of TinyMCE not playing well with removal and
        // recreation of instances, requiring instances to have different
        // selectors in order to render new instances properly
        scope.$on('$tinymce:refresh', function(e, id) {
          var eid = attrs.id;
          if (angular.isUndefined(id) || id === eid) {
            var parentElement = element.parent();
            var clonedElement = element.clone();
            clonedElement.removeAttr('id');
            clonedElement.removeAttr('style');
            clonedElement.removeAttr('aria-hidden');
            tinymce.execCommand('mceRemoveEditor', false, eid);
            parentElement.append($compile(clonedElement)(scope));
          }
        });

        scope.$on('$destroy', function() {
          ensureInstance();

          if (tinyInstance) {
            tinyInstance.remove();
            tinyInstance = null;
          }
        });

        function ensureInstance() {
          if (!tinyInstance) {
            tinyInstance = tinymce.get(attrs.id);
          }
        }
      }
    };
  }]);
<|endoftext|>