<commit_before>import { keys, isUndefined, isArray, isString } from 'underscore';
import Property from './PropertyComposite';
import PropertyBase from './Property';
import Layers from './Layers';
import { camelCase } from 'utils/mixins';

const VALUES_REG = /,(?![^\(]*\))/;
const PARTS_REG = /\s(?![^(]*\))/;

const splitStyleName = (style, name, sep) => {
  return (style[name] || '')
    .split(sep)
    .map(value => value.trim())
    .filter(Boolean);
};

export default Property.extend({
  defaults: {
    ...Property.prototype.defaults,
    // Array of layers (which contain properties)
    layers: [],

    // The separator used to split layer values
    layerSeparator: ', ',

    // The separator used to join layer values
    layerJoin: ', ',

    // Prepend new layers in the list
    prepend: 0,

    // Layer preview
    preview: 0,

    // Parse single layer value string
    parseLayer: null,

    // Current selected layer
    selectedLayer: null,
  },

  initialize(props = {}, opts = {}) {
    Property.callParentInit(Property, this, props, opts);
    const layers = this.get('layers');
    const layersColl = new Layers(layers);
    layersColl.property = this;
    layersColl.properties = this.get('properties');
    this.set('layers', layersColl, { silent: true });
    this.on('change:selectedLayer', this.__upSelected);
    this.listenTo(layersColl, 'add remove', this.__upLayers);
    Property.callInit(this, props, opts);
  },

  __upProperties(prop, opts = {}) {
    const layer = this.getSelectedLayer();
    if (opts.__up || !layer) return;
    const name = prop.getName();
    layer.upValues({ [name]: prop.__getFullValue() });
    const value = this.__getFullValue();
    this.upValue(value, opts);
    this.__upTargetsStyleProps(opts);
  },

  __upLayers(m, c, o) {
    this.__upTargetsStyleProps(o || c);
  },

  __upTargets(p, opts = {}) {
    if (opts.__select) return;
    return PropertyBase.prototype.__upTargets.call(this, p, opts);
  },

  __upTargetsStyleProps(opts = {}) {
    this.__upTargetsStyle(this.getStyleFromLayers(), opts);
  },

  __upTargetsStyle(style, opts) {
    return PropertyBase.prototype.__upTargetsStyle.call(this, style, opts);
  },

  __upSelected({ noEvent } = {}, opts = {}) {
    if (!this.__hasCustom()) return;
    const sm = this.em.get('StyleManager');
    const selected = this.getSelectedLayer();
    const values = selected?.getValues();

    // Update properties by layer value
    values &&
      this.getProperties().forEach(prop => {
        const name = prop.getName();
        const value = values[name];
        !isUndefined(value) && prop.upValue(value, { ...opts, __up: true });
      });

    !noEvent && sm.__trgEv(sm.events.layerSelect, { property: this });
  },

  _up(props, opts = {}) {
    const { __layers = [], ...rest } = props;
    this.__setLayers(__layers);
    this.__upSelected({ noEvent: true }, opts);
    return Property.prototype._up.call(this, rest, opts);
  },

  __setLayers(newLayers = []) {
    const layers = this.getLayers();
    const layersNew = newLayers.map(values => ({ values }));

    if (layers.length === layersNew.length) {
      layersNew.map((layer, n) => layers.at(n)?.upValues(layer.values));
    } else {
      this.getLayers().reset(layersNew);
    }
  },

  __parseValue(value) {
    const result = this.parseValue(value);
    result.__layers = value
      .split(VALUES_REG)
      .map(v => v.trim())
      .map(v => this.__parseLayer(v))
      .filter(Boolean);

    return result;
  },

  __parseLayer(value) {
    const parseFn = this.get('parseLayer');
    const values = value.split(PARTS_REG);
    const properties = this.getProperties();
    return parseFn
      ? parseFn({ value, values })
      : properties.reduce((acc, prop, i) => {
          const value = values[i];
          acc[prop.getId()] = !isUndefined(value) ? value : prop.getDefaultValue();
          return acc;
        }, {});
  },

  __getFromStyle(style = {}) {
    const fromStyle = this.get('fromStyle');

    return fromStyle ? fromStyle(style) : style;
  },

  __getLayersFromStyle(style = {}) {
    const name = this.getName();
    const props = this.getProperties();
    const nameProps = props.map(prop => prop.getName());
    const allNameProps = [name, ...nameProps];
    const hasProps = allNameProps.some(prop => !isUndefined(style[prop]));

    if (!hasProps) {
      return [];
    } else {
      const sep = this.getLayerSeparator();
      const fromStyle = this.get('fromStyle');
      let result = fromStyle ? fromStyle(style, { property: this, separatorLayers: sep }) : [];

      if (!fromStyle) {
        // Get layers from the main property
        const layers = splitStyleName(style, name, sep)
          .map(value => value.split(this.getSplitSeparator()))
          .map(parts => {
            const result = {};
            props.forEach((prop, i) => {
              const value = parts[i];
              result[prop.getId()] = !isUndefined(value) ? value : prop.getDefaultValue();
            });
            return result;
          });
        // Get layers from the inner properties
        props.forEach(prop => {
          const id = prop.getId();
          splitStyleName(style, prop.getName(), sep)
            .map(value => ({ [id]: value || prop.getDefaultValue() }))
            .forEach((inLayer, i) => {
              layers[i] = layers[i] ? { ...layers[i], ...inLayer } : inLayer;
            });
        });
        result = layers;
      }

      return isArray(result) ? result : [result];
    }
  },

  hasValue(opts) {
    return PropertyBase.prototype.hasValue.call(this, opts);
  },

  /**
   * Add new layer to the stack
   * @param {Object} [props={}] Layer props
   * @param {Object} [opts={}] Options
   * @returns {[Layer]}
   */
  addLayer(props = {}, opts = {}) {
    const values = {};
    this.getProperties().forEach(prop => {
      const name = prop.getName();
      const value = props[name];
      values[name] = isUndefined(value) ? prop.getDefaultValue() : value;
    });
    const layer = this.get('layers').push({ values }, opts);

    return layer;
  },

  /**
   * Remove layer
   * @param {[Layer]} layer
   * @returns {[Layer]} Removed layer
   */
  removeLayer(layer) {
    return this.get('layers').remove(layer);
  },

  /**
   * Remove layer at index
   * @param {Number} index Index of the layer to remove
   * @returns {[Layer] | null} Removed layer
   */
  removeLayerAt(index = 0) {
    const layer = this.getLayer(index);
    return layer ? this.removeLayer(layer) : null;
  },

  /**
   * Select layer
   * @param {[Layer]} layer
   */
  selectLayer(layer) {
    return this.set('selectedLayer', layer, { __select: true });
  },

  /**
   * Select layer at index
   * @param {Number} index Index of the layer to select
   */
  selectLayerAt(index = 0) {
    const layer = this.getLayer(index);
    return layer && this.selectLayer(layer);
  },

  /**
   * Get selected layer
   * @returns {[Layer] | null}
   */
  getSelectedLayer() {
    const layer = this.get('selectedLayer');
    return layer && layer.getIndex() >= 0 ? layer : null;
  },

  /**
   * Get style object from layer
   * @param {[Layer]} layer
   * @returns {Object} Style object
   */
  getStyleFromLayer(layer, opts = {}) {
    const join = this.__getJoin();
    const joinLayers = this.__getJoinLayers();
    const toStyle = this.get('toStyle');
    const name = this.getName();
    const values = layer.getValues();
    let style;

    if (toStyle) {
      style = toStyle(values, { join, joinLayers, name, property: this });
    } else {
      const result = this.getProperties().map(prop => {
        const name = prop.getName();
        const val = values[name];
        const value = isUndefined(val) ? prop.getDefaultValue() : val;
        return { name, value };
      });
      style = this.get('detached')
        ? result.reduce((acc, item) => {
            acc[item.name] = item.value;
            return acc;
          }, {})
        : {
            [this.getName()]: result.map(r => r.value).join(join),
          };
    }

    return opts.camelCase
      ? Object.keys(style).reduce((res, key) => {
          res[camelCase(key)] = style[key];
          return res;
        }, {})
      : style;
  },

  /**
   * Get style object from current layers
   * @returns {Object} Style object
   */
  getStyleFromLayers() {
    let result = {};
    const layers = this.getLayers();
    const styles = layers.map(l => this.getStyleFromLayer(l));
    styles.forEach(style => {
      keys(style).map(key => {
        if (!result[key]) result[key] = [];
        result[key].push(style[key]);
      });
    });
    keys(result).map(key => {
      result[key] = result[key].join(this.__getJoinLayers());
    });

    if (this.isDetached()) {
      result[this.getName()] = '';
    } else {
      const style = this.getProperties().reduce((acc, prop) => {
        acc[prop.getName()] = '';
        return acc;
      }, {});
      result = { ...result, ...style };
    }

    return result;
  },

  __getJoinLayers() {
    return this.get('layerJoin');
  },

  __getFullValue() {
    if (this.get('detached')) return '';
    const name = this.getName();

    return this.getLayers()
      .map(l => this.getStyleFromLayer(l))
      .map(s => s[name])
      .filter(Boolean)
      .map(v => v?.trim())
      .join(this.get('layerSeparator'));
  },

  /**
   * Get layer sperator
   * @return {RegExp}
   */
  getLayerSeparator() {
    const sep = this.get('layerSeparator');
    return isString(sep) ? new RegExp(`${sep}(?![^\\(]*\\))`) : sep;
  },

  getLayers() {
    return this.get('layers');
  },

  getLayer(index = 0) {
    return this.getLayers().at(index) || null;
  },

  getCurrentLayer() {
    return this.getLayers().filter(layer => layer.get('active'))[0];
  },

  getFullValue() {
    return this.get('detached') ? '' : this.get('layers').getFullValue();
  },

  getValueFromStyle(styles = {}) {
    const layers = this.getLayers().getLayersFromStyle(styles);
    return new Layers(layers).getFullValue();
  },

  clearValue() {
    this.getLayers().reset();
    return Property.prototype.clearValue.apply(this, arguments);
  },

  getValueFromTarget(target) {
    const { detached, property, properties } = this.attributes;
    const style = target.getStyle();
    const validStyles = {};

    properties.forEach(prop => {
      const name = prop.get('property');
      const value = style[name];
      if (value) validStyles[name] = value;
    });

    return !detached ? style[property] : keys(validStyles).length ? validStyles : '';
  },

  /**
   * This method allows to customize layers returned from the target
   * @param  {Object} target
   * @return {Array} Should return an array of layers
   * @example
   * // return example
   * [
   *  {
   *    properties: [
   *      { property: 'width', ... }
   *      { property: 'height', ... }
   *    ]
   *  }
   * ]
   */
  getLayersFromTarget(target) {
    return;
  },
});
<commit_msg>Update __getFullValue in stack<commit_after>import { keys, isUndefined, isArray, isString } from 'underscore';
import Property from './PropertyComposite';
import PropertyBase from './Property';
import Layers from './Layers';
import { camelCase } from 'utils/mixins';

const VALUES_REG = /,(?![^\(]*\))/;
const PARTS_REG = /\s(?![^(]*\))/;

const splitStyleName = (style, name, sep) => {
  return (style[name] || '')
    .split(sep)
    .map(value => value.trim())
    .filter(Boolean);
};

