<commit_before>(function () {
  'use strict';

  angular
    .module('app')
    .controller('SpotTabController', SpotTabController);

  SpotTabController.$inject = ['$cordovaGeolocation', '$ionicModal', '$ionicPopup', '$log', '$scope', '$state',
    'FormFactory', 'HelpersFactory', 'LiveDBFactory', 'ProjectFactory', 'SpotFactory', 'IS_WEB'];

  function SpotTabController($cordovaGeolocation, $ionicModal, $ionicPopup, $log, $scope, $state, FormFactory,
                             HelpersFactory, LiveDBFactory, ProjectFactory, SpotFactory, IS_WEB) {
    var vm = this;
    var vmParent = $scope.vm;

    var thisTabName = 'spot';

    vm.isCreateGeologicUnitTag = false;
    vm.isSelectGeologicUnitTag = false;
    vm.lat = undefined;
    vm.lng = undefined;
    vm.x = undefined;
    vm.y = undefined;

    vm.addGeologicUnitTag = addGeologicUnitTag;
    vm.closeGeologicUnitTagModal = closeGeologicUnitTagModal;
    vm.createGeologicUnitTag = createGeologicUnitTag;
    vm.getCoordArray = getCoordArray;
    vm.isImageBasemapSpot = isImageBasemapSpot;
    vm.isMapped = isMapped;
    vm.isPixelMapping = isPixelMapping;
    vm.isPointSpot = isPointSpot;
    vm.isStratSectionSpot= isStratSectionSpot;
    vm.setCurrentLocation = setCurrentLocation;
    vm.setFromMap = setFromMap;
    vm.updateDatetime = updateDatetime;
    vm.updateLatitude = updateLatitude;
    vm.updateLongitude = updateLongitude;
    vm.updateX = updateX;
    vm.updateY = updateY;

    activate();

    /**
     * Private Functions
     */

    function activate() {
      $log.log('In SpotTabController');

      // Loading tab from Spots list
      if ($state.current.name === 'app.spotTab.' + thisTabName) loadTab($state);
      // Loading tab in Map side panel
      $scope.$on('load-tab', function (event, args) {
        if (args.tabName === thisTabName) {
          vmParent.saveSpot().finally(function () {
            vmParent.spotChanged = false;
            loadTab({
              'current': {'name': 'app.spotTab.' + thisTabName},
              'params': {'spotId': args.spotId}
            });
          });
        }
      });

      $ionicModal.fromTemplateUrl('app/spot/spot-tab/add-geologic-unit-tag-modal.html', {
        'scope': $scope,
        'animation': 'slide-in-up',
        'backdropClickToClose': false
      }).then(function (modal) {
        vmParent.addGeologicUnitTagModal = modal;
      });

      $scope.$on('update-spot-geometry', function (event, args) {
        vmParent.spot.geometry = args.movedSpotGeometry;
        vmParent.initializing = true;
        setDisplayedCoords();
      });
    }

    // Get current location of the user
    function getCurrentLocation() {
      $cordovaGeolocation.getCurrentPosition().then(function (position) {
        vm.lat = position.coords.latitude;
        vm.lng = position.coords.longitude;
        if (isPixelMapping()) {
          vmParent.spot.properties.lng = vm.lng;
          vmParent.spot.properties.lat = vm.lat;
        }
        else {
          vmParent.spot.geometry = {
            'type': 'Point',
            'coordinates': [vm.lng, vm.lat]
          };
        }
        if (position.coords.altitude) {
          vmParent.spot.properties.altitude = HelpersFactory.roundToDecimalPlaces(position.coords.altitude, 2);
        }
      }, function (err) {
        $ionicPopup.alert({
          'title': 'Alert!',
          'template': 'Unable to get location: ' + err.message
        });
      });
    }

    function loadTab(state) {
      vmParent.loadTab(state);  // Need to load current state into parent

      vmParent.showTrace = false;
      vmParent.showGeologicUnit = true;
      vmParent.showSurfaceFeature = false;

      if (vmParent.spot && vmParent.spot.geometry && vmParent.spot.geometry.type === 'LineString') {
        vmParent.showTrace = true;
        vmParent.showGeologicUnit = false;
        if (vmParent.spot.properties.trace) vmParent.data = vmParent.spot.properties.trace;
        FormFactory.setForm('trace');
      }
      if (vmParent.spot && vmParent.spot.geometry && vmParent.spot.geometry.type === 'Polygon') {
        vmParent.showRadius = false;
        vmParent.showSurfaceFeature = true;
        if (vmParent.spot.properties.surface_feature) vmParent.data = vmParent.spot.properties.surface_feature;
        FormFactory.setForm('surface_feature');
      }

      // Has the spot been mapped yet?
      if (vmParent.spot && vmParent.spot.geometry && vmParent.spot.geometry.coordinates) {
        // If the geometry coordinates contain any null values, delete the geometry; it shouldn't be defined
        if (_.indexOf(_.flatten(vmParent.spot.geometry.coordinates), null) !== -1) delete vmParent.spot.geometry;
        else setDisplayedCoords();
      }
    }

    function reloadTab() {
      vmParent.addGeologicUnitTagModal.hide();
      loadTab({
        'current': {'name': 'app.spotTab.' + thisTabName},
        'params': {'spotId': vmParent.spot.properties.id}
      });
    }

    function setDisplayedCoords() {
      // Show Lat and Long if Pixel Coordinates or if the geometry type is Point
      if (isPixelMapping()) {
        vm.lat = vmParent.spot.properties.lat;
        vm.lng = vmParent.spot.properties.lng;
        if (vmParent.spot.geometry.type === 'Point') {
          vm.y = vmParent.spot.geometry.coordinates[1];
          vm.x = vmParent.spot.geometry.coordinates[0];
        }
      }
      else if (vmParent.spot.geometry.type === 'Point') {
          vm.lat = vmParent.spot.geometry.coordinates[1];
          vm.lng = vmParent.spot.geometry.coordinates[0];
      }
    }

    /**
     * Public Functions
     */

    function addGeologicUnitTag() {
      if (!IS_WEB) {
        vmParent.saveSpot().then(function () {
          vmParent.data = {};
          vm.isCreateGeologicUnitTag = false;
          vm.isSelectGeologicUnitTag = true;
          vmParent.addGeologicUnitTagModal.show();
        });
      }
      else {
        if (vmParent.spotChanged) {
          $ionicPopup.alert({
            'title': 'Save Spot First!',
            'template': 'Save your Spot before editing geologic units.'
          });
        }
        else {
          vmParent.data = {};
          vm.isCreateGeologicUnitTag = false;
          vm.isSelectGeologicUnitTag = true;
          vmParent.addGeologicUnitTagModal.show();
        }
      }
    }

    function closeGeologicUnitTagModal() {
      vmParent.data = HelpersFactory.cleanObj(vmParent.data);
      if (_.isEmpty(vmParent.data)) reloadTab();
      else {
        if (!vmParent.data.unit_label_abbreviation) {
          $ionicPopup.alert({
            'title': 'No Unit Label!',
            'template': 'Please give a unit label to this tag.'
          });
        }
        else {
          vmParent.data.id = HelpersFactory.getNewId().toString();
          vmParent.data.type = 'geologic_unit';
          vmParent.data.name = vmParent.data.unit_label_abbreviation;
          vmParent.data.spots = [];
          vmParent.data.spots.push(vmParent.spot.properties.id);
          ProjectFactory.saveTag(vmParent.data).then(function () {
            reloadTab();
            $log.log('Tag saved');
            if (IS_WEB) {
              $log.log('Save tags to LiveDB.', ProjectFactory.getCurrentProject());
              LiveDBFactory.save(null, ProjectFactory.getCurrentProject(), ProjectFactory.getSpotsDataset());
            }
          });
        }
      }
    }

    function createGeologicUnitTag() {
      vm.isCreateGeologicUnitTag = true;
      vm.isSelectGeologicUnitTag = false;
      FormFactory.setForm('rock_unit');
    }

    // Get the array of coordinates as a string
    function  getCoordArray() {
      var coordString = JSON.stringify(vmParent.spot.geometry.coordinates);
      return '[' + coordString.replace(/^\[+|\]+$/g,'') + ']';              // Remove extra [ and ] from start and end
    }

    // Is the Spot mapped on an image basemap?
    function isImageBasemapSpot() {
      return vmParent.spot && vmParent.spot.properties && vmParent.spot.properties.image_basemap;
    }

    // Has the Spot been mapped?
    function isMapped() {
      return vmParent.spot && vmParent.spot.geometry && vmParent.spot.geometry.coordinates;
    }

    // Does the Spot have pixel coordinates
    function isPixelMapping() {
      return isImageBasemapSpot() || isStratSectionSpot();
    }

    // Is the Spot a Point
    function isPointSpot() {
      return vmParent.spot && vmParent.spot.geometry && vmParent.spot.geometry.type === 'Point';
    }

    // Is the Spot mapped ona strat section
    function isStratSectionSpot() {
      return vmParent.spot && vmParent.spot.properties && vmParent.spot.properties.strat_section_id;
    }

    function setCurrentLocation() {
      if (vmParent.spot && vmParent.spot.geometry) {
        var confirmPopup = $ionicPopup.confirm({
          'title': 'Modify Lat/Long',
          'template': 'Are you sure you want to update the lat and long for this spot?'
        });
        confirmPopup.then(function (res) {
          if (res) getCurrentLocation();
        });
      }
      else getCurrentLocation();
    }

    // Open the map so the user can set the location for the spot
    function setFromMap() {
      SpotFactory.moveSpot = true;
      SpotFactory.setKeepSpotSelected(true);
      if (_.has(vmParent.spot.properties, 'image_basemap')) {
        vmParent.submit('/app/image-basemaps/' + vmParent.spot.properties.image_basemap);
      }
      else if (_.has(vmParent.spot.properties, 'strat_section_id')) {
        vmParent.submit('/app/strat_sections/' + vmParent.spot.properties.strat_section_id);
      }
      else vmParent.submit('/app/map');
    }

    function updateDatetime(datetime) {
      vmParent.spot.properties.date = datetime.toISOString();
      vmParent.spot.properties.time = datetime.toISOString(); // ToDo: remove time property when no longer needed
    }

    // Update the value for the Latitude from the user input
    function updateLatitude(lat) {
      if (isPixelMapping()) vmParent.spot.properties.lat = lat;
      else vmParent.spot.geometry.coordinates[1] = lat;
    }

    // Update the value for the Longitude from the user input
    function updateLongitude(lng) {
      if (isPixelMapping()) vmParent.spot.properties.lng = lng;
      else vmParent.spot.geometry.coordinates[0] = lng;
    }

    // Update the value for the x from the user input
    function updateX(x) {
      vmParent.spot.geometry.coordinates[0] = x;
    }

    // Update the value for the Longitude from the user input
    function updateY(y) {
      vmParent.spot.geometry.coordinates[1] = y;
    }
  }
}());
<commit_msg>reverting changes to getCurrentLocation ()<commit_after>(function () {
  'use strict';

  angular
    .module('app')
    .controller('SpotTabController', SpotTabController);

  SpotTabController.$inject = ['$cordovaGeolocation', '$ionicModal', '$ionicPopup', '$log', '$scope', '$state',
    'FormFactory', 'HelpersFactory', 'LiveDBFactory', 'ProjectFactory', 'SpotFactory', 'IS_WEB'];

  function SpotTabController($cordovaGeolocation, $ionicModal, $ionicPopup, $log, $scope, $state, FormFactory,
                             HelpersFactory, LiveDBFactory, ProjectFactory, SpotFactory, IS_WEB) {
    var vm = this;
    var vmParent = $scope.vm;

    var thisTabName = 'spot';

    vm.isCreateGeologicUnitTag = false;
    vm.isSelectGeologicUnitTag = false;
    vm.lat = undefined;
    vm.lng = undefined;
    vm.x = undefined;
    vm.y = undefined;

    vm.addGeologicUnitTag = addGeologicUnitTag;
    vm.closeGeologicUnitTagModal = closeGeologicUnitTagModal;
    vm.createGeologicUnitTag = createGeologicUnitTag;
    vm.getCoordArray = getCoordArray;
    vm.isImageBasemapSpot = isImageBasemapSpot;
    vm.isMapped = isMapped;
    vm.isPixelMapping = isPixelMapping;
    vm.isPointSpot = isPointSpot;
    vm.isStratSectionSpot= isStratSectionSpot;
    vm.setCurrentLocation = setCurrentLocation;
    vm.setFromMap = setFromMap;
    vm.updateDatetime = updateDatetime;
    vm.updateLatitude = updateLatitude;
    vm.updateLongitude = updateLongitude;
    vm.updateX = updateX;
    vm.updateY = updateY;

    activate();

    /**
     * Private Functions
     */

    function activate() {
      $log.log('In SpotTabController');

      // Loading tab from Spots list
      if ($state.current.name === 'app.spotTab.' + thisTabName) loadTab($state);
      // Loading tab in Map side panel
      $scope.$on('load-tab', function (event, args) {
        if (args.tabName === thisTabName) {
          vmParent.saveSpot().finally(function () {
            vmParent.spotChanged = false;
            loadTab({
              'current': {'name': 'app.spotTab.' + thisTabName},
              'params': {'spotId': args.spotId}
            });
          });
        }
      });

      $ionicModal.fromTemplateUrl('app/spot/spot-tab/add-geologic-unit-tag-modal.html', {
        'scope': $scope,
        'animation': 'slide-in-up',
        'backdropClickToClose': false
      }).then(function (modal) {
        vmParent.addGeologicUnitTagModal = modal;
      });

      $scope.$on('update-spot-geometry', function (event, args) {
        vmParent.spot.geometry = args.movedSpotGeometry;
        vmParent.initializing = true;
        setDisplayedCoords();
      });
    }

    // Get current location of the user
    function getCurrentLocation() {
      $cordovaGeolocation.getCurrentPosition().then(function (position) {
        vm.lat = HelpersFactory.roundToDecimalPlaces(position.coords.latitude, 6);
        vm.lng = HelpersFactory.roundToDecimalPlaces(position.coords.longitude, 6);
        if (isPixelMapping()) {
          vmParent.spot.properties.lng = vm.lng;
          vmParent.spot.properties.lat = vm.lat;
        }
        else {
          vmParent.spot.geometry = {
            'type': 'Point',
            'coordinates': [vm.lng, vm.lat]
          };
        }
        if (position.coords.altitude) {
          vmParent.spot.properties.altitude = HelpersFactory.roundToDecimalPlaces(position.coords.altitude, 2);
        }
      }, function (err) {
        $ionicPopup.alert({
          'title': 'Alert!',
          'template': 'Unable to get location: ' + err.message
        });
      });
    }

    function loadTab(state) {
      vmParent.loadTab(state);  // Need to load current state into parent

      vmParent.showTrace = false;
      vmParent.showGeologicUnit = true;
      vmParent.showSurfaceFeature = false;

      if (vmParent.spot && vmParent.spot.geometry && vmParent.spot.geometry.type === 'LineString') {
        vmParent.showTrace = true;
        vmParent.showGeologicUnit = false;
        if (vmParent.spot.properties.trace) vmParent.data = vmParent.spot.properties.trace;
        FormFactory.setForm('trace');
      }
      if (vmParent.spot && vmParent.spot.geometry && vmParent.spot.geometry.type === 'Polygon') {
        vmParent.showRadius = false;
        vmParent.showSurfaceFeature = true;
        if (vmParent.spot.properties.surface_feature) vmParent.data = vmParent.spot.properties.surface_feature;
        FormFactory.setForm('surface_feature');
      }

      // Has the spot been mapped yet?
      if (vmParent.spot && vmParent.spot.geometry && vmParent.spot.geometry.coordinates) {
        // If the geometry coordinates contain any null values, delete the geometry; it shouldn't be defined
        if (_.indexOf(_.flatten(vmParent.spot.geometry.coordinates), null) !== -1) delete vmParent.spot.geometry;
        else setDisplayedCoords();
      }
    }

    function reloadTab() {
      vmParent.addGeologicUnitTagModal.hide();
      loadTab({
        'current': {'name': 'app.spotTab.' + thisTabName},
        'params': {'spotId': vmParent.spot.properties.id}
      });
    }

    function setDisplayedCoords() {
      // Show Lat and Long if Pixel Coordinates or if the geometry type is Point
      if (isPixelMapping()) {
        vm.lat = vmParent.spot.properties.lat;
        vm.lng = vmParent.spot.properties.lng;
        if (vmParent.spot.geometry.type === 'Point') {
          vm.y = vmParent.spot.geometry.coordinates[1];
          vm.x = vmParent.spot.geometry.coordinates[0];
        }
      }
      else if (vmParent.spot.geometry.type === 'Point') {
          vm.lat = vmParent.spot.geometry.coordinates[1];
          vm.lng = vmParent.spot.geometry.coordinates[0];
      }
    }

    /**
     * Public Functions
     */

    function addGeologicUnitTag() {
      if (!IS_WEB) {
        vmParent.saveSpot().then(function () {
          vmParent.data = {};
          vm.isCreateGeologicUnitTag = false;
          vm.isSelectGeologicUnitTag = true;
          vmParent.addGeologicUnitTagModal.show();
        });
      }
      else {
        if (vmParent.spotChanged) {
          $ionicPopup.alert({
            'title': 'Save Spot First!',
            'template': 'Save your Spot before editing geologic units.'
          });
        }
        else {
          vmParent.data = {};
          vm.isCreateGeologicUnitTag = false;
          vm.isSelectGeologicUnitTag = true;
          vmParent.addGeologicUnitTagModal.show();
        }
      }
    }

    function closeGeologicUnitTagModal() {
      vmParent.data = HelpersFactory.cleanObj(vmParent.data);
      if (_.isEmpty(vmParent.data)) reloadTab();
      else {
        if (!vmParent.data.unit_label_abbreviation) {
          $ionicPopup.alert({
            'title': 'No Unit Label!',
            'template': 'Please give a unit label to this tag.'
          });
        }
        else {
          vmParent.data.id = HelpersFactory.getNewId().toString();
          vmParent.data.type = 'geologic_unit';
          vmParent.data.name = vmParent.data.unit_label_abbreviation;
          vmParent.data.spots = [];
          vmParent.data.spots.push(vmParent.spot.properties.id);
          ProjectFactory.saveTag(vmParent.data).then(function () {
            reloadTab();
            $log.log('Tag saved');
            if (IS_WEB) {
              $log.log('Save tags to LiveDB.', ProjectFactory.getCurrentProject());
              LiveDBFactory.save(null, ProjectFactory.getCurrentProject(), ProjectFactory.getSpotsDataset());
            }
          });
        }
      }
    }

    function createGeologicUnitTag() {
      vm.isCreateGeologicUnitTag = true;
      vm.isSelectGeologicUnitTag = false;
      FormFactory.setForm('rock_unit');
    }

    // Get the array of coordinates as a string
    function  getCoordArray() {
      var coordString = JSON.stringify(vmParent.spot.geometry.coordinates);
      return '[' + coordString.replace(/^\[+|\]+$/g,'') + ']';              // Remove extra [ and ] from start and end
    }

    // Is the Spot mapped on an image basemap?
    function isImageBasemapSpot() {
      return vmParent.spot && vmParent.spot.properties && vmParent.spot.properties.image_basemap;
    }

    // Has the Spot been mapped?
    function isMapped() {
      return vmParent.spot && vmParent.spot.geometry && vmParent.spot.geometry.coordinates;
    }

    // Does the Spot have pixel coordinates
    function isPixelMapping() {
      return isImageBasemapSpot() || isStratSectionSpot();
    }

    // Is the Spot a Point
    function isPointSpot() {
      return vmParent.spot && vmParent.spot.geometry && vmParent.spot.geometry.type === 'Point';
    }

    // Is the Spot mapped ona strat section
    function isStratSectionSpot() {
      return vmParent.spot && vmParent.spot.properties && vmParent.spot.properties.strat_section_id;
    }

    function setCurrentLocation() {
      if (vmParent.spot && vmParent.spot.geometry) {
        var confirmPopup = $ionicPopup.confirm({
          'title': 'Modify Lat/Long',
          'template': 'Are you sure you want to update the lat and long for this spot?'
        });
        confirmPopup.then(function (res) {
          if (res) getCurrentLocation();
        });
      }
      else getCurrentLocation();
    }

    // Open the map so the user can set the location for the spot
    function setFromMap() {
      SpotFactory.moveSpot = true;
      SpotFactory.setKeepSpotSelected(true);
      if (_.has(vmParent.spot.properties, 'image_basemap')) {
        vmParent.submit('/app/image-basemaps/' + vmParent.spot.properties.image_basemap);
      }
      else if (_.has(vmParent.spot.properties, 'strat_section_id')) {
        vmParent.submit('/app/strat_sections/' + vmParent.spot.properties.strat_section_id);
      }
      else vmParent.submit('/app/map');
    }

    function updateDatetime(datetime) {
      vmParent.spot.properties.date = datetime.toISOString();
      vmParent.spot.properties.time = datetime.toISOString(); // ToDo: remove time property when no longer needed
    }

    // Update the value for the Latitude from the user input
    function updateLatitude(lat) {
      if (isPixelMapping()) vmParent.spot.properties.lat = lat;
      else vmParent.spot.geometry.coordinates[1] = lat;
    }

    // Update the value for the Longitude from the user input
    function updateLongitude(lng) {
      if (isPixelMapping()) vmParent.spot.properties.lng = lng;
      else vmParent.spot.geometry.coordinates[0] = lng;
    }

    // Update the value for the x from the user input
    function updateX(x) {
      vmParent.spot.geometry.coordinates[0] = x;
    }

    // Update the value for the Longitude from the user input
    function updateY(y) {
      vmParent.spot.geometry.coordinates[1] = y;
    }
  }
}());
<|endoftext|>