export default Property.extend({
  defaults: {
    ...Property.prototype.defaults,
    // Array of layers (which contain properties)
    layers: [],

    // The separator used to split layer values
    layerSeparator: ', ',

    // The separator used to join layer values
    layerJoin: ', ',

    // Prepend new layers in the list
    prepend: 0,

    // Layer preview
    preview: 0,

    // Parse single layer value string
    parseLayer: null,

    // Current selected layer
    selectedLayer: null,
  },

  initialize(props = {}, opts = {}) {
    Property.callParentInit(Property, this, props, opts);
    const layers = this.get('layers');
    const layersColl = new Layers(layers);
    layersColl.property = this;
    layersColl.properties = this.get('properties');
    this.set('layers', layersColl, { silent: true });
    this.on('change:selectedLayer', this.__upSelected);
    this.listenTo(layersColl, 'add remove', this.__upLayers);
    Property.callInit(this, props, opts);
  },

  __upProperties(prop, opts = {}) {
    const layer = this.getSelectedLayer();
    if (opts.__up || !layer) return;
    const name = prop.getName();
    layer.upValues({ [name]: prop.__getFullValue() });
    // const value = this.__getFullValue();
    // this.upValue(value, opts);
    this.__upTargetsStyleProps(opts);
  },

  __upLayers(m, c, o) {
    this.__upTargetsStyleProps(o || c);
  },

  __upTargets(p, opts = {}) {
    if (opts.__select) return;
    return PropertyBase.prototype.__upTargets.call(this, p, opts);
  },

  __upTargetsStyleProps(opts = {}) {
    this.__upTargetsStyle(this.getStyleFromLayers(), opts);
  },

  __upTargetsStyle(style, opts) {
    return PropertyBase.prototype.__upTargetsStyle.call(this, style, opts);
  },

  __upSelected({ noEvent } = {}, opts = {}) {
    if (!this.__hasCustom()) return;
    const sm = this.em.get('StyleManager');
    const selected = this.getSelectedLayer();
    const values = selected?.getValues();

    // Update properties by layer value
    values &&
      this.getProperties().forEach(prop => {
        const name = prop.getName();
        const value = values[name];
        !isUndefined(value) && prop.upValue(value, { ...opts, __up: true });
      });

    !noEvent && sm.__trgEv(sm.events.layerSelect, { property: this });
  },

  _up(props, opts = {}) {
    const { __layers = [], ...rest } = props;
    this.__setLayers(__layers);
    this.__upSelected({ noEvent: true }, opts);
    return Property.prototype._up.call(this, rest, opts);
  },

  __setLayers(newLayers = []) {
    const layers = this.getLayers();
    const layersNew = newLayers.map(values => ({ values }));

    if (layers.length === layersNew.length) {
      layersNew.map((layer, n) => layers.at(n)?.upValues(layer.values));
    } else {
      this.getLayers().reset(layersNew);
    }
  },

  __parseValue(value) {
    const result = this.parseValue(value);
    result.__layers = value
      .split(VALUES_REG)
      .map(v => v.trim())
      .map(v => this.__parseLayer(v))
      .filter(Boolean);

    return result;
  },

  __parseLayer(value) {
    const parseFn = this.get('parseLayer');
    const values = value.split(PARTS_REG);
    const properties = this.getProperties();
    return parseFn
      ? parseFn({ value, values })
      : properties.reduce((acc, prop, i) => {
          const value = values[i];
          acc[prop.getId()] = !isUndefined(value) ? value : prop.getDefaultValue();
          return acc;
        }, {});
  },

  __getFromStyle(style = {}) {
    const fromStyle = this.get('fromStyle');

    return fromStyle ? fromStyle(style) : style;
  },

  __getLayersFromStyle(style = {}) {
    const name = this.getName();
    const props = this.getProperties();
    const nameProps = props.map(prop => prop.getName());
    const allNameProps = [name, ...nameProps];
    const hasProps = allNameProps.some(prop => !isUndefined(style[prop]));

    if (!hasProps) {
      return [];
    } else {
      const sep = this.getLayerSeparator();
      const fromStyle = this.get('fromStyle');
      let result = fromStyle ? fromStyle(style, { property: this, separatorLayers: sep }) : [];

      if (!fromStyle) {
        // Get layers from the main property
        const layers = splitStyleName(style, name, sep)
          .map(value => value.split(this.getSplitSeparator()))
          .map(parts => {
            const result = {};
            props.forEach((prop, i) => {
              const value = parts[i];
              result[prop.getId()] = !isUndefined(value) ? value : prop.getDefaultValue();
            });
            return result;
          });
        // Get layers from the inner properties
        props.forEach(prop => {
          const id = prop.getId();
          splitStyleName(style, prop.getName(), sep)
            .map(value => ({ [id]: value || prop.getDefaultValue() }))
            .forEach((inLayer, i) => {
              layers[i] = layers[i] ? { ...layers[i], ...inLayer } : inLayer;
            });
        });
        result = layers;
      }

      return isArray(result) ? result : [result];
    }
  },

  hasValue(opts) {
    return PropertyBase.prototype.hasValue.call(this, opts);
  },

  /**
   * Add new layer to the stack
   * @param {Object} [props={}] Layer props
   * @param {Object} [opts={}] Options
   * @returns {[Layer]}
   */
  addLayer(props = {}, opts = {}) {
    const values = {};
    this.getProperties().forEach(prop => {
      const name = prop.getName();
      const value = props[name];
      values[name] = isUndefined(value) ? prop.getDefaultValue() : value;
    });
    const layer = this.get('layers').push({ values }, opts);

    return layer;
  },

  /**
   * Remove layer
   * @param {[Layer]} layer
   * @returns {[Layer]} Removed layer
   */
  removeLayer(layer) {
    return this.get('layers').remove(layer);
  },

  /**
   * Remove layer at index
   * @param {Number} index Index of the layer to remove
   * @returns {[Layer] | null} Removed layer
   */
  removeLayerAt(index = 0) {
    const layer = this.getLayer(index);
    return layer ? this.removeLayer(layer) : null;
  },

  /**
   * Select layer
   * @param {[Layer]} layer
   */
  selectLayer(layer) {
    return this.set('selectedLayer', layer, { __select: true });
  },

  /**
   * Select layer at index
   * @param {Number} index Index of the layer to select
   */
  selectLayerAt(index = 0) {
    const layer = this.getLayer(index);
    return layer && this.selectLayer(layer);
  },

  /**
   * Get selected layer
   * @returns {[Layer] | null}
   */
  getSelectedLayer() {
    const layer = this.get('selectedLayer');
    return layer && layer.getIndex() >= 0 ? layer : null;
  },

  /**
   * Get style object from layer
   * @param {[Layer]} layer
   * @returns {Object} Style object
   */
  getStyleFromLayer(layer, opts = {}) {
    const join = this.__getJoin();
    const joinLayers = this.__getJoinLayers();
    const toStyle = this.get('toStyle');
    const name = this.getName();
    const values = layer.getValues();
    let style;

    if (toStyle) {
      style = toStyle(values, { join, joinLayers, name, property: this });
    } else {
      const result = this.getProperties().map(prop => {
        const name = prop.getName();
        const val = values[name];
        const value = isUndefined(val) ? prop.getDefaultValue() : val;
        return { name, value };
      });
      style = this.get('detached')
        ? result.reduce((acc, item) => {
            acc[item.name] = item.value;
            return acc;
          }, {})
        : {
            [this.getName()]: result.map(r => r.value).join(join),
          };
    }

    return opts.camelCase
      ? Object.keys(style).reduce((res, key) => {
          res[camelCase(key)] = style[key];
          return res;
        }, {})
      : style;
  },

  /**
   * Get style object from current layers
   * @returns {Object} Style object
   */
  getStyleFromLayers() {
    let result = {};
    const layers = this.getLayers();
    const styles = layers.map(l => this.getStyleFromLayer(l));
    styles.forEach(style => {
      keys(style).map(key => {
        if (!result[key]) result[key] = [];
        result[key].push(style[key]);
      });
    });
    keys(result).map(key => {
      result[key] = result[key].join(this.__getJoinLayers());
    });

    if (this.isDetached()) {
      result[this.getName()] = '';
    } else {
      const style = this.getProperties().reduce((acc, prop) => {
        acc[prop.getName()] = '';
        return acc;
      }, {});
      result = { ...result, ...style };
    }

    return result;
  },

  __getJoinLayers() {
    return this.get('layerJoin');
  },

  __getFullValue() {
    if (this.get('detached')) return '';
    const style = this.getStyleFromLayers();

    return style[this.getName()];
  },

  /**
   * Get layer sperator
   * @return {RegExp}
   */
  getLayerSeparator() {
    const sep = this.get('layerSeparator');
    return isString(sep) ? new RegExp(`${sep}(?![^\\(]*\\))`) : sep;
  },

  getLayers() {
    return this.get('layers');
  },

  getLayer(index = 0) {
    return this.getLayers().at(index) || null;
  },

  getCurrentLayer() {
    return this.getLayers().filter(layer => layer.get('active'))[0];
  },

  getFullValue() {
    return this.get('detached') ? '' : this.get('layers').getFullValue();
  },

  getValueFromStyle(styles = {}) {
    const layers = this.getLayers().getLayersFromStyle(styles);
    return new Layers(layers).getFullValue();
  },

  clearValue() {
    this.getLayers().reset();
    return Property.prototype.clearValue.apply(this, arguments);
  },

  getValueFromTarget(target) {
    const { detached, property, properties } = this.attributes;
    const style = target.getStyle();
    const validStyles = {};

    properties.forEach(prop => {
      const name = prop.get('property');
      const value = style[name];
      if (value) validStyles[name] = value;
    });

    return !detached ? style[property] : keys(validStyles).length ? validStyles : '';
  },

  /**
   * This method allows to customize layers returned from the target
   * @param  {Object} target
   * @return {Array} Should return an array of layers
   * @example
   * // return example
   * [
   *  {
   *    properties: [
   *      { property: 'width', ... }
   *      { property: 'height', ... }
   *    ]
   *  }
   * ]
   */
  getLayersFromTarget(target) {
    return;
  },
});
<|endoftext|>


<commit_before>/*
 * This file is part of the WordPress Standard project.
 *
 * Copyright (c) 2015-2016 LIN3S <info@lin3s.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @author Gorka Laucirica <gorka.lauzirika@gmail.com>
 * @author Beñat Espiña <benatespina@gmail.com>
 * @author Jon Torrado <jontorrado@gmail.com>
 */

'use strict';

var gulp = require('gulp'),
  concat = require('gulp-concat'),
  cssnext = require('postcss-cssnext'),
  cssnano = require('gulp-cssnano'),
  file = require('gulp-file'),
  livereload = require('gulp-livereload'),
  modernizr = require('gulp-modernizr'),
  plumber = require('gulp-plumber'),
  postcss = require('gulp-postcss'),
  rename = require('gulp-rename'),
  sass = require('gulp-sass'),
  scsslint = require('gulp-scss-lint'),
  svgSprite = require('gulp-svg-sprite'),
  uglify = require('gulp-uglify');

var paths = {
  npm: './node_modules',
  assets: './Resources/assets',
  sass: './Resources/assets/scss',
  js: './Resources/assets/js',
  css: './Resources/build/css',
  buildJs: './Resources/build/js',
  svg: './Resources/assets/svg',
  buildSvg: './Resources/build/svg'
};

var watch = {
  sass: './Resources/assets/scss/**/*.scss',
  svg: './Resources/assets/svg/**/*.svg'
};

// Plumber error function
function onError(err) {
  console.log(err);
  this.emit('end');
}

gulp.task('wp-style', function () {
  var content = '/*\nTheme Name: WordPress Standard';
  content += '\nAuthor: LIN3S';
  content += '\nAuthor URI: http://www.lin3s.com/\n*/';

  return file('style.css', content, {src: true}).pipe(gulp.dest('.'));
});

gulp.task('scss-lint', function () {
  return gulp.src([
      watch.sass,
      '!' + paths.sass + '/base/_reset.scss',
      '!' + paths.sass + '/base/_grid.scss'
    ])
    .pipe(plumber({
      errorHandler: onError
    }))
    .pipe(scsslint({
      'config': './.scss_lint.yml'
    }));
});

gulp.task('sass', ['wp-style', 'scss-lint'], function () {
  return gulp.src(paths.sass + '/app.scss')
    .pipe(plumber({
      errorHandler: onError
    }))
    .pipe(sass({
      errLogToConsole: true
    }))
    .pipe(postcss([cssnext]))
    .pipe(gulp.dest(paths.css))
    .pipe(livereload());
});

gulp.task('sass:prod', function () {
  return gulp.src([
      paths.sass + '/app.scss'
      // Put here css/scss vendor files, for example:
      // paths.npm + '/slick-carousel/slick/slick.scss'
    ])
    .pipe(plumber({
      errorHandler: onError
    }))
    .pipe(sass())
    .pipe(postcss([cssnext]))
    .pipe(cssnano({
      keepSpecialComments: 1,
      rebase: false
    }))
    .pipe(rename({
      suffix: '.min'
    }))
    .pipe(gulp.dest(paths.css));
});

gulp.task('sprites', function () {
  return gulp.src(paths.svg + '/*.svg')
    .pipe(plumber({
      errorHandler: onError
    }))
    .pipe(svgSprite({
      mode: {
        symbol: {
          dest: '',
          sprite: 'symbols',
          example: {dest: 'symbols'}
        }
      }
    }))
    .pipe(gulp.dest(paths.buildSvg));
});

gulp.task('modernizr', function () {
  return gulp.src([paths.js + '/*.js'])
    .pipe(plumber({
      errorHandler: onError
    }))
    .pipe(modernizr({
      'options': [
        'setClasses', 'addTest', 'html5printshiv', 'testProp', 'fnBind'
      ],
      'tests': ['objectfit', 'flexbox']
    }))
    .pipe(gulp.dest(paths.buildJs))
});

gulp.task('js:prod', ['modernizr'], function () {
  return gulp.src([
      paths.buildJs + '/modernizr.js',
      paths.npm + '/fastclick/lib/fastclick.js',
      paths.npm + '/svg4everybody/dist/svg4everybody.min.js',
      // Put here js vendor files, for example:
      // paths.npm + '/slick-carousel/slick/slick.min.js'
      paths.js + '/*.js'
    ])
    .pipe(plumber({
      errorHandler: onError
    }))
    .pipe(concat('app.min.js'))
    .pipe(uglify())
    .pipe(gulp.dest(paths.buildJs));
});

gulp.task('watch', function () {
  livereload.listen();
  gulp.watch(watch.sass, ['sass']);
  gulp.watch(watch.svg, ['sprites']);
});

gulp.task('default', ['sass', 'sprites', 'modernizr']);

gulp.task('prod', ['sass:prod', 'sprites', 'modernizr', 'js:prod']);
<commit_msg>Fixed gulpfile sass:prod minification<commit_after>/*
 * This file is part of the WordPress Standard project.
 *
 * Copyright (c) 2015-2016 LIN3S <info@lin3s.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @author Gorka Laucirica <gorka.lauzirika@gmail.com>
 * @author Beñat Espiña <benatespina@gmail.com>
 * @author Jon Torrado <jontorrado@gmail.com>
 */

'use strict';

var gulp = require('gulp'),
  concat = require('gulp-concat'),
  cssnext = require('postcss-cssnext'),
  cssnano = require('gulp-cssnano'),
  file = require('gulp-file'),
  livereload = require('gulp-livereload'),
  modernizr = require('gulp-modernizr'),
  plumber = require('gulp-plumber'),
  postcss = require('gulp-postcss'),
  rename = require('gulp-rename'),
  sass = require('gulp-sass'),
  scsslint = require('gulp-scss-lint'),
  svgSprite = require('gulp-svg-sprite'),
  uglify = require('gulp-uglify');

var paths = {
  npm: './node_modules',
  assets: './Resources/assets',
  sass: './Resources/assets/scss',
  js: './Resources/assets/js',
  css: './Resources/build/css',
  buildJs: './Resources/build/js',
  svg: './Resources/assets/svg',
  buildSvg: './Resources/build/svg'
};

var watch = {
  sass: './Resources/assets/scss/**/*.scss',
  svg: './Resources/assets/svg/**/*.svg'
};

// Plumber error function
function onError(err) {
  console.log(err);
  this.emit('end');
}

gulp.task('wp-style', function () {
  var content = '/*\nTheme Name: WordPress Standard';
  content += '\nAuthor: LIN3S';
  content += '\nAuthor URI: http://www.lin3s.com/\n*/';

  return file('style.css', content, {src: true}).pipe(gulp.dest('.'));
});

gulp.task('scss-lint', function () {
  return gulp.src([
      watch.sass,
      '!' + paths.sass + '/base/_reset.scss',
      '!' + paths.sass + '/base/_grid.scss'
    ])
    .pipe(plumber({
      errorHandler: onError
    }))
    .pipe(scsslint({
      'config': './.scss_lint.yml'
    }));
});

gulp.task('sass', ['wp-style', 'scss-lint'], function () {
  return gulp.src(paths.sass + '/app.scss')
    .pipe(plumber({
      errorHandler: onError
    }))
    .pipe(sass({
      errLogToConsole: true
    }))
    .pipe(postcss([cssnext]))
    .pipe(gulp.dest(paths.css))
    .pipe(livereload());
});

gulp.task('sass:prod', function () {
  // Import your css/scss vendor files in app.scss. Example:
  // @import '../../../node_modules/slick-carousel/slick/slick.scss'
  return gulp.src(paths.sass + '/app.scss')
    .pipe(plumber({
      errorHandler: onError
    }))
    .pipe(sass())
    .pipe(postcss([cssnext]))
    .pipe(cssnano({
      keepSpecialComments: 1,
      rebase: false
    }))
    .pipe(rename({
      suffix: '.min'
    }))
    .pipe(gulp.dest(paths.css));
});

gulp.task('sprites', function () {
  return gulp.src(paths.svg + '/*.svg')
    .pipe(plumber({
      errorHandler: onError
    }))
    .pipe(svgSprite({
      mode: {
        symbol: {
          dest: '',
          sprite: 'symbols',
          example: {dest: 'symbols'}
        }
      }
    }))
    .pipe(gulp.dest(paths.buildSvg));
});

gulp.task('modernizr', function () {
  return gulp.src([paths.js + '/*.js'])
    .pipe(plumber({
      errorHandler: onError
    }))
    .pipe(modernizr({
      'options': [
        'setClasses', 'addTest', 'html5printshiv', 'testProp', 'fnBind'
      ],
      'tests': ['objectfit', 'flexbox']
    }))
    .pipe(gulp.dest(paths.buildJs))
});

gulp.task('js:prod', ['modernizr'], function () {
  return gulp.src([
      paths.buildJs + '/modernizr.js',
      paths.npm + '/fastclick/lib/fastclick.js',
      paths.npm + '/svg4everybody/dist/svg4everybody.min.js',
      // Put here js vendor files, for example:
      // paths.npm + '/slick-carousel/slick/slick.min.js'
      paths.js + '/*.js'
    ])
    .pipe(plumber({
      errorHandler: onError
    }))
    .pipe(concat('app.min.js'))
    .pipe(uglify())
    .pipe(gulp.dest(paths.buildJs));
});

gulp.task('watch', function () {
  livereload.listen();
  gulp.watch(watch.sass, ['sass']);
  gulp.watch(watch.svg, ['sprites']);
});

gulp.task('default', ['sass', 'sprites', 'modernizr']);

gulp.task('prod', ['sass:prod', 'sprites', 'modernizr', 'js:prod']);
<|endoftext|>


<commit_before>// third party imports
import MediaQuery from 'mediaquery'
import transform from 'lodash/object/transform'
import reduce from 'lodash/collection/reduce'
// local imports
import CALCULATE_RESPONSIVE_STATE from '../actions/types/CALCULATE_RESPONSIVE_STATE'

// default breakpoints
const defaultBreakpoints = {
    extraSmall: 480,
    small: 768,
    medium: 992,
    large: 1200,
}
// media type to default to when no `window` present
const defaultMediaType = 'infinity'

/**
 * Compute the `lessThan` object based on the browser width.
 * @arg {number} browserWidth - Width of the browser.
 * @arg {object} breakpoints - The breakpoints object.
 * @returns {object} The `lessThan` object.  Its keys are the same as the
 * keys of the breakpoints object.  The value for each key indicates whether
 * or not the browser width is less than the breakpoint.
 */
function getLessThan(browserWidth, breakpoints) {
    return transform(breakpoints, (result, breakpoint, mediaType) => {
        // if the breakpoint is a number
        if (typeof breakpoint === 'number') {
            // store wether or not it is less than the breakpoint
            result[mediaType] = browserWidth < breakpoint
        } else {
            result[mediaType] = false
        }
    })
}

/**
 * Compute the `greaterThan` object based on the browser width.
 * @arg {number} browserWidth - Width of the browser.
 * @arg {object} breakpoints - The breakpoints object.
 * @returns {object} The `greaterThan` object.  Its keys are the same as the
 * keys of the breakpoints object.  The value for each key indicates whether
 * or not the browser width is greater than the breakpoint.
 */
function getGreaterThan(browserWidth, breakpoints) {
    return transform(breakpoints, (result, breakpoint, mediaType) => {
        // if the breakpoint is a number
        if (typeof breakpoint === 'number') {
            // store wether or not it is greater than the breakpoint
            result[mediaType] = browserWidth > breakpoint
        } else {
            result[mediaType] = false
        }
    })
}

/**
 * Gets the current media type from the global `window`.
 * @arg {object} mediaQueries - The media queries object.
 * @returns {string} The window's current media type.  This is the key of the
 * breakpoint that is the next breakpoint larger than the window.
 */
function getMediaType(matchMedia, mediaQueries) {
    // if there's no window
    if (typeof matchMedia === 'undefined') {
        // return the default
        return defaultMediaType
    }

    // there is a window, so compute the true media type
    return reduce(mediaQueries, (result, query, type) => {
        // return the new type if the query matches otherwise the previous one
        return matchMedia(query).matches ? type : result
    // use the default media type
    }, defaultMediaType)
}

// export the reducer factory
export default (breakpoints = defaultBreakpoints) => {
    // add `infinity` breakpoint for upper bound
    breakpoints[defaultMediaType] = Infinity
    // media queries associated with the breakpoints
    const mediaQueries = MediaQuery.asObject(breakpoints)

    // return reducer for handling the responsive state
    return (state, action) => {
        // if told to recalculate state or state has not yet been initialized
        if (action.type === CALCULATE_RESPONSIVE_STATE || typeof state === 'undefined') {
            // return calculated state
            return {
                width: action.innerWidth,
                lessThan: getLessThan(action.innerWidth, breakpoints),
                greaterThan: getGreaterThan(action.innerWidth, breakpoints),
                mediaType: getMediaType(action.matchMedia, mediaQueries),
            }
        }
        // otherwise return the previous state
        return state
    }
}
<commit_msg>less than calculation in reducer now ignores the current media type. Fixes #5<commit_after>// third party imports
import MediaQuery from 'mediaquery'
import transform from 'lodash/object/transform'
import reduce from 'lodash/collection/reduce'
// local imports
import CALCULATE_RESPONSIVE_STATE from '../actions/types/CALCULATE_RESPONSIVE_STATE'

// default breakpoints
const defaultBreakpoints = {
    extraSmall: 480,
    small: 768,
    medium: 992,
    large: 1200,
}
// media type to default to when no `window` present
const defaultMediaType = 'infinity'

/**
 * Compute the `lessThan` object based on the browser width.
 * @arg {number} browserWidth - Width of the browser.
 * @arg {object} breakpoints - The breakpoints object.
 * @returns {object} The `lessThan` object.  Its keys are the same as the
 * keys of the breakpoints object.  The value for each key indicates whether
 * or not the browser width is less than the breakpoint.
 */