<commit_before>/* eslint-disable no-console */
'use strict'

const path = require('path')
const fs = require('fs')
const bytes = require('bytes')
const execa = require('execa')
const { premove: del } = require('premove')
const { fromAegir, gzipSize, pkg, hasTsconfig } = require('./../utils')
const userConfig = require('../config/user')
const tsCmd = require('../ts')

const config = userConfig()

module.exports = async (argv) => {
  const input = argv._.slice(1)
  const forwardOptions = argv['--'] ? argv['--'] : []
  const useBuiltinConfig = !forwardOptions.includes('--config')
  const progress = !forwardOptions.includes('--progress') && !process.env.CI ? ['--progress'] : []
  const webpackConfig = useBuiltinConfig
    ? ['--config', fromAegir('src/config/webpack.config.js')]
    : []

  // Clean dist
  await del(path.join(process.cwd(), 'dist'))

  // Run webpack
  const webpack = await execa('webpack-cli', [
    ...webpackConfig,
    ...progress,
    ...input,
    ...forwardOptions
  ], {
    env: {
      NODE_ENV: process.env.NODE_ENV || 'production',
      AEGIR_BUILD_ANALYZE: argv.bundlesize,
      AEGIR_NODE: argv.node,
      AEGIR_TS: argv.ts
    },
    localDir: path.join(__dirname, '../..'),
    preferLocal: true,
    stdio: 'inherit'
  })

  if (hasTsconfig) {
    await tsCmd({ preset: 'types' })
  }

  if (argv.bundlesize) {
    const stats = JSON.parse(fs.readFileSync(path.join(process.cwd(), 'dist/stats.json')))
    const gzip = await gzipSize(path.join(stats.outputPath, stats.assets[0].name))
    const maxsize = bytes(config.bundlesize.maxSize)
    const diff = gzip - maxsize

    console.log('Use http://webpack.github.io/analyse/ to load "./dist/stats.json".')
    console.log(`Check previous sizes in https://bundlephobia.com/result?p=${pkg.name}@${pkg.version}`)

    if (diff > 0) {
      throw new Error(`${bytes(gzip)} (▲${bytes(diff)} / ${bytes(maxsize)})`)
    } else {
      console.log(`${bytes(gzip)} (▼${bytes(diff)} / ${bytes(maxsize)})`)
    }
  }
  return webpack
}
<commit_msg>fix: build types after bundle size (#695)<commit_after>/* eslint-disable no-console */
'use strict'

const path = require('path')
const fs = require('fs')
const bytes = require('bytes')
const execa = require('execa')
const { premove: del } = require('premove')
const { fromAegir, gzipSize, pkg, hasTsconfig } = require('./../utils')
const userConfig = require('../config/user')
const tsCmd = require('../ts')

const config = userConfig()

module.exports = async (argv) => {
  const input = argv._.slice(1)
  const forwardOptions = argv['--'] ? argv['--'] : []
  const useBuiltinConfig = !forwardOptions.includes('--config')
  const progress = !forwardOptions.includes('--progress') && !process.env.CI ? ['--progress'] : []
  const webpackConfig = useBuiltinConfig
    ? ['--config', fromAegir('src/config/webpack.config.js')]
    : []

  // Clean dist
  await del(path.join(process.cwd(), 'dist'))

  // Run webpack
  const webpack = await execa('webpack-cli', [
    ...webpackConfig,
    ...progress,
    ...input,
    ...forwardOptions
  ], {
    env: {
      NODE_ENV: process.env.NODE_ENV || 'production',
      AEGIR_BUILD_ANALYZE: argv.bundlesize,
      AEGIR_NODE: argv.node,
      AEGIR_TS: argv.ts
    },
    localDir: path.join(__dirname, '../..'),
    preferLocal: true,
    stdio: 'inherit'
  })

  if (argv.bundlesize) {
    const stats = JSON.parse(fs.readFileSync(path.join(process.cwd(), 'dist/stats.json')))
    const gzip = await gzipSize(path.join(stats.outputPath, stats.assets[0].name))
    const maxsize = bytes(config.bundlesize.maxSize)
    const diff = gzip - maxsize

    console.log('Use http://webpack.github.io/analyse/ to load "./dist/stats.json".')
    console.log(`Check previous sizes in https://bundlephobia.com/result?p=${pkg.name}@${pkg.version}`)

    if (diff > 0) {
      throw new Error(`${bytes(gzip)} (▲${bytes(diff)} / ${bytes(maxsize)})`)
    } else {
      console.log(`${bytes(gzip)} (▼${bytes(diff)} / ${bytes(maxsize)})`)
    }
  }

  if (hasTsconfig) {
    await tsCmd({ preset: 'types' })
  }
  return webpack
}
<|endoftext|>


<commit_before>/* globals jQuery, window, document */

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

  var methods = {
    options : {
      "optionClass": "",
      "dropdownClass": "",
      "autoinit": false,
      "callback": false,
      "onSelected": false,
      "dynamicOptLabel": "Add a new option..."
    },
    init: function(options) {

      // Apply user options if user has defined some
      if (options) {
        options = $.extend(methods.options, options);
      } else {
        options = methods.options;
      }

      function initElement($select) {
        // Don't do anything if this is not a select or if this select was already initialized
        if ($select.data("dropdownjs") || !$select.is("select")) {
          return;
        }

        // Is it a multi select?
        var multi = $select.attr("multiple");

        // Does it allow to create new options dynamically?
        var dynamicOptions = $select.attr("data-dynamic-opts"),
            $dynamicInput = $();

        // Create the dropdown wrapper
        var $dropdown = $("

");
        $dropdown.addClass("dropdownjs").addClass(options.dropdownClass);
        $dropdown.data("select", $select);

        // Create the fake input used as "select" element and cache it as $input
        var $input = $("<input type=text readonly class=fakeinput>");
        if ($.material) { $input.data("mdproc", true); }
        // Append it to the dropdown wrapper
        $dropdown.append($input);

        // Create the UL that will be used as dropdown and cache it AS $ul
        var $ul = $("

");
        $ul.data("select", $select);

        // Append it to the dropdown
        $dropdown.append($ul);

        // Transfer the placeholder attribute
        $input.attr("placeholder", $select.attr("placeholder"));

        // Loop trough options and transfer them to the dropdown menu
        $select.find("option").each(function() {
          // Cache $(this)
          var $this = $(this);
          methods._addOption($ul, $this);

        });

        // If this select allows dynamic options add the widget
        if (dynamicOptions) {
          $dynamicInput = $("

");
          $dynamicInput.append("<input>");
          $dynamicInput.find("input").attr("placeholder", options.dynamicOptLabel);
          $ul.append($dynamicInput);
        }
        // Cache the dropdown options
        var selectOptions = $dropdown.find("li");

        // If is a single select, selected the first one or the last with selected attribute
        if (!multi) {
            var $selected;
            if ($select.find(":selected").length) {
                $selected = $select.find(":selected").last();
            } else {
                $selected = $select.find("option, li").first();
            }

            methods._select($dropdown, $selected);
        } else {
            var selectors = [], val = $select.val()
            for (var i in val) {
              selectors.push('li[value=' + val[i] + ']')
            }
            if (selectors.length > 0) {
              methods._select($dropdown, $dropdown.find(selectors.join(',')));
            }
        }

        // Transfer the classes of the select to the input dropdown
        $input.addClass($select[0].className);

        // Hide the old and ugly select
        $select.hide().attr("data-dropdownjs", true);

        // Bring to life our awesome dropdownjs
        $select.after($dropdown);

        // Call the callback
        if (options.callback) {
          options.callback($dropdown);
        }

        //---------------------------------------//
        // DROPDOWN EVENTS                       //
        //---------------------------------------//

        // On click, set the clicked one as selected
        $ul.on("click", "li:not(.dropdownjs-add)", function(e) {
          methods._select($dropdown, $(this));
        });
        $ul.on("keydown", "li:not(.dropdownjs-add)", function(e) {
          if (e.which === 27) {
            $(".dropdownjs > ul > li").attr("tabindex", -1);
            return $input.removeClass("focus").blur();
          }
          if (e.which === 32 && !$(e.target).is("input")) {
            methods._select($dropdown, $(this));
            return false;
          }
        });
        $ul.on("focus", "li:not(.dropdownjs-add)", function() {
          if ($select.is(":disabled")) {
            return;
          }
          $input.addClass("focus");
        });

        // Add new options when the widget is used
        if (dynamicOptions && dynamicOptions.length) {
          $dynamicInput.on("keydown", function(e) {
            if(e.which !== 13) return;
            var $option = $("<option>"),
                val = $dynamicInput.find("input").val();
            $dynamicInput.find("input").val("");

            $option.attr("value", val);
            $option.text(val);
            $select.append($option);

          });
        }

        // Listen for new added options and update dropdown if needed
        $select.on("DOMNodeInserted", function(e) {
          var $this = $(e.target);
          if (!$this.val().length) return;

          methods._addOption($ul, $this);
          $ul.find("li").not(".dropdownjs-add").attr("tabindex", 0);

        });

        // Update dropdown when using val, need to use .val("value").trigger("change");
        $select.on("change", function(e) {
          var $this = $(e.target);
          if (!$this.val().length) return;

          if (!multi) {
            var $selected;
            if ($select.find(":selected").length) {
              $selected = $select.find(":selected").last();
            } else {
              $selected = $select.find("option, li").first();
            }
            methods._select($dropdown, $selected);
          } else {
            methods._select($dropdown, $select.find(":selected"));
          }
        });

        // Used to make the dropdown menu more dropdown-ish
        $input.on("click focus", function(e) {
          e.stopPropagation();
          if ($select.is(":disabled")) {
            return;
          }
          $(".dropdownjs > ul > li").attr("tabindex", -1);
          $(".dropdownjs > input").not($(this)).removeClass("focus").blur();

          $(".dropdownjs > ul > li").not(".dropdownjs-add").attr("tabindex", 0);

          // Set height of the dropdown
          var coords = {
            top: $(this).offset().top - $(document).scrollTop(),
            left: $(this).offset().left - $(document).scrollLeft(),
            bottom: $(window).height() - ($(this).offset().top - $(document).scrollTop()),
            right: $(window).width() - ($(this).offset().left - $(document).scrollLeft())
          };

          var height = coords.bottom;

          // Decide if place the dropdown below or above the input
          if (height < 200 && coords.top > coords.bottom) {
            height = coords.top;
            $ul.attr("placement", "top-left");
          } else {
            $ul.attr("placement", "bottom-left");
          }

          $(this).next("ul").css("max-height", height - 20);
          $(this).addClass("focus");
        });
        // Close every dropdown on click outside
        $(document).on("click", function(e) {

          // Don't close the multi dropdown if user is clicking inside it
          if (multi && $(e.target).parents(".dropdownjs").length) return;

          // Don't close the dropdown if user is clicking inside the dynamic-opts widget
          if ($(e.target).parents(".dropdownjs-add").length || $(e.target).is(".dropdownjs-add")) return;

          // Close opened dropdowns
          $(".dropdownjs > ul > li").attr("tabindex", -1);
          $input.removeClass("focus");
        });
      }

      if (options.autoinit) {
        $(document).on("DOMNodeInserted", function(e) {
          var $this = $(e.target);
          if (!$this.is("select")) {
            $this = $this.find('select');
          }
          if ($this.is(options.autoinit)) {
            $this.each(function() {
              initElement($(this));
            });
          }
        });
      }

      // Loop trough elements
      $(this).each(function() {
        initElement($(this));
      });
    },
    select: function(target) {
      var $target = $(this).find("[value=\"" + target + "\"]");
      console.log("called from select");
      methods._select($(this), $target);
    },
    _select: function($dropdown, $target) {
      if ($target.is(".dropdownjs-add")) return;

      // Get dropdown's elements
      var $select = $dropdown.data("select"),
          $input  = $dropdown.find("input.fakeinput");
      // Is it a multi select?
      var multi = $select.attr("multiple");

      // Cache the dropdown options
      var selectOptions = $dropdown.find("li");

      // Behavior for multiple select
      if (multi) {
        // Toggle option state
        $target.toggleClass("selected");
        // Toggle selection of the clicked option in native select
        $target.each(function() {
          var $selected = $select.find("[value=\"" + $(this).attr("value") + "\"]");
          $selected.prop("selected", $(this).hasClass("selected"));
        });
        // Add or remove the value from the input
        var text = [];
        selectOptions.each(function() {
          if ($(this).hasClass("selected")) {
            text.push($(this).text());
          }
        });
        $input.val(text.join(", "));
      }

      // Behavior for single select
      if (!multi) {
        // Unselect options except the one that will be selected
        if ($target.is("li")) {
          selectOptions.not($target).removeClass("selected");
        }
        // Select the selected option
        $target.addClass("selected");
        // Set the value to the native select
        $select.val($target.attr("value"));
        // Set the value to the input
        $input.val($target.text().trim());
      }

      // This is used only if Material Design for Bootstrap is selected
      if ($.material) {
        if ($input.val().trim()) {
          $select.removeClass("empty");
        } else {
          $select.addClass("empty");
        }
      }

      // Call the callback
      if (this.options.onSelected) {
        this.options.onSelected($target.attr("value"));
      }
    },
    _addOption: function($ul, $this) {
      // Create the option
      var $option = $("

");

      // Style the option
      $option.addClass(this.options.optionClass);

      // If the option has some text then transfer it
      if ($this.text()) {
        $option.text($this.text());
      }
      // Otherwise set the empty label and set it as an empty option
      else {
        $option.html(" ");
      }
      // Set the value of the option
      $option.attr("value", $this.val());

      // Will user be able to remove this option?
      if ($ul.data("select").attr("data-dynamic-opts")) {
        $option.append("");
        $option.find(".close").on("click", function() {
          $option.remove();
          $this.remove();
        });
      }

      // Ss it selected?
      if ($this.prop("selected")) {
        $option.attr("selected", true);
        $option.addClass("selected");
      }

      // Append option to our dropdown
      if ($ul.find(".dropdownjs-add").length) {
        $ul.find(".dropdownjs-add").before($option);
      } else {
        $ul.append($option);
      }
    }
  };

  $.fn.dropdown = function(params) {
    if (methods[params]) {
      return methods[params].apply(this, Array.prototype.slice.call(arguments,1));
    } else if (typeof params === "object" | !params) {
      return methods.init.apply(this, arguments);
    } else {
      $.error("Method " + params + " does not exists on jQuery.dropdown");
    }
  };

}));
<commit_msg>Remove console logging<commit_after>/* globals jQuery, window, document */

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

  var methods = {
    options : {
      "optionClass": "",
      "dropdownClass": "",
      "autoinit": false,
      "callback": false,
      "onSelected": false,
      "dynamicOptLabel": "Add a new option..."
    },
    init: function(options) {

      // Apply user options if user has defined some
      if (options) {
        options = $.extend(methods.options, options);
      } else {
        options = methods.options;
      }

      function initElement($select) {
        // Don't do anything if this is not a select or if this select was already initialized
        if ($select.data("dropdownjs") || !$select.is("select")) {
          return;
        }

        // Is it a multi select?
        var multi = $select.attr("multiple");

        // Does it allow to create new options dynamically?
        var dynamicOptions = $select.attr("data-dynamic-opts"),
            $dynamicInput = $();

        // Create the dropdown wrapper
        var $dropdown = $("

");
        $dropdown.addClass("dropdownjs").addClass(options.dropdownClass);
        $dropdown.data("select", $select);

        // Create the fake input used as "select" element and cache it as $input
        var $input = $("<input type=text readonly class=fakeinput>");
        if ($.material) { $input.data("mdproc", true); }
        // Append it to the dropdown wrapper
        $dropdown.append($input);

        // Create the UL that will be used as dropdown and cache it AS $ul
        var $ul = $("

");
        $ul.data("select", $select);

        // Append it to the dropdown
        $dropdown.append($ul);

        // Transfer the placeholder attribute
        $input.attr("placeholder", $select.attr("placeholder"));

        // Loop trough options and transfer them to the dropdown menu
        $select.find("option").each(function() {
          // Cache $(this)
          var $this = $(this);
          methods._addOption($ul, $this);

        });

        // If this select allows dynamic options add the widget
        if (dynamicOptions) {
          $dynamicInput = $("

");
          $dynamicInput.append("<input>");
          $dynamicInput.find("input").attr("placeholder", options.dynamicOptLabel);
          $ul.append($dynamicInput);
        }
        // Cache the dropdown options
        var selectOptions = $dropdown.find("li");

        // If is a single select, selected the first one or the last with selected attribute
        if (!multi) {
            var $selected;
            if ($select.find(":selected").length) {
                $selected = $select.find(":selected").last();
            } else {
                $selected = $select.find("option, li").first();
            }

            methods._select($dropdown, $selected);
        } else {
            var selectors = [], val = $select.val()
            for (var i in val) {
              selectors.push('li[value=' + val[i] + ']')
            }
            if (selectors.length > 0) {
              methods._select($dropdown, $dropdown.find(selectors.join(',')));
            }
        }

        // Transfer the classes of the select to the input dropdown
        $input.addClass($select[0].className);

        // Hide the old and ugly select
        $select.hide().attr("data-dropdownjs", true);

        // Bring to life our awesome dropdownjs
        $select.after($dropdown);

        // Call the callback
        if (options.callback) {
          options.callback($dropdown);
        }

        //---------------------------------------//
        // DROPDOWN EVENTS                       //
        //---------------------------------------//

        // On click, set the clicked one as selected
        $ul.on("click", "li:not(.dropdownjs-add)", function(e) {
          methods._select($dropdown, $(this));
        });
        $ul.on("keydown", "li:not(.dropdownjs-add)", function(e) {
          if (e.which === 27) {
            $(".dropdownjs > ul > li").attr("tabindex", -1);
            return $input.removeClass("focus").blur();
          }
          if (e.which === 32 && !$(e.target).is("input")) {
            methods._select($dropdown, $(this));
            return false;
          }
        });
        $ul.on("focus", "li:not(.dropdownjs-add)", function() {
          if ($select.is(":disabled")) {
            return;
          }
          $input.addClass("focus");
        });

        // Add new options when the widget is used
        if (dynamicOptions && dynamicOptions.length) {
          $dynamicInput.on("keydown", function(e) {
            if(e.which !== 13) return;
            var $option = $("<option>"),
                val = $dynamicInput.find("input").val();
            $dynamicInput.find("input").val("");

            $option.attr("value", val);
            $option.text(val);
            $select.append($option);

          });
        }

        // Listen for new added options and update dropdown if needed
        $select.on("DOMNodeInserted", function(e) {
          var $this = $(e.target);
          if (!$this.val().length) return;

          methods._addOption($ul, $this);
          $ul.find("li").not(".dropdownjs-add").attr("tabindex", 0);

        });

        // Update dropdown when using val, need to use .val("value").trigger("change");
        $select.on("change", function(e) {
          var $this = $(e.target);
          if (!$this.val().length) return;

          if (!multi) {
            var $selected;
            if ($select.find(":selected").length) {
              $selected = $select.find(":selected").last();
            } else {
              $selected = $select.find("option, li").first();
            }
            methods._select($dropdown, $selected);
          } else {
            methods._select($dropdown, $select.find(":selected"));
          }
        });

        // Used to make the dropdown menu more dropdown-ish
        $input.on("click focus", function(e) {
          e.stopPropagation();
          if ($select.is(":disabled")) {
            return;
          }
          $(".dropdownjs > ul > li").attr("tabindex", -1);
          $(".dropdownjs > input").not($(this)).removeClass("focus").blur();

          $(".dropdownjs > ul > li").not(".dropdownjs-add").attr("tabindex", 0);

          // Set height of the dropdown
          var coords = {
            top: $(this).offset().top - $(document).scrollTop(),
            left: $(this).offset().left - $(document).scrollLeft(),
            bottom: $(window).height() - ($(this).offset().top - $(document).scrollTop()),
            right: $(window).width() - ($(this).offset().left - $(document).scrollLeft())
          };

          var height = coords.bottom;

          // Decide if place the dropdown below or above the input
          if (height < 200 && coords.top > coords.bottom) {
            height = coords.top;
            $ul.attr("placement", "top-left");
          } else {
            $ul.attr("placement", "bottom-left");
          }

          $(this).next("ul").css("max-height", height - 20);
          $(this).addClass("focus");
        });
        // Close every dropdown on click outside
        $(document).on("click", function(e) {

          // Don't close the multi dropdown if user is clicking inside it
          if (multi && $(e.target).parents(".dropdownjs").length) return;

          // Don't close the dropdown if user is clicking inside the dynamic-opts widget
          if ($(e.target).parents(".dropdownjs-add").length || $(e.target).is(".dropdownjs-add")) return;

          // Close opened dropdowns
          $(".dropdownjs > ul > li").attr("tabindex", -1);
          $input.removeClass("focus");
        });
      }

      if (options.autoinit) {
        $(document).on("DOMNodeInserted", function(e) {
          var $this = $(e.target);
          if (!$this.is("select")) {
            $this = $this.find('select');
          }
          if ($this.is(options.autoinit)) {
            $this.each(function() {
              initElement($(this));
            });
          }
        });
      }

      // Loop trough elements
      $(this).each(function() {
        initElement($(this));
      });
    },
    select: function(target) {
      var $target = $(this).find("[value=\"" + target + "\"]");
      methods._select($(this), $target);
    },
    _select: function($dropdown, $target) {
      if ($target.is(".dropdownjs-add")) return;

      // Get dropdown's elements
      var $select = $dropdown.data("select"),
          $input  = $dropdown.find("input.fakeinput");
      // Is it a multi select?
      var multi = $select.attr("multiple");

      // Cache the dropdown options
      var selectOptions = $dropdown.find("li");

      // Behavior for multiple select
      if (multi) {
        // Toggle option state
        $target.toggleClass("selected");
        // Toggle selection of the clicked option in native select
        $target.each(function() {
          var $selected = $select.find("[value=\"" + $(this).attr("value") + "\"]");
          $selected.prop("selected", $(this).hasClass("selected"));
        });
        // Add or remove the value from the input
        var text = [];
        selectOptions.each(function() {
          if ($(this).hasClass("selected")) {
            text.push($(this).text());
          }
        });
        $input.val(text.join(", "));
      }

      // Behavior for single select
      if (!multi) {
        // Unselect options except the one that will be selected
        if ($target.is("li")) {
          selectOptions.not($target).removeClass("selected");
        }
        // Select the selected option
        $target.addClass("selected");
        // Set the value to the native select
        $select.val($target.attr("value"));
        // Set the value to the input
        $input.val($target.text().trim());
      }

      // This is used only if Material Design for Bootstrap is selected
      if ($.material) {
        if ($input.val().trim()) {
          $select.removeClass("empty");
        } else {
          $select.addClass("empty");
        }
      }

      // Call the callback
      if (this.options.onSelected) {
        this.options.onSelected($target.attr("value"));
      }
    },
    _addOption: function($ul, $this) {
      // Create the option
      var $option = $("

");

      // Style the option
      $option.addClass(this.options.optionClass);

      // If the option has some text then transfer it
      if ($this.text()) {
        $option.text($this.text());
      }
      // Otherwise set the empty label and set it as an empty option
      else {
        $option.html(" ");
      }
      // Set the value of the option
      $option.attr("value", $this.val());

      // Will user be able to remove this option?
      if ($ul.data("select").attr("data-dynamic-opts")) {
        $option.append("");
        $option.find(".close").on("click", function() {
          $option.remove();
          $this.remove();
        });
      }

      // Ss it selected?
      if ($this.prop("selected")) {
        $option.attr("selected", true);
        $option.addClass("selected");
      }

      // Append option to our dropdown
      if ($ul.find(".dropdownjs-add").length) {
        $ul.find(".dropdownjs-add").before($option);
      } else {
        $ul.append($option);
      }
    }
  };

  $.fn.dropdown = function(params) {
    if (methods[params]) {
      return methods[params].apply(this, Array.prototype.slice.call(arguments,1));
    } else if (typeof params === "object" | !params) {
      return methods.init.apply(this, arguments);
    } else {
      $.error("Method " + params + " does not exists on jQuery.dropdown");
    }
  };

}));
<|endoftext|>


<commit_before>dojo.provide("dijit._editor.plugins.LinkDialog");
dojo.require("dijit._editor._Plugin");
dojo.require("dijit.Dialog");
dojo.require("dijit._Templated");

dojo.declare("dijit._editor.plugins.LinkDialog",
	[ dijit._editor._Plugin, dijit._Widget ],
	function(){
		this._linkDialog = new dijit.layout.TooltipDialog({
			title: "link url" // FIxmE: i18n
		});
		// FIXME: this is totally torturned. _Templated should make this easier. *sigh*
		this._linkDialog.containerNode.innerHTML = this.linkDialogTemplate;
		dijit._Templated.prototype._attachTemplateNodes.call(this, this._linkDialog.containerNode);
		this._linkDialog.startup();
		this.connect(this.button, "onClick", "showEditor");
	},
	{
		// FIXME: this is a PITA. There should be a lighter weight way to do this
		urlInput: null,
		buttonClass: dijit.form.ToggleButton,
		linkDialogTemplate: [
			"url:  ",
			"<input class='dijitComboBoxInput' type='text' dojoAttachPoint='urlInput'>",
			"
",
			"<input class='dijitButtonNode' type='button' dojoAttachEvent='onclick: setValue;' value='set'>",
			"<input class='dijitButtonNode' type='button' dojoAttachEvent='onclick: hideEditor;' value='cancel'>"
		].join(""),
		useDefaultCommand: false,
		command: "createLink",
		_linkDialog: null,
		setValue: function(){
			this.editor.execCommand(this.command, this.urlInput.value);
			this.hideEditor();
		},
		hideEditor: function(){
			this._linkDialog.hide();
		},
		showEditor: function(){
			// console.debug("showEditor");
			if(!this.button.selected){
				this.editor.execCommand("unlink");
				this.button.setSelected();
			}else{
				this._linkDialog.show(this.button.domNode);
				this.urlInput.focus();
			}
		},
		updateState: function(){
			if(!this._lastUpdate){
				this._lastUpdate = new Date();
			}else{
				if(((new Date())-this._lastUpdate) < this.updateInterval){
					return;
				}
			}
			var _e = this.editor;
			if(!_e){ return; }
			if(!_e.isLoaded){ return; }
			if(this.button){
				try{
					var enabled = _e.queryCommandEnabled("unlink");
					this.button._setDisabled(!enabled);
					if(this.button.setSelected){
						var selected;
						if(dojo.isSafari){
							selected = !!dojo.withGlobal(this.editor.window, "getAncestorElement",dijit._editor.selection, ['a']);
						}else{
							selected = _e.queryCommandState("createLink");
						}
						this.button.setSelected(selected);
					}
				}catch(e){
					console.debug(e);
				}
			}
			this._lastUpdate = new Date();
		}
	}
);
<commit_msg>IE is pretty much fully b0rken for adding links. *sigh*.<commit_after>dojo.provide("dijit._editor.plugins.LinkDialog");
dojo.require("dijit._editor._Plugin");
dojo.require("dijit.Dialog");
dojo.require("dijit._Templated");

dojo.declare("dijit._editor.plugins.LinkDialog",
	[ dijit._editor._Plugin, dijit._Widget ],
	function(){
		this._linkDialog = new dijit.layout.TooltipDialog({
			title: "link url" // FIxmE: i18n
		});
		// FIXME: this is totally torturned. _Templated should make this easier. *sigh*
		this._linkDialog.containerNode.innerHTML = this.linkDialogTemplate;
		// dojo.body().appendChild(this._linkDialog.domNode);
		dijit._Templated.prototype._attachTemplateNodes.call(this, this._linkDialog.containerNode);
		this._linkDialog.startup();

		dojo.connect(this, "_initButton", this, function(){
			this.connect(this.button, "onClick", "showEditor");
		});
	},
	{
		// FIXME: this is a PITA. There should be a lighter weight way to do this
		urlInput: null,
		buttonClass: dijit.form.ToggleButton,
		linkDialogTemplate: [
			"url:  ",
			"<input class='dijitComboBoxInput' type='text' dojoAttachPoint='urlInput'>",
			"
",
			"<input class='dijitButtonNode' type='button' dojoAttachEvent='onclick: setValue;' value='set'>",
			"<input class='dijitButtonNode' type='button' dojoAttachEvent='onclick: hideEditor;' value='cancel'>"
		].join(""),
		useDefaultCommand: false,
		command: "createLink",
		_linkDialog: null,
		setValue: function(){
			var val = this.urlInput.value;
			this.hideEditor();
			this.editor.execCommand(this.command, val);
		},
		_savedSelection: null,
		hideEditor: function(){
			this._linkDialog.hide();
			/* // FIXME: IE is really messed up here!!
			if(dojo.isIE){
				// this.urlInput.blur();
				// console.debug(this._savedSelection);
				// var range = this.editor.document.selection.createRange();
				var range = document.selection.createRange();
				range.moveToBookmark(this._savedSelection);
				setTimeout(function(){
					range.select();
				}, 1);
				// this._savedSelection = null;
			}
			*/
		},
		showEditor: function(){
			if(!this.button.selected){
				console.debug("selected");
				this.editor.execCommand("unlink");
				// this.button.setSelected();
			}else{

				/* // FIXME: IE is *really* b0rken
				if(dojo.isIE){
					var range = this.editor.document.selection.createRange();
					// range.select();
					// console.debug(range.htmlText);
					this._savedSelection = range.getBookmark();
					// console.debug(this._savedSelection);
				}
				*/
				dojo.coords(this.button.domNode);
				this._linkDialog.show(this.button.domNode);
				this.urlInput.focus();
			}
		},
		updateState: function(){
			if(!this._lastUpdate){
				this._lastUpdate = new Date();
			}else{
				if(((new Date())-this._lastUpdate) < this.updateInterval){
					return;
				}
			}
			var _e = this.editor;
			if(!_e){ return; }
			if(!_e.isLoaded){ return; }
			if(this.button){
				try{
					// var enabled = _e.queryCommandEnabled("unlink");
					var enabled = _e.queryCommandEnabled("createlink");
					// this.button._setDisabled(!enabled);
					if(this.button.setSelected){
						var selected = !!dojo.withGlobal(this.editor.window, "getAncestorElement",dijit._editor.selection, ['a']);
						this.button.setSelected(selected);
					}
				}catch(e){
					console.debug(e);
				}
			}
			this._lastUpdate = new Date();
		}
	}
);
<|endoftext|>


<commit_before>/**
 * grunt-nunjucks-render
 * https://github.com/piwi/grunt-nunjucks-render
 *
 * Copyright (c) 2015 Pierre Cassat
 * Licensed under the Apache 2.0 license.
 */

'use strict';

module.exports = function gruntTask(grunt) {

    var path        = require('path'),
        nunjucks    = require('nunjucks'),
        lib         = require('nunjucks/src/lib');

    // merge two objects with priority on second
    function merge(obj1, obj2)
    {
        var obj3 = {}, index;
        for (index in obj1) {
            obj3[index] = obj1[index];
        }
        for (index in obj2) {
            obj3[index] = obj2[index];
        }
        return obj3;
    }

    // prepare data parsing JSON or YAML file if so
    function getData(data)
    {
        var tmp_data = {};
        if (typeof(data)=='object') {
            for (var i in data) {
                if (typeof(data[i])=='string') {
                    tmp_data = merge(tmp_data, getData(data[i]));
                } else {
                    tmp_data = merge(tmp_data, data[i]);
                }
            }
        } else if (typeof(data)=='string') {
            if (/\.json/i.test(data)) {
              tmp_data = grunt.file.readJSON(data);
            } else if (/\.ya?ml/i.test(data)) {
              tmp_data = grunt.file.readYAML(data);
            }
        }
        return tmp_data;
    }

    // GRUNT task "nunjucks_render"
    grunt.registerMultiTask('nunjucks_render', 'Render nunjucks templates', function () {

        // merge task-specific and/or target-specific options with these defaults
        var opts = this.options({
                directory :     '.',
                extension :     '.j2',
                autoescape:     false,
                watch:          true,
                asFunction:     false,
                data:           null,
                processData:    function(data){ return data; }
            });

        var nameFunc = lib.isFunction(opts.name) ? opts.name : function(filepath) {
            return filepath;
        };

        if (!grunt.file.exists(opts.directory)) {
            grunt.log.warn('Views directory "' + opts.directory + '" not found!');
            return false;
        }
        opts.abs_directory = path.resolve(opts.directory) + '/';
        if (grunt.option('debug')) {
            grunt.log.writeln('Setting up Nunjucks view paths to: ' + opts.abs_directory);
        }

        nunjucks.configure(opts.abs_directory, {
            autoescape:     opts.autoescape,
            watch:          opts.watch
        });

/*
// http://gruntjs.com/configuring-tasks#files-array-format
files: [
    {src: ['src/bb.js', 'src/bbb.js'], dest: 'dest/b/', nonull: true},
    {src: ['src/bb1.js', 'src/bbb1.js'], dest: 'dest/b1/', filter: 'isFile'},
],
*/
        this.files.forEach(function (f) {

            var fopts = getData((f.options !== undefined) ? f.options : undefined);
            fopts = merge(opts, fopts);

            var data = getData((f.data !== undefined) ? f.data : undefined);
            data = merge(opts.data, data);
            if (opts.processData) {
                data = opts.processData(data);
            }

            var src = f.src.filter(function (filepath) {
                if (!grunt.file.exists(filepath)) {
                    grunt.log.warn('File "' + filepath + '" not found!');
                    return false;
                }
                return true;
            }).map(function(filepath) {
                var filename = filepath;
                if (filepath.substr(0, opts.directory.length) === opts.directory) {
                    filename = filepath.substr(opts.directory.length);
                }
                data.template_name      = nameFunc(filename);
                data.template_path      = filepath;
                data.template_realpath  = opts.abs_directory + filename;
                if (opts.asFunction) {
                    return nunjucks.precompile(filename, data);
                }
                return nunjucks.render(filename, data);
            }).join('');

            if (grunt.option('debug')) {
                grunt.log.writeflags(data);
            }
            grunt.file.write(f.dest, src);
        });
    });

};
<commit_msg>review to pass the tests :(<commit_after>/**
 * grunt-nunjucks-render
 * https://github.com/piwi/grunt-nunjucks-render
 *
 * Copyright (c) 2015 Pierre Cassat
 * Licensed under the Apache 2.0 license.
 */

'use strict';

module.exports = function gruntTask(grunt) {

    // node/external libs
    var path        = require('path'),
        nunjucks    = require('nunjucks');

    // test if obj is callable
    function isFunction(obj)
    {
        return Object.prototype.toString.call(obj) == '[object Function]';
    }

    // merge two objects with priority on second
    function merge(obj1, obj2)
    {
        var obj3 = {}, index;
        for (index in obj1) {
            obj3[index] = obj1[index];
        }
        for (index in obj2) {
            obj3[index] = obj2[index];
        }
        return obj3;
    }

    // prepare data parsing JSON or YAML file if so
    function getData(data)
    {
        var tmp_data = {};
        if (typeof(data)=='object') {
            for (var i in data) {
                if (typeof(data[i])=='string') {
                    tmp_data = merge(tmp_data, getData(data[i]));
                } else {
                    tmp_data = merge(tmp_data, data[i]);
                }
            }
        } else if (typeof(data)=='string') {
            if (/\.json/i.test(data)) {
              tmp_data = grunt.file.readJSON(data);
            } else if (/\.ya?ml/i.test(data)) {
              tmp_data = grunt.file.readYAML(data);
            }
        }
        return tmp_data;
    }

    // GRUNT task "nunjucks_render"
    grunt.registerMultiTask('nunjucks_render', 'Render nunjucks templates', function () {

        // merge task-specific and/or target-specific options with these defaults
        var opts = this.options({
                basedir :       '.',
//                extension :    '.j2',
                autoescape:     false,
                watch:          true,
                asFunction:     false,
                data:           null,
                processData:    function(data){ return data; }
            });

        var nameFunc = isFunction(opts.name) ? opts.name : function(filepath) {
            return filepath;
        };

        // setup Nunjucks views
        if (!grunt.file.exists(opts.basedir)) {
            grunt.log.warn('Views directory "' + opts.basedir + '" not found!');
            return false;
        }
        opts.abs_basedir = path.resolve(opts.basedir) + '/';
        if (grunt.option('debug')) {
            grunt.log.writeln('Setting up Nunjucks view paths to: ' + opts.abs_basedir);
        }
        nunjucks.configure(opts.abs_basedir, {
            autoescape:     opts.autoescape,
            watch:          opts.watch
        });

        // iterate over all specified file groups
        this.files.forEach(function (f) {

            var fopts = getData((f.options !== undefined) ? f.options : undefined);
            fopts = merge(opts, fopts);

            var data = getData((f.data !== undefined) ? f.data : undefined);
            data = merge(opts.data, data);
            if (opts.processData) {
                data = opts.processData(data);
            }

            // concat specified files
            var src = f.src.filter(function (filepath) {
                // Warn on and remove invalid source files (if nonull was set)
                if (!grunt.file.exists(filepath)) {
                    grunt.log.warn('File "' + filepath + '" not found!');
                    return false;
                }
                return true;
            }).map(function(filepath) {
                var filename = filepath;
                if (filepath.substr(0, opts.basedir.length) === opts.basedir) {
                    filename = filepath.substr(opts.basedir.length);
                }
                data.template_name      = nameFunc(filename);
                data.template_path      = filepath;
                data.template_realpath  = opts.abs_basedir + filename;
                if (opts.asFunction) {
                    return nunjucks.precompile(filepath, data);
                }
                return nunjucks.render(filename, data);
            }).join('');

            // show data on debug
            if (grunt.option('debug')) {
                grunt.log.writeflags(data);
            }

            // write the destination file
            grunt.file.write(f.dest, src);

            // print a success message
            grunt.log.writeln('File "' + f.dest + '" created.');
        });
    });

};
<|endoftext|>


<commit_before>// Copyright 2006 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview Zippy widget implementation.
 *
 *
 * @see ../demos/zippy.html
 */

goog.provide('goog.ui.Zippy');
goog.provide('goog.ui.ZippyEvent');

goog.require('goog.dom');
goog.require('goog.dom.classes');
goog.require('goog.events');
goog.require('goog.events.Event');
goog.require('goog.events.EventTarget');
goog.require('goog.events.EventType');
goog.require('goog.events.KeyCodes');
goog.require('goog.style');

/**
 * Zippy widget. Expandable/collapsible container, clicking the header toggles
 * the visibility of the content.
 *
 * @extends {goog.events.EventTarget}
 * @param {Element|string|null} header Header element, either element
 *     reference, string id or null if no header exists.
 * @param {Element|string|function():Element=} opt_content Content element
 *     (if any), either element reference or string id.  If skipped, the caller
 *     should handle the TOGGLE event in its own way. If a function is passed,
 *     then if will be called to create the content element the first time the
 *     zippy is expanded.
 * @param {boolean=} opt_expanded Initial expanded/visibility state. Defaults to
 *     false.
 * @param {Element|string=} opt_expandedHeader Element to use as the header when
 *     the zippy is expanded.
 * @constructor
 */
goog.ui.Zippy = function(header, opt_content, opt_expanded,
    opt_expandedHeader) {
  goog.events.EventTarget.call(this);

  /**
   * Header element or null if no header exists.
   * @type {Element}
   * @private
   */
  this.elHeader_ = goog.dom.getElement(header) || null;

  /**
   * When present, the header to use when the zippy is expanded.
   * @type {Element}
   * @private
   */
  this.elExpandedHeader_ = goog.dom.getElement(opt_expandedHeader || null);

  /**
   * Function that will create the content element, or false if there is no such
   * function.
   * @type {?function():Element}
   * @private
   */
  this.lazyCreateFunc_ = goog.isFunction(opt_content) ? opt_content : null;

  /**
   * Content element.
   * @type {Element}
   * @private
   */
  this.elContent_ = this.lazyCreateFunc_ || !opt_content ? null :
      goog.dom.getElement(/** @type {Element} */ (opt_content));

  /**
   * Expanded state.
   * @type {boolean}
   * @private
   */
  this.expanded_ = opt_expanded == true;

  var self = this;
  function addHeaderEvents(el) {
    if (el) {
      // Listen for click and keydown events on header
      el.tabIndex = 0;
      goog.events.listen(el, goog.events.EventType.CLICK,
          self.onHeaderClick_, false, self);
      goog.events.listen(el, goog.events.EventType.KEYDOWN,
          self.onHeaderKeyDown_, false, self);
    }
  }
  addHeaderEvents(this.elHeader_);
  addHeaderEvents(this.elExpandedHeader_);

  // initialize based on expanded state
  this.setExpanded(this.expanded_);
};
goog.inherits(goog.ui.Zippy, goog.events.EventTarget);

/**
 * Constants for event names
 *
 * @type {Object}
 */
goog.ui.Zippy.Events = {
  TOGGLE: 'toggle'
};

/**
 * Destroys widget and removes all event listeners.
 */
goog.ui.Zippy.prototype.disposeInternal = function() {
  if (this.elHeader_) {
    goog.events.removeAll(this.elHeader_);
  }
  if (this.elExpandedHeader_) {
    goog.events.removeAll(this.elExpandedHeader_);
  }
  goog.ui.Zippy.superClass_.disposeInternal.call(this);
};

/**
 * Expands content pane.
 */
goog.ui.Zippy.prototype.expand = function() {
  this.setExpanded(true);
};

/**
 * Collapses content pane.
 */
goog.ui.Zippy.prototype.collapse = function() {
  this.setExpanded(false);
};

/**
 * Toggles expanded state.
 */
goog.ui.Zippy.prototype.toggle = function() {
  this.setExpanded(!this.expanded_);
};

/**
 * Sets expanded state.
 *
 * @param {boolean} expanded Expanded/visibility state.
 */
goog.ui.Zippy.prototype.setExpanded = function(expanded) {
  if (this.elContent_) {
    // Hide the element, if one is provided.
    goog.style.showElement(this.elContent_, expanded);
  } else if (expanded && this.lazyCreateFunc_) {
    // Assume that when the element is not hidden upon creation.
    this.elContent_ = this.lazyCreateFunc_();
  }

  if (this.elExpandedHeader_) {
    // Hide the show header and show the hide one.
    goog.style.showElement(this.elHeader_, !expanded);
    goog.style.showElement(this.elExpandedHeader_, expanded);
  } else {
    // Update header image, if any.
    this.updateHeaderClassName_(expanded);
  }

  this.expanded_ = expanded;

  // Fire toggle event
  this.dispatchEvent(new goog.ui.ZippyEvent(goog.ui.Zippy.Events.TOGGLE,
                                            this, this.expanded_));
};

/**
 * @return {boolean} Whether the zippy is expanded.
 */
goog.ui.Zippy.prototype.isExpanded = function() {
  return this.expanded_;
};

/**
 * Updates the header element's className
 *
 * @param {boolean} expanded Expanded/visibility state.
 * @private
 */
goog.ui.Zippy.prototype.updateHeaderClassName_ = function(expanded) {
  if (this.elHeader_) {
    goog.dom.classes.enable(this.elHeader_,
        goog.getCssName('goog-zippy-expanded'), expanded);
    goog.dom.classes.enable(this.elHeader_,
        goog.getCssName('goog-zippy-collapsed'), !expanded);
  }
};

/**
 * KeyDown event handler for header element. Enter and space toggles expanded
 * state.
 *
 * @param {goog.events.BrowserEvent} event KeyDown event.
 * @private
 */
goog.ui.Zippy.prototype.onHeaderKeyDown_ = function(event) {
  if (event.keyCode == goog.events.KeyCodes.ENTER ||
      event.keyCode == goog.events.KeyCodes.SPACE) {

    this.toggle();

    // Prevent enter key from submiting form.
    event.preventDefault();

    event.stopPropagation();
  }
};

/**
 * Click event handler for header element.
 *
 * @param {goog.events.BrowserEvent} event Click event.
 * @private
 */
goog.ui.Zippy.prototype.onHeaderClick_ = function(event) {
  this.toggle();
};

/**
 * Object representing a zippy toggle event.
 *
 * @param {string} type Event type.
 * @param {goog.ui.Zippy} target Zippy widget initiating event.
 * @param {boolean} expanded Expanded state.
 * @extends {goog.events.Event}
 * @constructor
 */
goog.ui.ZippyEvent = function(type, target, expanded) {
  goog.events.Event.call(this, type, target);

  /**
   * The expanded state.
   * @type {boolean}
   */
  this.expanded = expanded;
};
goog.inherits(goog.ui.ZippyEvent, goog.events.Event);
<commit_msg><commit_after>// Copyright 2006 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview Zippy widget implementation.
 *
 *
 * @see ../demos/zippy.html
 */

goog.provide('goog.ui.Zippy');
goog.provide('goog.ui.ZippyEvent');

goog.require('goog.dom');
goog.require('goog.dom.classes');
goog.require('goog.events');
goog.require('goog.events.Event');
goog.require('goog.events.EventTarget');
goog.require('goog.events.EventType');
goog.require('goog.events.KeyCodes');
goog.require('goog.style');

/**
 * Zippy widget. Expandable/collapsible container, clicking the header toggles
 * the visibility of the content.
 *
 * @extends {goog.events.EventTarget}
 * @param {Element|string|null} header Header element, either element
 *     reference, string id or null if no header exists.
 * @param {Element|string|function():Element=} opt_content Content element
 *     (if any), either element reference or string id.  If skipped, the caller
 *     should handle the TOGGLE event in its own way. If a function is passed,
 *     then if will be called to create the content element the first time the
 *     zippy is expanded.
 * @param {boolean=} opt_expanded Initial expanded/visibility state. Defaults to
 *     false.
 * @param {Element|string=} opt_expandedHeader Element to use as the header when
 *     the zippy is expanded.
 * @param {goog.dom.DomHelper=} opt_domHelper An optional DOM helper.
 * @constructor
 */
goog.ui.Zippy = function(header, opt_content, opt_expanded,
    opt_expandedHeader, opt_domHelper) {
  goog.events.EventTarget.call(this);

  /**
   * DomHelper used to interact with the document, allowing components to be
   * created in a different window.
   * @type {!goog.dom.DomHelper}
   * @private
   */
  this.dom_ = opt_domHelper || goog.dom.getDomHelper();

  /**
   * Header element or null if no header exists.
   * @type {Element}
   * @private
   */
  this.elHeader_ = this.dom_.getElement(header) || null;

  /**
   * When present, the header to use when the zippy is expanded.
   * @type {Element}
   * @private
   */
  this.elExpandedHeader_ = this.dom_.getElement(opt_expandedHeader || null);

  /**
   * Function that will create the content element, or false if there is no such
   * function.
   * @type {?function():Element}
   * @private
   */
  this.lazyCreateFunc_ = goog.isFunction(opt_content) ? opt_content : null;

  /**
   * Content element.
   * @type {Element}
   * @private
   */
  this.elContent_ = this.lazyCreateFunc_ || !opt_content ? null :
      this.dom_.getElement(/** @type {Element} */ (opt_content));

  /**
   * Expanded state.
   * @type {boolean}
   * @private
   */
  this.expanded_ = opt_expanded == true;

  var self = this;
  function addHeaderEvents(el) {
    if (el) {
      // Listen for click and keydown events on header
      el.tabIndex = 0;
      goog.events.listen(el, goog.events.EventType.CLICK,
          self.onHeaderClick_, false, self);
      goog.events.listen(el, goog.events.EventType.KEYDOWN,
          self.onHeaderKeyDown_, false, self);
    }
  }
  addHeaderEvents(this.elHeader_);
  addHeaderEvents(this.elExpandedHeader_);

  // initialize based on expanded state
  this.setExpanded(this.expanded_);
};
goog.inherits(goog.ui.Zippy, goog.events.EventTarget);

/**
 * Constants for event names
 *
 * @type {Object}
 */
goog.ui.Zippy.Events = {
  TOGGLE: 'toggle'
};

/**
 * Destroys widget and removes all event listeners.
 */
goog.ui.Zippy.prototype.disposeInternal = function() {
  if (this.elHeader_) {
    goog.events.removeAll(this.elHeader_);
  }
  if (this.elExpandedHeader_) {
    goog.events.removeAll(this.elExpandedHeader_);
  }
  goog.ui.Zippy.superClass_.disposeInternal.call(this);
};

/**
 * Expands content pane.
 */
goog.ui.Zippy.prototype.expand = function() {
  this.setExpanded(true);
};

/**
 * Collapses content pane.
 */
goog.ui.Zippy.prototype.collapse = function() {
  this.setExpanded(false);
};

/**
 * Toggles expanded state.
 */
goog.ui.Zippy.prototype.toggle = function() {
  this.setExpanded(!this.expanded_);
};

/**
 * Sets expanded state.
 *
 * @param {boolean} expanded Expanded/visibility state.
 */
goog.ui.Zippy.prototype.setExpanded = function(expanded) {
  if (this.elContent_) {
    // Hide the element, if one is provided.
    goog.style.showElement(this.elContent_, expanded);
  } else if (expanded && this.lazyCreateFunc_) {
    // Assume that when the element is not hidden upon creation.
    this.elContent_ = this.lazyCreateFunc_();
  }

  if (this.elExpandedHeader_) {
    // Hide the show header and show the hide one.
    goog.style.showElement(this.elHeader_, !expanded);
    goog.style.showElement(this.elExpandedHeader_, expanded);
  } else {
    // Update header image, if any.
    this.updateHeaderClassName_(expanded);
  }

  this.expanded_ = expanded;

  // Fire toggle event
  this.dispatchEvent(new goog.ui.ZippyEvent(goog.ui.Zippy.Events.TOGGLE,
                                            this, this.expanded_));
};

/**
 * @return {boolean} Whether the zippy is expanded.
 */
goog.ui.Zippy.prototype.isExpanded = function() {
  return this.expanded_;
};

/**
 * Updates the header element's className
 *
 * @param {boolean} expanded Expanded/visibility state.
 * @private
 */
goog.ui.Zippy.prototype.updateHeaderClassName_ = function(expanded) {
  if (this.elHeader_) {
    goog.dom.classes.enable(this.elHeader_,
        goog.getCssName('goog-zippy-expanded'), expanded);
    goog.dom.classes.enable(this.elHeader_,
        goog.getCssName('goog-zippy-collapsed'), !expanded);
  }
};

/**
 * KeyDown event handler for header element. Enter and space toggles expanded
 * state.
 *
 * @param {goog.events.BrowserEvent} event KeyDown event.
 * @private
 */
goog.ui.Zippy.prototype.onHeaderKeyDown_ = function(event) {
  if (event.keyCode == goog.events.KeyCodes.ENTER ||
      event.keyCode == goog.events.KeyCodes.SPACE) {

    this.toggle();

    // Prevent enter key from submiting form.
    event.preventDefault();

    event.stopPropagation();
  }
};

/**
 * Click event handler for header element.
 *
 * @param {goog.events.BrowserEvent} event Click event.
 * @private
 */
goog.ui.Zippy.prototype.onHeaderClick_ = function(event) {
  this.toggle();
};

/**
 * Object representing a zippy toggle event.
 *
 * @param {string} type Event type.
 * @param {goog.ui.Zippy} target Zippy widget initiating event.
 * @param {boolean} expanded Expanded state.
 * @extends {goog.events.Event}
 * @constructor
 */
goog.ui.ZippyEvent = function(type, target, expanded) {
  goog.events.Event.call(this, type, target);

  /**
   * The expanded state.
   * @type {boolean}
   */
  this.expanded = expanded;
};
goog.inherits(goog.ui.ZippyEvent, goog.events.Event);
<|endoftext|>


<commit_before>/**
 * @file Tree Demo
 * @author Han Bing Feng (hanbingfeng@)
 */

define(function (require) {
    let React = require('react');
    let _ = require('underscore');
    let DualTreeSelector = require('fcui/DualTreeSelector.jsx');
    let treeTools = require('fcui/core/treeTools.es6');

    let items = [
        {
            title: 'Normal Tree',
            props: {
                treeNodes: [{
                    id: '1',
                    name: 'Node 1',
                    isChildrenLoaded: true
                }, {
                    id: '2',
                    name: 'Node 2',
                    isChildrenLoaded: true
                }],
                value: {}
            }
        },
        {
            title: 'Tree with children',
            props: {
                treeNodes: [{
                    id: '1',
                    name: 'Node 1 with children',
                    isChildrenLoaded: true,
                    children: [{
                        id: '1.1',
                        name: 'Node 1.1',
                        isChildrenLoaded: true
                    }, {
                        id: '1.2',
                        name: 'Node 1.2',
                        isChildrenLoaded: true
                    }]
                }, {
                    id: '2',
                    name: 'Node 2',
                    isChildrenLoaded: true
                }],
                value: {}
            }
        },
        {
            title: '3-level Tree with children',
            props: {
                treeNodes: [{
                    id: '1',
                    name: 'Node 1 with children',
                    isChildrenLoaded: true,
                    children: [{
                        id: '1.1',
                        name: 'Node 1.1 with children',
                        isChildrenLoaded: true,
                        children: [{
                            id: '1.1.1',
                            name: 'Node 1.1.1',
                            isChildrenLoaded: true
                        }]
                    }, {
                        id: '1.2',
                        name: 'Node 1.2',
                        isChildrenLoaded: true
                    }]
                }, {
                    id: '2',
                    name: 'Node 2',
                    isChildrenLoaded: true
                }],
                value: {}
            }
        },
        {
            title: 'Normal tree with async loading',
            props: {
                treeNodes: [{
                    id: '1',
                    name: 'Node 1 with async loading',
                    isChildrenLoaded: false
                }, {
                    id: '2',
                    name: 'Node 2',
                    isChildrenLoaded: true
                }],
                value: {}
            }
        }
    ];

    function factory(me, items) {
        let widgets = [];
        let omitChildren = _.partial(
            _.omit, _, 'children'
        );
        function alertEvents(eventType, e, treeNode, parentTreeNodes) {
            me.props.alert(
                eventType
                + ' | '
                + JSON.stringify(omitChildren(treeNode))
                + ' | '
                + JSON.stringify(parentTreeNodes.map(omitChildren))
            );
        }

        function asyncLoad(cb) {
            let node = items[3].props.treeNodes[0];
            node.isChildrenLoading = true;

            me.forceUpdate();

            setTimeout(() => {
                node.isChildrenLoaded = true;
                node.isChildrenLoading = false;
                node.children = [{
                    id: '1.1',
                    name: 'Node 1.1',
                    isChildrenLoaded: true
                }, {
                    id: '1.2',
                    name: 'Node 1.2',
                    isChildrenLoaded: true
                }];
                let theComponent = me.refs['dualTree_3'];
                theComponent.setLeftTreeExpandedTreeNodeId(
                    _.extend({1: true}, theComponent.refs.leftTree.state.expandedTreeId)
                );
                cb && cb(node);
                me.forceUpdate();
            }, 1000);

            return node;
        }

        // the async one
        function asyncOnTreeNodeExpandClicked(e, treeNode, parentTreeNodes) {
            if (treeNode.isChildrenLoaded) {
                alertEvents('expand', e, treeNode, parentTreeNodes);
                return;
            }

            e.preventDefault();

            asyncLoad();
        }

        function asyncOnTreeNodeOperationClicked(e, treeNode, parentTreeNodes) {
            if (treeNode.isChildrenLoaded) {
                alertEvents('expand', e, treeNode, parentTreeNodes);
                return;
            }

            e.preventDefault();

            asyncLoad(node => {
                onChange(null, treeTools.selectTreeNode(node, parentTreeNodes, items[3].props.value), 3);
            });

            me.forceUpdate();
        }

        function onChange(e, value, index) {
            let props = items[index].props;
            let theComponent = me.refs['dualTree_' + index];
            let expandedTreeNodeId = treeTools.getExpandedTreeNodeIdAfterSelect(theComponent, props.value, value);
            theComponent.setRightTreeExpandedTreeNodeId(expandedTreeNodeId);
            props.rightTreeSummary = treeTools.countSelectedLeaf(props.treeNodes, value) + '';
            props.value = value;
            me.props.alert('onChange' + ' | ' + JSON.stringify(value));
            me.forceUpdate();
        }

        for (let i = 0; i < items.length; i++) {
            let item = items[i];
            let prop = item.props;
            if (i === 3) {
                // async
                prop.onLeftTreeNodeExpandClicked = asyncOnTreeNodeExpandClicked;
                prop.onLeftTreeNodeOperationClicked = asyncOnTreeNodeOperationClicked;
                prop.onChange = _.partial(onChange, _, _, i);
            }
            else {
                prop = _.extend({
                    onLeftTreeNodeExpandClicked: _.partial(alertEvents, 'left-expand'),
                    onLeftTreeNodeOperationClicked: _.partial(alertEvents, 'left-oper')
                }, prop);
                prop.onChange = _.partial(onChange, _, _, i);
            }
            prop.ref = 'dualTree_' + i;
            prop.height = 150;
            let conf = JSON.stringify(prop);
            widgets.push(

{item.title}

{conf}

                    <DualTreeSelector {...prop}/>

            );
        }
        return widgets;
    }

    return React.createClass({
        // @override
        getDefaultProps() {
            return {
                demo: 'DualTreeSelector',
                alert() {}
            };
        },
        render() {
            let containerProp = {
                className: 'demo-content',
                style: {
                    display: this.props.demo === 'DualTreeSelector' ? 'block' : 'none'
                }
            };
            return (
{factory(this, items)}
);
        }
    });
});
<commit_msg>add one DualTreeSelector demo case<commit_after>/**
 * @file Tree Demo
 * @author Han Bing Feng (hanbingfeng@)
 */

define(function (require) {
    let React = require('react');
    let _ = require('underscore');
    let DualTreeSelector = require('fcui/DualTreeSelector.jsx');
    let treeTools = require('fcui/core/treeTools.es6');

    let items = [
        {
            title: 'Normal Tree',
            props: {
                treeNodes: [{
                    id: '1',
                    name: 'Node 1',
                    isChildrenLoaded: true
                }, {
                    id: '2',
                    name: 'Node 2',
                    isChildrenLoaded: true
                }],
                value: {}
            }
        },
        {
            title: 'Normal Tree with preset values',
            props: {
                treeNodes: [{
                    id: '1',
                    name: 'Node 1',
                    isChildrenLoaded: true
                }, {
                    id: '2',
                    name: 'Node 2',
                    isChildrenLoaded: true
                }],
                value: {
                    '1': true
                }
            }
        },
        {
            title: 'Tree with children',
            props: {
                treeNodes: [{
                    id: '1',
                    name: 'Node 1 with children',
                    isChildrenLoaded: true,
                    children: [{
                        id: '1.1',
                        name: 'Node 1.1',
                        isChildrenLoaded: true
                    }, {
                        id: '1.2',
                        name: 'Node 1.2',
                        isChildrenLoaded: true
                    }]
                }, {
                    id: '2',
                    name: 'Node 2',
                    isChildrenLoaded: true
                }],
                value: {}
            }
        },
        {
            title: '3-level Tree with children',
            props: {
                treeNodes: [{
                    id: '1',
                    name: 'Node 1 with children',
                    isChildrenLoaded: true,
                    children: [{
                        id: '1.1',
                        name: 'Node 1.1 with children',
                        isChildrenLoaded: true,
                        children: [{
                            id: '1.1.1',
                            name: 'Node 1.1.1',
                            isChildrenLoaded: true
                        }]
                    }, {
                        id: '1.2',
                        name: 'Node 1.2',
                        isChildrenLoaded: true
                    }]
                }, {
                    id: '2',
                    name: 'Node 2',
                    isChildrenLoaded: true
                }],
                value: {}
            }
        },
        {
            title: 'Normal tree with async loading',
            props: {
                treeNodes: [{
                    id: '1',
                    name: 'Node 1 with async loading',
                    isChildrenLoaded: false
                }, {
                    id: '2',
                    name: 'Node 2',
                    isChildrenLoaded: true
                }],
                value: {}
            }
        }
    ];

    function factory(me, items) {
        let widgets = [];
        let omitChildren = _.partial(
            _.omit, _, 'children'
        );
        function alertEvents(eventType, e, treeNode, parentTreeNodes) {
            me.props.alert(
                eventType
                + ' | '
                + JSON.stringify(omitChildren(treeNode))
                + ' | '
                + JSON.stringify(parentTreeNodes.map(omitChildren))
            );
        }

        function asyncLoad(cb) {
            let node = items[3].props.treeNodes[0];
            node.isChildrenLoading = true;

            me.forceUpdate();

            setTimeout(() => {
                node.isChildrenLoaded = true;
                node.isChildrenLoading = false;
                node.children = [{
                    id: '1.1',
                    name: 'Node 1.1',
                    isChildrenLoaded: true
                }, {
                    id: '1.2',
                    name: 'Node 1.2',
                    isChildrenLoaded: true
                }];
                let theComponent = me.refs['dualTree_3'];
                theComponent.setLeftTreeExpandedTreeNodeId(
                    _.extend({1: true}, theComponent.refs.leftTree.state.expandedTreeId)
                );
                cb && cb(node);
                me.forceUpdate();
            }, 1000);

            return node;
        }

        // the async one
        function asyncOnTreeNodeExpandClicked(e, treeNode, parentTreeNodes) {
            if (treeNode.isChildrenLoaded) {
                alertEvents('expand', e, treeNode, parentTreeNodes);
                return;
            }

            e.preventDefault();

            asyncLoad();
        }

        function asyncOnTreeNodeOperationClicked(e, treeNode, parentTreeNodes) {
            if (treeNode.isChildrenLoaded) {
                alertEvents('expand', e, treeNode, parentTreeNodes);
                return;
            }

            e.preventDefault();

            asyncLoad(node => {
                onChange(null, treeTools.selectTreeNode(node, parentTreeNodes, items[3].props.value), 3);
            });

            me.forceUpdate();
        }

        function onChange(e, value, index) {
            let props = items[index].props;
            let theComponent = me.refs['dualTree_' + index];
            let expandedTreeNodeId = treeTools.getExpandedTreeNodeIdAfterSelect(theComponent, props.value, value);
            theComponent.setRightTreeExpandedTreeNodeId(expandedTreeNodeId);
            props.rightTreeSummary = treeTools.countSelectedLeaf(props.treeNodes, value) + '';
            props.value = value;
            me.props.alert('onChange' + ' | ' + JSON.stringify(value));
            me.forceUpdate();
        }

        for (let i = 0; i < items.length; i++) {
            let item = items[i];
            let prop = item.props;
            if (i === 3) {
                // async
                prop.onLeftTreeNodeExpandClicked = asyncOnTreeNodeExpandClicked;
                prop.onLeftTreeNodeOperationClicked = asyncOnTreeNodeOperationClicked;
                prop.onChange = _.partial(onChange, _, _, i);
            }
            else {
                prop = _.extend({
                    onLeftTreeNodeExpandClicked: _.partial(alertEvents, 'left-expand'),
                    onLeftTreeNodeOperationClicked: _.partial(alertEvents, 'left-oper')
                }, prop);
                prop.onChange = _.partial(onChange, _, _, i);
            }
            prop.ref = 'dualTree_' + i;
            prop.height = 150;
            let conf = JSON.stringify(prop);
            widgets.push(

{item.title}

{conf}

                    <DualTreeSelector {...prop}/>

            );
        }
        return widgets;
    }

    return React.createClass({
        // @override
        getDefaultProps() {
            return {
                demo: 'DualTreeSelector',
                alert() {}
            };
        },
        render() {
            let containerProp = {
                className: 'demo-content',
                style: {
                    display: this.props.demo === 'DualTreeSelector' ? 'block' : 'none'
                }
            };
            return (
{factory(this, items)}
);
        }
    });
});
<|endoftext|>