function getLessThan(browserWidth, breakpoints, currentMediaType) {
    return transform(breakpoints, (result, breakpoint, mediaType) => {
        // if the breakpoint is a number
        if (typeof breakpoint === 'number') {
            // store wether or not it is less than the breakpoint
            result[mediaType] = browserWidth < breakpoint && mediaType !== currentMediaType
        // handle non numerical breakpoints specially
        } else {
            result[mediaType] = false
        }
    })
}

/**
 * Compute the `greaterThan` object based on the browser width.
 * @arg {number} browserWidth - Width of the browser.
 * @arg {object} breakpoints - The breakpoints object.
 * @returns {object} The `greaterThan` object.  Its keys are the same as the
 * keys of the breakpoints object.  The value for each key indicates whether
 * or not the browser width is greater than the breakpoint.
 */
function getGreaterThan(browserWidth, breakpoints) {
    return transform(breakpoints, (result, breakpoint, mediaType) => {
        // if the breakpoint is a number
        if (typeof breakpoint === 'number') {
            // store wether or not it is greater than the breakpoint
            result[mediaType] = browserWidth > breakpoint
        } else {
            result[mediaType] = false
        }
    })
}

/**
 * Gets the current media type from the global `window`.
 * @arg {object} mediaQueries - The media queries object.
 * @returns {string} The window's current media type.  This is the key of the
 * breakpoint that is the next breakpoint larger than the window.
 */
function getMediaType(matchMedia, mediaQueries) {
    // if there's no window
    if (typeof matchMedia === 'undefined') {
        // return the default
        return defaultMediaType
    }

    // there is a window, so compute the true media type
    return reduce(mediaQueries, (result, query, type) => {
        // return the new type if the query matches otherwise the previous one
        return matchMedia(query).matches ? type : result
    // use the default media type
    }, defaultMediaType)
}

// export the reducer factory
export default (breakpoints = defaultBreakpoints) => {
    // add `infinity` breakpoint for upper bound
    breakpoints[defaultMediaType] = Infinity
    // media queries associated with the breakpoints
    const mediaQueries = MediaQuery.asObject(breakpoints)

    // return reducer for handling the responsive state
    return (state, action) => {
        // if told to recalculate state or state has not yet been initialized
        if (action.type === CALCULATE_RESPONSIVE_STATE || typeof state === 'undefined') {
            // the current media type
            const mediaType = getMediaType(action.matchMedia, mediaQueries)
            // return calculated state
            return {
                width: action.innerWidth,
                lessThan: getLessThan(action.innerWidth, breakpoints, mediaType),
                greaterThan: getGreaterThan(action.innerWidth, breakpoints),
                mediaType,
            }
        }
        // otherwise return the previous state
        return state
    }
}
<|endoftext|>


<commit_before>/**
 * Created by windy on 2017/3/13.
 * 数值微调器
 */
BI.NumberEditor = BI.inherit(BI.Widget, {
    _defaultConfig: function () {
        return BI.extend(BI.NumberEditor.superclass._defaultConfig.apply(this, arguments), {
            baseCls: "bi-number-editor bi-border bi-focus-shadow",
            validationChecker: function () {
                return true;
            },
            valueFormatter: function (v) {
                return v;
            },
            value: 0,
            allowBlank: false,
            errorText: "",
            step: 1
        });
    },

    _init: function () {
        BI.NumberEditor.superclass._init.apply(this, arguments);
        var self = this, o = this.options;
        this.editor = BI.createWidget({
            type: "bi.sign_editor",
            height: o.height - 2,
            allowBlank: o.allowBlank,
            value: o.valueFormatter(o.value),
            validationChecker: o.validationChecker,
            errorText: o.errorText
        });
        this.editor.on(BI.TextEditor.EVENT_CHANGE, function () {
            o.value = BI.parseFloat(this.getValue());
            self.fireEvent(BI.NumberEditor.EVENT_CHANGE);
        });
        this.editor.on(BI.TextEditor.EVENT_CONFIRM, function () {
            this.setValue(BI.parseFloat(this.getValue()));
            self.fireEvent(BI.NumberEditor.EVENT_CONFIRM);
        });
        this.topBtn = BI.createWidget({
            type: "bi.icon_button",
            forceNotSelected: true,
            trigger: "lclick,",
            cls: "add-up-font top-button bi-border-left bi-list-item-active2 icon-size-12"
        });
        this.topBtn.on(BI.IconButton.EVENT_CHANGE, function () {
            self._finetuning(o.step);
            self.fireEvent(BI.NumberEditor.EVENT_CHANGE);
            self.fireEvent(BI.NumberEditor.EVENT_CONFIRM);
        });
        this.bottomBtn = BI.createWidget({
            type: "bi.icon_button",
            trigger: "lclick,",
            forceNotSelected: true,
            cls: "minus-down-font bottom-button bi-border-left bi-list-item-active2 icon-size-12"
        });
        this.bottomBtn.on(BI.IconButton.EVENT_CHANGE, function () {
            self._finetuning(-o.step);
            self.fireEvent(BI.NumberEditor.EVENT_CHANGE);
            self.fireEvent(BI.NumberEditor.EVENT_CONFIRM);
        });
        BI.createWidget({
            type: "bi.htape",
            height: o.height - 2,
            element: this,
            items: [this.editor, {
                el: {
                    type: "bi.grid",
                    columns: 1,
                    rows: 2,
                    items: [{
                        column: 0,
                        row: 0,
                        el: this.topBtn
                    }, {
                        column: 0,
                        row: 1,
                        el: this.bottomBtn
                    }]
                },
                width: 23
            }]
        });
    },

    focus: function () {
        this.editor.focus();
    },

    isEditing: function () {
        return this.editor.isEditing();
    },

    // 微调
    _finetuning: function (add) {
        var v = BI.parseFloat(this.getValue());
        this.setValue(BI.add(v, add));
    },

    setUpEnable: function (v) {
        this.topBtn.setEnable(!!v);
    },

    setDownEnable: function (v) {
        this.bottomBtn.setEnable(!!v);
    },

    getValue: function () {
        return this.options.value;
    },

    setValue: function (v) {
        var o = this.options;
        o.value = v;
        this.editor.setValue(o.valueFormatter(v));
    }

});
BI.NumberEditor.EVENT_CONFIRM = "EVENT_CONFIRM";
BI.NumberEditor.EVENT_CHANGE = "EVENT_CHANGE";
BI.shortcut("bi.number_editor", BI.NumberEditor);<commit_msg>无JIRA任务 number_editor存值逻辑改变<commit_after>/**
 * Created by windy on 2017/3/13.
 * 数值微调器
 */
BI.NumberEditor = BI.inherit(BI.Widget, {
    _defaultConfig: function () {
        return BI.extend(BI.NumberEditor.superclass._defaultConfig.apply(this, arguments), {
            baseCls: "bi-number-editor bi-border bi-focus-shadow",
            validationChecker: function () {
                return true;
            },
            valueFormatter: function (v) {
                return v;
            },
            value: 0,
            allowBlank: false,
            errorText: "",
            step: 1
        });
    },

    _init: function () {
        BI.NumberEditor.superclass._init.apply(this, arguments);
        var self = this, o = this.options;
        this.editor = BI.createWidget({
            type: "bi.sign_editor",
            height: o.height - 2,
            allowBlank: o.allowBlank,
            value: o.valueFormatter(o.value),
            validationChecker: o.validationChecker,
            errorText: o.errorText
        });
        this.editor.on(BI.TextEditor.EVENT_CHANGE, function () {
            self.fireEvent(BI.NumberEditor.EVENT_CHANGE);
        });
        this.editor.on(BI.TextEditor.EVENT_CONFIRM, function () {
            o.value = BI.parseFloat(this.getValue());
            self.fireEvent(BI.NumberEditor.EVENT_CONFIRM);
        });
        this.topBtn = BI.createWidget({
            type: "bi.icon_button",
            forceNotSelected: true,
            trigger: "lclick,",
            cls: "add-up-font top-button bi-border-left bi-list-item-active2 icon-size-12"
        });
        this.topBtn.on(BI.IconButton.EVENT_CHANGE, function () {
            self._finetuning(o.step);
            self.fireEvent(BI.NumberEditor.EVENT_CHANGE);
            self.fireEvent(BI.NumberEditor.EVENT_CONFIRM);
        });
        this.bottomBtn = BI.createWidget({
            type: "bi.icon_button",
            trigger: "lclick,",
            forceNotSelected: true,
            cls: "minus-down-font bottom-button bi-border-left bi-list-item-active2 icon-size-12"
        });
        this.bottomBtn.on(BI.IconButton.EVENT_CHANGE, function () {
            self._finetuning(-o.step);
            self.fireEvent(BI.NumberEditor.EVENT_CHANGE);
            self.fireEvent(BI.NumberEditor.EVENT_CONFIRM);
        });
        BI.createWidget({
            type: "bi.htape",
            height: o.height - 2,
            element: this,
            items: [this.editor, {
                el: {
                    type: "bi.grid",
                    columns: 1,
                    rows: 2,
                    items: [{
                        column: 0,
                        row: 0,
                        el: this.topBtn
                    }, {
                        column: 0,
                        row: 1,
                        el: this.bottomBtn
                    }]
                },
                width: 23
            }]
        });
    },

    focus: function () {
        this.editor.focus();
    },

    isEditing: function () {
        return this.editor.isEditing();
    },

    // 微调
    _finetuning: function (add) {
        var v = BI.parseFloat(this.getValue());
        this.setValue(BI.add(v, add));
    },

    setUpEnable: function (v) {
        this.topBtn.setEnable(!!v);
    },

    setDownEnable: function (v) {
        this.bottomBtn.setEnable(!!v);
    },

    getValue: function () {
        return this.options.value;
    },

    setValue: function (v) {
        var o = this.options;
        o.value = v;
        this.editor.setValue(o.valueFormatter(v));
    }

});
BI.NumberEditor.EVENT_CONFIRM = "EVENT_CONFIRM";
BI.NumberEditor.EVENT_CHANGE = "EVENT_CHANGE";
BI.shortcut("bi.number_editor", BI.NumberEditor);<|endoftext|>


<commit_before>// TODO: pass errors back to the calling function in the compile
//       command to give more visibility into the error, things like view
//       name, view file, etc...

var _ = require('../../../lib/alloy/underscore')._,
	U = require('../../../utils'),
	CU = require('../compilerUtils');

exports.parse = function(node, state) {
	var args = CU.getParserArgs(node, state),
		children = U.XML.getElementsFromNodes(node.childNodes),
		linePrefix = '\t',
		annotationSymbols = [],
		code = '';

	// iterate through all children
	for (var i = 0, l = children.length; i < l; i++) {
		var child = children[i],
			childArgs = CU.getParserArgs(child);

		// Process the Map's Annotations
		if (childArgs.fullname === 'Ti.Map.Annotation') {
			var annotationState = require('./default').parse(child, CU.createEmptyState(state.styles));
			annotationSymbols.push(annotationState.parent.symbol);
			code += annotationState.code;

			// When we are done processing the Annotation, remove it from the
			// markup. That way we can just pass back the current Map state as
			// the returned state and it can continue to process any other children
			// without special handling
			node.removeChild(child);
		}
	}

	// Create the initial Map code
	var mapState;
	if (annotationSymbols.length > 0) {
		var extraStyle = CU.createVariableStyle('annotations', '[' + annotationSymbols.join(',') + ']');
		mapState = require('./default').parse(node, state, extraStyle);
	} else {
		mapState = require('./default').parse(node, state);
	}
	code += mapState.code;

	// Update the parsing state
	return _.extend(mapState, {code:code});
};<commit_msg>changes to Ti.Map.View to facilitate platform tag on annotations<commit_after>// TODO: pass errors back to the calling function in the compile
//       command to give more visibility into the error, things like view
//       name, view file, etc...

var _ = require('../../../lib/alloy/underscore')._,
	U = require('../../../utils'),
	CU = require('../compilerUtils');

exports.parse = function(node, state) {
	var args = CU.getParserArgs(node, state),
		children = U.XML.getElementsFromNodes(node.childNodes),
		linePrefix = '\t',
		annotationSymbols = [],
		arrayName = CU.generateUniqueId(),
		code = 'var ' + arrayName + ' = [];\n';

	// iterate through all children
	for (var i = 0, l = children.length; i < l; i++) {
		var child = children[i],
			childArgs = CU.getParserArgs(child);

		// Process the Map's Annotations
		if (childArgs.fullname === 'Ti.Map.Annotation') {
			var annCode = CU.generateNode(child, {
				parent: {},
				styles: state.styles,
				arrayName: arrayName
			});
			code += annCode;

			// When we are done processing the Annotation, remove it from the
			// markup. That way we can just pass back the current Map state as
			// the returned state and it can continue to process any other children
			// without special handling
			node.removeChild(child);
		}
	}

	// Create the initial Map code
	var extraStyle = CU.createVariableStyle('annotations', arrayName);
	var mapState = require('./default').parse(node, state, extraStyle);
	code += mapState.code;

	// Update the parsing state
	return _.extend(mapState, {code:code});
};<|endoftext|>


<commit_before>(function (root, factory) {
    'use strict';
    if (typeof define === 'function' && define.amd) {
        define('adtech-manager', function () {
            return (root.AdtechManager = factory(root));
        });
    }
    else if (typeof exports === 'object') {
        module.exports = factory(root);
    }
    else {
        root.AdtechManager = factory(root);
    }
}(this, function (window) {
    'use strict';

    if(typeof window.ADTECH === 'undefined') {
        throw 'AdTechManager requires Dac.js.'
    }

    // HELPERS
    var $ = document.querySelector.bind(document);

    var camelCase = function(str) {
         return str.replace(/-+(.)?/g, function(match, chr){
             return chr ? chr.toUpperCase() : '';
         });
    };
    var getData = function(el) {
        if (el.dataset) {
            return el.dataset;
        }
        else {
            var data = {};

            each(el.attributes, function(attr) {
                var name = attr.nodeName;
                if (/data\-/.test(name)) {
                    data[camelCase(name.replace('data-', ''))] = attr.nodeValue;
                }
            });

            return data;
        }
    };
    var extend = function(target, source) {
        for (var prop in source) {
            if (prop in target) {
                extend(target[prop], source[prop]);
            }
            else {
                target[prop] = source[prop];
            }
        }
        return target;
    };
    var each = function(arr, callback, obj) {
        if (arr) {
            if (typeof(arr.length) === 'undefined') {
                var prop;
                for (prop in arr) {
                    if (arr.hasOwnProperty(prop)) {
                        callback.call(obj || null, arr[prop], prop, arr);
                    }
                }
            } else {
                var l = arr.length,
                    i = 0;
                for (;i < l;i++) {
                    callback.call(obj || null, arr[i], i, arr);
                }
            }
        }
    };

    // Adscript
    var AdtechManager = function(config) {
        this.config = extend(config, this.config);
        if(typeof ADTECH !== 'undefined') {
            ADTECH.config.page = this.config.adtech;
            ADTECH.debugMode = this.config.debugMode;
        }
        this.getAdData();
        console.log(this.config);
    };

    AdtechManager.prototype = {
        config: {
            adtech: {
                protocol: null,
                server: null,
                network: null,
                enableMultiAd: true,
                fif: {
                    usfif: true
                },
                params: {loc : '100'}
            },
            placements: {
                desktop: {},
                tablet: {},
                mobile: {},
            },
            emptyPixel: 'Default_Size_16_1x1.gif',
            onAdLoaded: null,
            debugMode: false
        },
        data: null,
        getAdData: function() {
            if (this.data === null) {
                this.data = getData($('#ad-data'));
            }
            return this.data;
        },
        getKeywords: function() {
            var data = this.getAdData();
            return data.keywords || '';
        },
        getPlacements: function(platform, route) {
            var platform = platform;

            return this.config.placements[platform][route] || {};
        },
        renderAd: function(placement, placementId) {
            var params = {},
                el = $('#ad-' + placement);

             if (el) {
                params.keywords = this.getKeywords();
                ADTECH.enqueueAd({
                    params: params,
                    placement: placementId,
                    adContainerId: 'ad-' + placement,
                    complete: this.onAdLoaded.bind(this, placement, el)
                });
             }
        },
        renderAds: function() {
            var placements = this.getPlacements(this.data.platform, this.data.route);
            each(placements, function(id, name) {
                this.renderAd(name, id);
            }, this);

            ADTECH.executeQueue();
        },
        onAdLoaded: function(placement, el) {
            var ifDoc = el.querySelector('iframe').contentDocument
            if (ifDoc.querySelector('[src*="'+ this.config.emptyPixel +'"]')) {
                el.style.display = 'none';
            } else {
                el.style.display = 'block';
                if (typeof this.config.onAdLoaded === 'function') {
                    this.config.onAdLoaded.bind(this, placement, el);
                }
            }
        }
    };

    return AdtechManager;
}));
<commit_msg>Let requiring script handle the ad-data logic.<commit_after>(function (root, factory) {
    'use strict';
    if (typeof define === 'function' && define.amd) {
        define('adtech-manager', function () {
            return (root.AdtechManager = factory(root));
        });
    }
    else if (typeof exports === 'object') {
        module.exports = factory(root);
    }
    else {
        root.AdtechManager = factory(root);
    }
}(this, function (window) {
    'use strict';

    if(typeof window.ADTECH === 'undefined') {
        throw 'AdTechManager requires Dac.js.'
    }

    // HELPERS
    var $ = document.querySelector.bind(document);

    var camelCase = function(str) {
         return str.replace(/-+(.)?/g, function(match, chr){
             return chr ? chr.toUpperCase() : '';
         });
    };
    var extend = function(target, source) {
        var prop;
        for (prop in source) {
            if (prop in target) {
                if (typeof(target[prop]) === 'object') {
                    extend(target[prop], source[prop]);
                }
            }
            else {
                target[prop] = source[prop];
            }
        }
        return target;
    };
    var each = function(arr, callback, obj) {
        if (arr) {
            if (typeof(arr.length) === 'undefined') {
                var prop;
                for (prop in arr) {
                    if (arr.hasOwnProperty(prop)) {
                        callback.call(obj || null, arr[prop], prop, arr);
                    }
                }
            } else {
                var l = arr.length,
                    i = 0;
                for (;i < l;i++) {
                    callback.call(obj || null, arr[i], i, arr);
                }
            }
        }
    };

    // Adscript
    var AdtechManager = function(config) {
        this.config = extend(config, this.config);
        if(typeof ADTECH !== 'undefined') {
            ADTECH.config.page = this.config.adtech;
            ADTECH.debugMode = this.config.debugMode;
        }
        console.log(this.config);
    };

    AdtechManager.prototype = {
        config: {
            adtech: {
                protocol: null,
                server: null,
                network: null,
                enableMultiAd: true,
                fif: {
                    usfif: true
                },
                params: {loc : '100'}
            },
            placements: {
                desktop: {},
                tablet: {},
                mobile: {},
            },
            device: 'desktop',
            route: null,
            keywords: [],
            emptyPixel: 'Default_Size_16_1x1.gif',
            onAdLoaded: null,
            debugMode: false
        },
        getKeywords: function() {
            return (this.config.keywords || []).join('+');
        },
        getPlacements: function(device, route) {
            var device = device;

            return this.config.placements[device][route] || {};
        },
        renderAd: function(placement, placementId) {
            var params = {},
                el = $('#ad-' + placement);

             if (el) {
                params.keywords = this.getKeywords();
                ADTECH.enqueueAd({
                    params: params,
                    placement: placementId,
                    adContainerId: 'ad-' + placement,
                    complete: this.onAdLoaded.bind(this, placement, el)
                });
             }
        },
        renderAds: function() {
            var placements = this.getPlacements(this.config.device, this.config.route);
            each(placements, function(id, name) {
                this.renderAd(name, id);
            }, this);

            ADTECH.executeQueue();
        },
        onAdLoaded: function(placement, el) {
            var ifDoc = el.querySelector('iframe').contentDocument
            if (ifDoc.querySelector('[src*="'+ this.config.emptyPixel +'"]')) {
                el.style.display = 'none';
            } else {
                el.style.display = 'block';
                if (typeof this.config.onAdLoaded === 'function') {
                    this.config.onAdLoaded.bind(this, placement, el);
                }
            }
        }
    };

    return AdtechManager;
}));
<|endoftext|>


<commit_before>'use strict';

// MODULES //

var debug = require( 'debug' )( 'stdlib-docs:main' );
var resolve = require( 'path' ).resolve;
var isFunction = require( '@stdlib/assert/is-function' );
var copy = require( '@stdlib/utils/copy' );
var cwd = require( '@stdlib/utils/cwd' );
var menu = require( './../../stdlib-package-menu' );
var buildPkgs = require( './../../build-packages' );
var defaults = require( './defaults.json' );

// MAIN //

/**
* Builds documentation.
*
* @param {Callback} clbk - callback
* @throws {TypeError} callback argument must be a function
*
* @example
* build( clbk );
*
* function clbk( error ) {
*     if ( error ) {
*         throw error;
*     }
* }
*/
function build( clbk ) {
	var opts;
	if ( !isFunction( clbk ) ) {
		throw new TypeError( 'invalid input argument. Callback argument must be a function. Value: `'+clbk+'`.' );
	}
	opts = copy( defaults );
	menu( opts, onMenu );

	/**
	* Callback invoked upon creating a menu fragment.
	*
	* @private
	* @param {(Error|null)} error - error object
	* @param {Object} menu - menu
	*/
	function onMenu( error, menu ) {
		var bopts;
		var dest;
		if ( error ) {
			debug( 'Encountered an error when generating a package menu: %s', error.message );
			return clbk( error );
		}
		dest = resolve( cwd(), opts.out );
		bopts = {
			'head': '<style>'+menu.css+'</style>',
			'prepend': menu.html
		};

		buildPkgs( dest, bopts, onBuild );
	} // end FUNCTION onMenu()

	/**
	* Callback invoked upon building packages.
	*
	* @private
	* @param {(Error|null)} error - error object
	*/
	function onBuild( error ) {
		if ( error ) {
			debug( 'Encountered an error when building packages: %s', error.message );
			return clbk( error );
		}
		clbk();
	} // end FUNCTION onBuild()
} // end FUNCTION build()

// EXPORTS //

module.exports = build;
<commit_msg>Append a script to support AJAX navigation<commit_after>'use strict';

// MODULES //

var debug = require( 'debug' )( 'stdlib-docs:main' );
var resolve = require( 'path' ).resolve;
var isFunction = require( '@stdlib/assert/is-function' );
var copy = require( '@stdlib/utils/copy' );
var cwd = require( '@stdlib/utils/cwd' );
var readFileSync = require( '@stdlib/fs/read-file' ).sync;
var menu = require( './../../stdlib-package-menu' );
var buildPkgs = require( './../../build-packages' );
var defaults = require( './defaults.json' );

// VARIABLES //

var fpath = resolve( __dirname, '..', 'static', 'js', 'script.js' );
var script = readFileSync( fpath, {
	'encoding': 'utf8'
});

// MAIN //

/**
* Builds documentation.
*
* @param {Callback} clbk - callback
* @throws {TypeError} callback argument must be a function
*
* @example
* build( clbk );
*
* function clbk( error ) {
*     if ( error ) {
*         throw error;
*     }
* }
*/
function build( clbk ) {
	var opts;
	if ( !isFunction( clbk ) ) {
		throw new TypeError( 'invalid input argument. Callback argument must be a function. Value: `'+clbk+'`.' );
	}
	opts = copy( defaults );
	menu( opts, onMenu );

	/**
	* Callback invoked upon creating a menu fragment.
	*
	* @private
	* @param {(Error|null)} error - error object
	* @param {Object} menu - menu
	* @returns {void}
	*/
	function onMenu( error, menu ) {
		var bopts;
		var dest;
		if ( error ) {
			debug( 'Encountered an error when generating a package menu: %s', error.message );
			return clbk( error );
		}
		dest = resolve( cwd(), opts.out );
		bopts = {
			'head': '<style>'+menu.css+'</style>',
			'prepend': menu.html,
			'append': script
		};

		buildPkgs( dest, bopts, onBuild );
	} // end FUNCTION onMenu()

	/**
	* Callback invoked upon building packages.
	*
	* @private
	* @param {(Error|null)} error - error object
	* @returns {void}
	*/
	function onBuild( error ) {
		if ( error ) {
			debug( 'Encountered an error when building packages: %s', error.message );
			return clbk( error );
		}
		clbk();
	} // end FUNCTION onBuild()
} // end FUNCTION build()

// EXPORTS //

module.exports = build;
<|endoftext|>


<commit_before>/*
@author kaosat-dev
*/
var detectEnv = require("composite-detect");
if(detectEnv.isModule) var XMLWriter = require('xml-writer');
if(detectEnv.isModule) var JSZip = require( 'jszip' );
if(detectEnv.isModule) var THREE = require("three");

AMFSerializer = function(unit, origin)
{
    this.unit = unit || "milimeter";
    this.origin = origin || "Generated by usco";
}

AMFSerializer.prototype = {
  constructor: AMFSerializer,

  serialize: function( rootElement, compress, fileName ){
    this.writer = new XMLWriter('UTF-8', '1.0');
    var compress = compress || false ;
    var amfContent = this.exportHierarchy ( rootElement );

    if(compress){
      var zipped = new JSZip();
      zipped = zipped.file(fileName, amfContent);
      var outputType = "base64";
      if(detectEnv.isModule) outputType = "nodebuffer";
      console.log("zipping",outputType);
      amfContent = zipped.generate({type: outputType,compression:"DEFLATE"});
    }

    return amfContent;
  },

	exportHierarchy : function (hierarchy) {
		var writer = this.writer;
    var meshes = [];

    writer.startDocument();
    writer.startElement("amf");
    writer.writeAttribute("unit", this.unit);

    this._writeMetaData("cad", this.origin);
    this._writeMaterials(writer, []);

    hierarchy.traverse (function (current) {
			if (current instanceof THREE.Mesh) {
				meshes.push (current);
			}
		});
    //this._writeObject( hierarchy );

    for(var i=0 ; i<meshes.length;i++)
    {
      var part = meshes[i];
      this._writeObject( part );
    }

    this._writeConstellation( hierarchy );

    writer.endElement("amf");
    writer.endDocument();
    result = writer.toString();
    return result;
	},

  _writeMetaData: function(type, data) {
    if(!(type)) throw new Error("Attempting to write metadata with no type");
    var writer = this.writer;

    writer.startElement("metadata");
    writer.writeAttribute("type", "" + type);
    writer.text(data);
    return writer.endElement();
  },

  _writeMaterials: function( materials ) {
    var writer = this.writer;
    writer.startElement("materials");

    for (var i=0, len = materials.length; i < len; i++) {
      material = materials[i];
      this._writeMaterial(material);
    }
    return writer.endElement();
  },

  _writeMaterial: function( material ) {
    var writer = this.writer;
    writer.startElement( "material" );
    this._writeMetaData( "Name", material.name );
    return writer.endElement();
  },

  _writeColor: function(xw, element) {
    xw.startElement("color");
    xw.writeElementString("r", String(element.material.color[0]));
    xw.writeElementString("g", String(element.material.color[1]));
    xw.writeElementString("b", String(element.material.color[2]));
    xw.writeElementString("a", "0");
    return xw.endElement();
  },

  _writeTexture: function(writer, texture) {
    writer.startElement("materials");
    return writer.endElement();
  },

  _writeObject: function( object ) {
    var writer = this.writer;
    var id = object.id;

    writer.startElement("object");
    writer.writeAttribute("id", "" + id);
    if (object.name != null) {
      if (object.name !== "") {
        this._writeMetaData("name", "" + object.name);
      }
    }
    this._writeMesh( object );
    return writer.endElement();
  },

  _writeMesh: function(mesh) {
    var writer = this.writer;
    var geometry = mesh.geometry;

    writer.startElement("mesh");
    this._writeVertices( geometry.vertices );
    this._writeVolumes ( geometry.faces );
    return writer.endElement();
  },
  _writeVertices: function( vertices ) {
    var writer = this.writer
    writer.startElement("vertices");
    for (var i = 0, len = vertices.length; i < len; i++) {
      vertex = vertices[ i ];
      this._writeVertexNode(vertex);
    }
    return writer.endElement();
  },

  _writeVertexNode: function( vertex ) {
    var writer = this.writer;
    writer.startElement("vertex");
    writer.startElement("coordinates");
    writer.writeElement("x", "" + vertex.x);
    writer.writeElement("y", "" + vertex.y);
    writer.writeElement("z", "" + vertex.z);
    writer.endElement();
    return writer.endElement();
  },

  _writeConstellation: function( hierarchy ) {
    var writer = this.writer;
    writer.startElement("constellation");
    writer.writeAttribute("id", "1");

    hierarchy.traverse (function (current) {
			if (current instanceof THREE.Mesh) {
        var rotation = current.rotation;
        var position = current.position;
        if(current.parent)
        {
          var parent = current.parent;
          parent.updateMatrixWorld();
          position = new THREE.Vector3();
          rotation = new THREE.Quaternion();
          var scale = new THREE.Vector3();

          var result = current.matrixWorld.decompose( position, rotation, scale );
        }
        var id = current.id;
        writer.startElement("instance");
        writer.writeAttribute("objectid", "" + id);
        writer.writeElement("deltax", "" + position.x);
        writer.writeElement("deltay", "" + position.y);
        writer.writeElement("deltaz", "" + position.z);
        writer.writeElement("rx", "" + rotation.x);
        writer.writeElement("ry", "" + rotation.y);
        writer.writeElement("rz", "" + rotation.z);
        writer.endElement();

			}
		});

   /* var items = hierarchy.children;
    for (var i = 0, len = items.length; i < len; i++) {
      var child = items[i];
      var id = child.id;
      writer.startElement("instance");
      writer.writeAttribute("objectid", "" + id);
      writer.writeElement("deltax", "" + child.position.x);
      writer.writeElement("deltay", "" + child.position.y);
      writer.writeElement("deltaz", "" + child.position.z);
      writer.writeElement("rx", "" + child.rotation.x);
      writer.writeElement("ry", "" + child.rotation.y);
      writer.writeElement("rz", "" + child.rotation.z);
      writer.endElement();
    }*/
    return writer.endElement();
  },

  _writeVolumes: function(faces) {
    var writer = this.writer;
    writer.startElement("volume");
    for (var i = 0, len = faces.length; i < len; i++) {
      var face = faces[i];
      this._writeTriangle( face );
    }
    return writer.endElement();
  },
  _writeTriangle: function(face) {
    var writer = this.writer;
      writer.startElement("triangle");
      writer.writeElement("v1", "" + face.a);
      writer.writeElement("v2", "" + face.b);
      writer.writeElement("v3", "" + face.c);
      return writer.endElement();
  },

};

if (detectEnv.isModule) module.exports = AMFSerializer;

<commit_msg>- added correct handling of three.js dependency based on browser/node environment<commit_after>/*
@author kaosat-dev
*/
var detectEnv = require("composite-detect");
if(detectEnv.isModule) var XMLWriter = require('xml-writer');
if(detectEnv.isModule) var JSZip = require( 'jszip' );
if(detectEnv.isNode) var THREE = require("three");
if(detectEnv.isBrowser) var THREE = window.THREE;

AMFSerializer = function(unit, origin)
{
    this.unit = unit || "milimeter";
    this.origin = origin || "Generated by usco";
}

AMFSerializer.prototype = {
  constructor: AMFSerializer,

  serialize: function( rootElement, compress, fileName ){
    this.writer = new XMLWriter('UTF-8', '1.0');
    var compress = compress || false ;
    var amfContent = this.exportHierarchy ( rootElement );

    if(compress){
      var zipped = new JSZip();
      zipped = zipped.file(fileName, amfContent);
      var outputType = "base64";
      if(detectEnv.isModule) outputType = "nodebuffer";
      console.log("zipping",outputType);
      amfContent = zipped.generate({type: outputType,compression:"DEFLATE"});
    }

    return amfContent;
  },

	exportHierarchy : function (hierarchy) {
		var writer = this.writer;
    var meshes = [];

    writer.startDocument();
    writer.startElement("amf");
    writer.writeAttribute("unit", this.unit);

    this._writeMetaData("cad", this.origin);
    this._writeMaterials(writer, []);

    hierarchy.traverse (function (current) {
			if (current instanceof THREE.Mesh) {
				meshes.push (current);
			}
		});
    //this._writeObject( hierarchy );

    for(var i=0 ; i<meshes.length;i++)
    {
      var part = meshes[i];
      this._writeObject( part );
    }

    this._writeConstellation( hierarchy );

    writer.endElement("amf");
    writer.endDocument();
    result = writer.toString();
    return result;
	},

  _writeMetaData: function(type, data) {
    if(!(type)) throw new Error("Attempting to write metadata with no type");
    var writer = this.writer;

    writer.startElement("metadata");
    writer.writeAttribute("type", "" + type);
    writer.text(data);
    return writer.endElement();
  },

  _writeMaterials: function( materials ) {
    var writer = this.writer;
    writer.startElement("materials");

    for (var i=0, len = materials.length; i < len; i++) {
      material = materials[i];
      this._writeMaterial(material);
    }
    return writer.endElement();
  },

  _writeMaterial: function( material ) {
    var writer = this.writer;
    writer.startElement( "material" );
    this._writeMetaData( "Name", material.name );
    return writer.endElement();
  },

  _writeColor: function(xw, element) {
    xw.startElement("color");
    xw.writeElementString("r", String(element.material.color[0]));
    xw.writeElementString("g", String(element.material.color[1]));
    xw.writeElementString("b", String(element.material.color[2]));
    xw.writeElementString("a", "0");
    return xw.endElement();
  },

  _writeTexture: function(writer, texture) {
    writer.startElement("materials");
    return writer.endElement();
  },

  _writeObject: function( object ) {
    var writer = this.writer;
    var id = object.id;

    writer.startElement("object");
    writer.writeAttribute("id", "" + id);
    if (object.name != null) {
      if (object.name !== "") {
        this._writeMetaData("name", "" + object.name);
      }
    }
    this._writeMesh( object );
    return writer.endElement();
  },

  _writeMesh: function(mesh) {
    var writer = this.writer;
    var geometry = mesh.geometry;

    writer.startElement("mesh");
    this._writeVertices( geometry.vertices );
    this._writeVolumes ( geometry.faces );
    return writer.endElement();
  },
  _writeVertices: function( vertices ) {
    var writer = this.writer
    writer.startElement("vertices");
    for (var i = 0, len = vertices.length; i < len; i++) {
      vertex = vertices[ i ];
      this._writeVertexNode(vertex);
    }
    return writer.endElement();
  },

  _writeVertexNode: function( vertex ) {
    var writer = this.writer;
    writer.startElement("vertex");
    writer.startElement("coordinates");
    writer.writeElement("x", "" + vertex.x);
    writer.writeElement("y", "" + vertex.y);
    writer.writeElement("z", "" + vertex.z);
    writer.endElement();
    return writer.endElement();
  },

  _writeConstellation: function( hierarchy ) {
    var writer = this.writer;
    writer.startElement("constellation");
    writer.writeAttribute("id", "1");

    hierarchy.traverse (function (current) {
			if (current instanceof THREE.Mesh) {
        var rotation = current.rotation;
        var position = current.position;
        if(current.parent)
        {
          var parent = current.parent;
          parent.updateMatrixWorld();
          position = new THREE.Vector3();
          rotation = new THREE.Quaternion();
          var scale = new THREE.Vector3();

          var result = current.matrixWorld.decompose( position, rotation, scale );
        }
        var id = current.id;
        writer.startElement("instance");
        writer.writeAttribute("objectid", "" + id);
        writer.writeElement("deltax", "" + position.x);
        writer.writeElement("deltay", "" + position.y);
        writer.writeElement("deltaz", "" + position.z);
        writer.writeElement("rx", "" + rotation.x);
        writer.writeElement("ry", "" + rotation.y);
        writer.writeElement("rz", "" + rotation.z);
        writer.endElement();

			}
		});

   /* var items = hierarchy.children;
    for (var i = 0, len = items.length; i < len; i++) {
      var child = items[i];
      var id = child.id;
      writer.startElement("instance");
      writer.writeAttribute("objectid", "" + id);
      writer.writeElement("deltax", "" + child.position.x);
      writer.writeElement("deltay", "" + child.position.y);
      writer.writeElement("deltaz", "" + child.position.z);
      writer.writeElement("rx", "" + child.rotation.x);
      writer.writeElement("ry", "" + child.rotation.y);
      writer.writeElement("rz", "" + child.rotation.z);
      writer.endElement();
    }*/
    return writer.endElement();
  },

  _writeVolumes: function(faces) {
    var writer = this.writer;
    writer.startElement("volume");
    for (var i = 0, len = faces.length; i < len; i++) {
      var face = faces[i];
      this._writeTriangle( face );
    }
    return writer.endElement();
  },
  _writeTriangle: function(face) {
    var writer = this.writer;
      writer.startElement("triangle");
      writer.writeElement("v1", "" + face.a);
      writer.writeElement("v2", "" + face.b);
      writer.writeElement("v3", "" + face.c);
      return writer.endElement();
  },

};

if (detectEnv.isModule) module.exports = AMFSerializer;

<|endoftext|>


<commit_before>frappe.pages["leaderboard"].on_page_load = (wrapper) => {
	frappe.leaderboard = new Leaderboard(wrapper);

	$(wrapper).bind('show', ()=> {
		// Get which leaderboard to show
		let doctype = frappe.get_route()[1];
		frappe.leaderboard.show_leaderboard(doctype);
	});
};

class Leaderboard {

	constructor(parent) {
		frappe.ui.make_app_page({
			parent: parent,
			title: __("Leaderboard"),
			single_column: false,
			card_layout: true,
		});

		this.parent = parent;
		this.page = this.parent.page;
		this.page.sidebar.html(`<ul class="standard-sidebar leaderboard-sidebar overlay-sidebar"></ul>`);
		this.$sidebar_list = this.page.sidebar.find('ul');

		this.get_leaderboard_config();

	}

	get_leaderboard_config() {
		this.doctypes = [];
		this.filters = {};
		this.leaderboard_limit = 20;

		frappe.xcall("frappe.desk.page.leaderboard.leaderboard.get_leaderboard_config").then(config => {
			this.leaderboard_config = config;
			for (let doctype in this.leaderboard_config) {
				this.doctypes.push(doctype);
				this.filters[doctype] = this.leaderboard_config[doctype].fields.map(field => {
					if (typeof field ==='object') {
						return field.label || field.fieldname;
					}
					return field;
				});
			}

			// For translation. Do not remove this
			// __("This Week"), __("This Month"), __("This Quarter"), __("This Year"),
			//	__("Last Week"), __("Last Month"), __("Last Quarter"), __("Last Year"),
			//	__("All Time"), __("Select From Date")
			this.timespans = [
				"This Week", "This Month", "This Quarter", "This Year",
				"Last Week", "Last Month", "Last Quarter", "Last Year",
				"All Time", "Select Date Range"
			];

			// for saving current selected filters
			const _initial_doctype = frappe.get_route()[1] || this.doctypes[0];
			const _initial_timespan = this.timespans[0];
			const _initial_filter = this.filters[_initial_doctype];

			this.options = {
				selected_doctype: _initial_doctype,
				selected_filter: _initial_filter,
				selected_filter_item: _initial_filter[0],
				selected_timespan: _initial_timespan,
			};

			this.message = null;
			this.make();
		});
	}

	make() {

		this.$container = $(`

`).appendTo(this.page.main);

		this.$graph_area = this.$container.find(".leaderboard-graph");

		this.doctypes.map(doctype => {
			const icon = this.leaderboard_config[doctype].icon;
			this.get_sidebar_item(doctype, icon).appendTo(this.$sidebar_list);
		});

		this.setup_leaderboard_fields();

		this.render_selected_doctype();

		this.render_search_box();

		// Get which leaderboard to show
		let doctype = frappe.get_route()[1];
		this.show_leaderboard(doctype);

	}

	setup_leaderboard_fields() {
		this.company_select = this.page.add_field({
			fieldname: "company",
			label: __("Company"),
			fieldtype: "Link",
			options: "Company",
			default: frappe.defaults.get_default("company"),
			reqd: 1,
			change: (e) => {
				this.options.selected_company = e.currentTarget.value;
				this.make_request();
			}
		});

		this.timespan_select = this.page.add_select(__("Timespan"),
			this.timespans.map(d => {
				return {"label": __(d), value: d };
			})
		);
		this.create_date_range_field();

		this.type_select = this.page.add_select(__("Field"),
			this.options.selected_filter.map(d => {
				return {"label": __(frappe.model.unscrub(d)), value: d };
			})
		);

		this.timespan_select.on("change", (e) => {
			this.options.selected_timespan = e.currentTarget.value;
			if (this.options.selected_timespan === 'Select Date Range') {
				this.date_range_field.show();
			} else {
				this.date_range_field.hide();
			}
			this.make_request();
		});

		this.type_select.on("change", (e) => {
			this.options.selected_filter_item = e.currentTarget.value;
			this.make_request();
		});
	}

	create_date_range_field() {
		let timespan_field = $(this.parent).find(`.frappe-control[data-original-title='Timespan']`);
		this.date_range_field = $(`<div class="from-date-field"></div>`).insertAfter(timespan_field).hide();

		let date_field = frappe.ui.form.make_control({
			df: {
				fieldtype: 'DateRange',
				fieldname: 'selected_date_range',
				placeholder: __("Date Range"),
				default: [frappe.datetime.month_start(), frappe.datetime.now_date()],
				input_class: 'input-xs',
				reqd: 1,
				change: () => {
					this.selected_date_range = date_field.get_value();
					if (this.selected_date_range) this.make_request();
				}
			},
			parent: $(this.parent).find('.from-date-field'),
			render_input: 1
		});
	}

	render_selected_doctype() {

		this.$sidebar_list.on("click", "li", (e)=> {
			let $li = $(e.currentTarget);
			let doctype = $li.find(".doctype-text").attr("doctype-value");

			this.options.selected_company = frappe.defaults.get_default("company");
			this.options.selected_doctype = doctype;
			this.options.selected_filter = this.filters[doctype];
			this.options.selected_filter_item = this.filters[doctype][0];

			this.type_select.empty().add_options(
				this.options.selected_filter.map(d => {
					return {"label": __(frappe.model.unscrub(d)), value: d };
				})
			);
			if (this.leaderboard_config[this.options.selected_doctype].company_disabled) {
				$(this.parent).find("[data-original-title=Company]").hide();
			} else {
				$(this.parent).find("[data-original-title=Company]").show();
			}

			this.$sidebar_list.find("li").removeClass("active selected");
			$li.addClass("active selected");

			frappe.set_route("leaderboard", this.options.selected_doctype);
			this.make_request();
		});
	}

	render_search_box() {

		this.$search_box =
			$(`

				<input type="text" placeholder=${ __("Search") } data-element="search" class="form-control leaderboard-search-input input-xs">

`);

		$(this.parent).find(".page-form").append(this.$search_box);
	}

	show_leaderboard(doctype) {
		if (this.doctypes.length) {
			if (this.doctypes.includes(doctype)) {
				this.options.selected_doctype = doctype;
				this.$sidebar_list.find(`[doctype-value = "${this.options.selected_doctype}"]`).trigger("click");
			}

			this.$search_box.find(".leaderboard-search-input").val("");
			frappe.set_route("leaderboard", this.options.selected_doctype);
		}
	}

	make_request() {

		frappe.model.with_doctype(this.options.selected_doctype, ()=> {
			this.get_leaderboard(this.get_leaderboard_data);
		});
	}

	get_leaderboard(notify) {
		if (!this.options.selected_company) {
			frappe.throw(__("Please select Company"));
		}
		frappe.call(
			this.leaderboard_config[this.options.selected_doctype].method,
			{
				'date_range': this.get_date_range(),
				'company': this.options.selected_company,
				'field': this.options.selected_filter_item,
				'limit': this.leaderboard_limit,
			}
		).then(r => {
			let results = r.message || [];

			let graph_items = results.slice(0, 10);

			this.$graph_area.show().empty();

			const custom_options = {
				data: {
					datasets: [{ values: graph_items.map(d => d.value) }],
					labels: graph_items.map(d => d.name)
				},
				format_tooltip_x: d => d[this.options.selected_filter_item],
				height: 140
			};
			frappe.utils.make_chart('.leaderboard-graph', custom_options);

			notify(this, r);
		});
	}

	get_leaderboard_data(me, res) {
		if (res && res.message.length) {
			me.message = null;
			me.$container.find(".leaderboard-list").html(me.render_list_view(res.message));
			frappe.utils.setup_search($(me.parent), ".list-item-container", ".list-id");
		} else {
			me.$graph_area.hide();
			me.message = __("No Items Found");
			me.$container.find(".leaderboard-list").html(me.render_list_view());
		}
	}

	render_list_view(items = []) {

		var html =
			`${this.render_message()}

				${this.render_result(items)}

`;

		return $(html);
	}

	render_result(items) {

		var html =
			`${this.render_list_header()}
			${this.render_list_result(items)}`;
		return html;
	}

	render_list_header() {
		const _selected_filter = this.options.selected_filter
			.map(i => frappe.model.unscrub(i));
		const fields = ["rank", "name", this.options.selected_filter_item];
		const filters = fields.map(filter => {
			const col = __(frappe.model.unscrub(filter));
			return (
				`

						${col}

`
			);
		}).join("");

		const html =
			`

${filters}

`;
		return html;
	}

	render_list_result(items) {

		let _html = items.map((item, index) => {
			const $value = $(this.get_item_html(item, index+1));
			const $item_container = $(`<div class="list-item-container">`).append($value);
			return $item_container[0].outerHTML;
		}).join("");

		let html =
			`

					${_html}

`;

		return html;
	}

	render_message() {
		const display_class = this.message ? '' : 'hide';
		let html = `

${this.message}

`;
		return html;
	}

	get_item_html(item, index) {
		const fields = this.leaderboard_config[this.options.selected_doctype].fields;
		const value = frappe.format(item.value, fields.find(field => {
			let fieldname = field.fieldname || field;
			return fieldname === this.options.selected_filter_item;
		}));

		const link = `/app/${frappe.router.slug(this.options.selected_doctype)}/${item.name}`;
		const name_html = item.formatted_name ?
			`<span class="text-muted ellipsis list-id">${item.formatted_name}</span>`
			: `<a class="grey list-id ellipsis" href="${link}"> ${item.name} </a>`;
		const html =
			`

					${index}

					${name_html}

					${value}

`;

		return html;
	}

	get_sidebar_item(item, icon) {
		let icon_html = icon ? frappe.utils.icon(icon, 'md') : '';
		return $(`

			${icon_html}

				${ __(item) }

`);
	}

	get_date_range() {
		let timespan = this.options.selected_timespan.toLowerCase();
		let current_date = frappe.datetime.now_date();
		let date_range_map = {
			"this week": [frappe.datetime.week_start(), current_date],
			"this month": [frappe.datetime.month_start(), current_date],
			"this quarter": [frappe.datetime.quarter_start(), current_date],
			"this year": [frappe.datetime.year_start(), current_date],
			"last week": [frappe.datetime.add_days(current_date, -7), current_date],
			"last month": [frappe.datetime.add_months(current_date, -1), current_date],
			"last quarter": [frappe.datetime.add_months(current_date, -3), current_date],
			"last year": [frappe.datetime.add_months(current_date, -12), current_date],
			"all time": null,
			"select date range": this.selected_date_range || [frappe.datetime.month_start(), current_date]
		}
		return date_range_map[timespan];
	}

}
<commit_msg>fix: leaderboard not work when lang is not English<commit_after>frappe.pages["leaderboard"].on_page_load = (wrapper) => {
	frappe.leaderboard = new Leaderboard(wrapper);

	$(wrapper).bind('show', ()=> {
		// Get which leaderboard to show
		let doctype = frappe.get_route()[1];
		frappe.leaderboard.show_leaderboard(doctype);
	});
};

class Leaderboard {

	constructor(parent) {
		frappe.ui.make_app_page({
			parent: parent,
			title: __("Leaderboard"),
			single_column: false,
			card_layout: true,
		});

		this.parent = parent;
		this.page = this.parent.page;
		this.page.sidebar.html(`<ul class="standard-sidebar leaderboard-sidebar overlay-sidebar"></ul>`);
		this.$sidebar_list = this.page.sidebar.find('ul');

		this.get_leaderboard_config();

	}

	get_leaderboard_config() {
		this.doctypes = [];
		this.filters = {};
		this.leaderboard_limit = 20;

		frappe.xcall("frappe.desk.page.leaderboard.leaderboard.get_leaderboard_config").then(config => {
			this.leaderboard_config = config;
			for (let doctype in this.leaderboard_config) {
				this.doctypes.push(doctype);
				this.filters[doctype] = this.leaderboard_config[doctype].fields.map(field => {
					if (typeof field ==='object') {
						return field.label || field.fieldname;
					}
					return field;
				});
			}

			// For translation. Do not remove this
			// __("This Week"), __("This Month"), __("This Quarter"), __("This Year"),
			//	__("Last Week"), __("Last Month"), __("Last Quarter"), __("Last Year"),
			//	__("All Time"), __("Select From Date")
			this.timespans = [
				"This Week", "This Month", "This Quarter", "This Year",
				"Last Week", "Last Month", "Last Quarter", "Last Year",
				"All Time", "Select Date Range"
			];

			// for saving current selected filters
			const _initial_doctype = frappe.get_route()[1] || this.doctypes[0];
			const _initial_timespan = this.timespans[0];
			const _initial_filter = this.filters[_initial_doctype];

			this.options = {
				selected_doctype: _initial_doctype,
				selected_filter: _initial_filter,
				selected_filter_item: _initial_filter[0],
				selected_timespan: _initial_timespan,
			};

			this.message = null;
			this.make();
		});
	}

	make() {

		this.$container = $(`

`).appendTo(this.page.main);

		this.$graph_area = this.$container.find(".leaderboard-graph");

		this.doctypes.map(doctype => {
			const icon = this.leaderboard_config[doctype].icon;
			this.get_sidebar_item(doctype, icon).appendTo(this.$sidebar_list);
		});

		this.setup_leaderboard_fields();

		this.render_selected_doctype();

		this.render_search_box();

		// Get which leaderboard to show
		let doctype = frappe.get_route()[1];
		this.show_leaderboard(doctype);

	}

	setup_leaderboard_fields() {
		this.company_select = this.page.add_field({
			fieldname: "company",
			label: __("Company"),
			fieldtype: "Link",
			options: "Company",
			default: frappe.defaults.get_default("company"),
			reqd: 1,
			change: (e) => {
				this.options.selected_company = e.currentTarget.value;
				this.make_request();
			}
		});

		this.timespan_select = this.page.add_select(__("Timespan"),
			this.timespans.map(d => {
				return {"label": __(d), value: d };
			})
		);
		this.create_date_range_field();

		this.type_select = this.page.add_select(__("Field"),
			this.options.selected_filter.map(d => {
				return {"label": __(frappe.model.unscrub(d)), value: d };
			})
		);

		this.timespan_select.on("change", (e) => {
			this.options.selected_timespan = e.currentTarget.value;
			if (this.options.selected_timespan === 'Select Date Range') {
				this.date_range_field.show();
			} else {
				this.date_range_field.hide();
			}
			this.make_request();
		});

		this.type_select.on("change", (e) => {
			this.options.selected_filter_item = e.currentTarget.value;
			this.make_request();
		});
	}

	create_date_range_field() {
		let timespan_field = $(this.parent).find(`.frappe-control[data-original-title=${__('Timespan')}]`);
		this.date_range_field = $(`<div class="from-date-field"></div>`).insertAfter(timespan_field).hide();

		let date_field = frappe.ui.form.make_control({
			df: {
				fieldtype: 'DateRange',
				fieldname: 'selected_date_range',
				placeholder: __("Date Range"),
				default: [frappe.datetime.month_start(), frappe.datetime.now_date()],
				input_class: 'input-xs',
				reqd: 1,
				change: () => {
					this.selected_date_range = date_field.get_value();
					if (this.selected_date_range) this.make_request();
				}
			},
			parent: $(this.parent).find('.from-date-field'),
			render_input: 1
		});
	}

	render_selected_doctype() {

		this.$sidebar_list.on("click", "li", (e)=> {
			let $li = $(e.currentTarget);
			let doctype = $li.find(".doctype-text").attr("doctype-value");

			this.options.selected_company = frappe.defaults.get_default("company");
			this.options.selected_doctype = doctype;
			this.options.selected_filter = this.filters[doctype];
			this.options.selected_filter_item = this.filters[doctype][0];

			this.type_select.empty().add_options(
				this.options.selected_filter.map(d => {
					return {"label": __(frappe.model.unscrub(d)), value: d };
				})
			);
			if (this.leaderboard_config[this.options.selected_doctype].company_disabled) {
				$(this.parent).find("[data-original-title=Company]").hide();
			} else {
				$(this.parent).find("[data-original-title=Company]").show();
			}

			this.$sidebar_list.find("li").removeClass("active selected");
			$li.addClass("active selected");

			frappe.set_route("leaderboard", this.options.selected_doctype);
			this.make_request();
		});
	}

	render_search_box() {

		this.$search_box =
			$(`

				<input type="text" placeholder=${ __("Search") } data-element="search" class="form-control leaderboard-search-input input-xs">

`);

		$(this.parent).find(".page-form").append(this.$search_box);
	}

	show_leaderboard(doctype) {
		if (this.doctypes.length) {
			if (this.doctypes.includes(doctype)) {
				this.options.selected_doctype = doctype;
				this.$sidebar_list.find(`[doctype-value = "${this.options.selected_doctype}"]`).trigger("click");
			}

			this.$search_box.find(".leaderboard-search-input").val("");
			frappe.set_route("leaderboard", this.options.selected_doctype);
		}
	}

	make_request() {

		frappe.model.with_doctype(this.options.selected_doctype, ()=> {
			this.get_leaderboard(this.get_leaderboard_data);
		});
	}

	get_leaderboard(notify) {
		if (!this.options.selected_company) {
			frappe.throw(__("Please select Company"));
		}
		frappe.call(
			this.leaderboard_config[this.options.selected_doctype].method,
			{
				'date_range': this.get_date_range(),
				'company': this.options.selected_company,
				'field': this.options.selected_filter_item,
				'limit': this.leaderboard_limit,
			}
		).then(r => {
			let results = r.message || [];

			let graph_items = results.slice(0, 10);

			this.$graph_area.show().empty();

			const custom_options = {
				data: {
					datasets: [{ values: graph_items.map(d => d.value) }],
					labels: graph_items.map(d => d.name)
				},
				format_tooltip_x: d => d[this.options.selected_filter_item],
				height: 140
			};
			frappe.utils.make_chart('.leaderboard-graph', custom_options);

			notify(this, r);
		});
	}

	get_leaderboard_data(me, res) {
		if (res && res.message.length) {
			me.message = null;
			me.$container.find(".leaderboard-list").html(me.render_list_view(res.message));
			frappe.utils.setup_search($(me.parent), ".list-item-container", ".list-id");
		} else {
			me.$graph_area.hide();
			me.message = __("No Items Found");
			me.$container.find(".leaderboard-list").html(me.render_list_view());
		}
	}

	render_list_view(items = []) {

		var html =
			`${this.render_message()}

				${this.render_result(items)}

`;

		return $(html);
	}

	render_result(items) {

		var html =
			`${this.render_list_header()}
			${this.render_list_result(items)}`;
		return html;
	}

	render_list_header() {
		const _selected_filter = this.options.selected_filter
			.map(i => frappe.model.unscrub(i));
		const fields = ["rank", "name", this.options.selected_filter_item];
		const filters = fields.map(filter => {
			const col = __(frappe.model.unscrub(filter));
			return (
				`

						${col}

`
			);
		}).join("");

		const html =
			`

${filters}

`;
		return html;
	}

	render_list_result(items) {

		let _html = items.map((item, index) => {
			const $value = $(this.get_item_html(item, index+1));
			const $item_container = $(`<div class="list-item-container">`).append($value);
			return $item_container[0].outerHTML;
		}).join("");

		let html =
			`

					${_html}

`;

		return html;
	}

	render_message() {
		const display_class = this.message ? '' : 'hide';
		let html = `

${this.message}

`;
		return html;
	}

	get_item_html(item, index) {
		const fields = this.leaderboard_config[this.options.selected_doctype].fields;
		const value = frappe.format(item.value, fields.find(field => {
			let fieldname = field.fieldname || field;
			return fieldname === this.options.selected_filter_item;
		}));

		const link = `/app/${frappe.router.slug(this.options.selected_doctype)}/${item.name}`;
		const name_html = item.formatted_name ?
			`<span class="text-muted ellipsis list-id">${item.formatted_name}</span>`
			: `<a class="grey list-id ellipsis" href="${link}"> ${item.name} </a>`;
		const html =
			`

					${index}

					${name_html}

					${value}

`;

		return html;
	}

	get_sidebar_item(item, icon) {
		let icon_html = icon ? frappe.utils.icon(icon, 'md') : '';
		return $(`

			${icon_html}

				${ __(item) }

`);
	}

	get_date_range() {
		let timespan = this.options.selected_timespan.toLowerCase();
		let current_date = frappe.datetime.now_date();
		let date_range_map = {
			"this week": [frappe.datetime.week_start(), current_date],
			"this month": [frappe.datetime.month_start(), current_date],
			"this quarter": [frappe.datetime.quarter_start(), current_date],
			"this year": [frappe.datetime.year_start(), current_date],
			"last week": [frappe.datetime.add_days(current_date, -7), current_date],
			"last month": [frappe.datetime.add_months(current_date, -1), current_date],
			"last quarter": [frappe.datetime.add_months(current_date, -3), current_date],
			"last year": [frappe.datetime.add_months(current_date, -12), current_date],
			"all time": null,
			"select date range": this.selected_date_range || [frappe.datetime.month_start(), current_date]
		}
		return date_range_map[timespan];
	}

}
<|endoftext|>