<commit_before>import Component from '@ember/component';
import $ from 'jquery';
import coughDropExtras from '../utils/extras';
import app_state from '../utils/app_state';
import modal from '../utils/modal';
import capabilities from '../utils/capabilities';
import i18n from '../utils/i18n';
import { computed } from '@ember/object';

export default Component.extend({
  tagName: 'span',
  didInsertElement: function() {
    if(this.get('utterance') && this.get('utterance').check_for_large_image_url) {
      this.get('utterance').check_for_large_image_url();
    }
    this.check_native_shares();
  },
  check_native_shares: function() {
    var _this = this;
    _this.set('native', {});
    capabilities.sharing.available().then(function(list) {
      if(list.indexOf('facebook') != -1) { _this.set('native.facebook', true); }
      if(list.indexOf('twitter') != -1) { _this.set('native.twitter', true); }
      if(list.indexOf('instagram') != -1) { _this.set('native.instagram', true); }
      if(list.indexOf('email') != -1) { _this.set('native.email', true); }
      if(list.indexOf('clipboard') != -1) { _this.set('native.clipboard', true); }
      if(list.indexOf('generic') != -1) { _this.set('native.generic', true); }
    });
  },
  facebook_enabled: computed('url', 'native.generic', 'native.facebook', function() {
    return !!(this.get('url') && (!this.get('native.generic') || this.get('native.facebook')));
  }),
  twitter_enabled: computed('url', 'native.generic', 'native.twitter', function() {
    return !!(this.get('url') && (!this.get('native.generic') || this.get('native.twitter')));
  }),
  email_enabled: computed('text', function() {
    return !!this.get('text');
  }),
  instagram_enabled: computed('url', 'native.instagram', 'utterance.best_image_url', function() {
    return !!(this.get('url') && this.get('native.instagram') && this.get('utterance.best_image_url'));
  }),
  clipboard_enabled: computed('native.clipboard', function() {
    if(document.queryCommandSupported && document.queryCommandSupported('copy')) {
      return true;
    } else {
      return !!this.get('native.clipboard');
    }
  }),
  generic_enabled: computed('url', 'native.generic', function() {
    return !!(this.get('url') && this.get('native.generic'));
  }),
  facebook_url: computed('url', function() {
    return 'https://www.facebook.com/sharer/sharer.php?u=' + encodeURIComponent(this.get('url'));
  }),
  twitter_url: computed('url', 'text', function() {
    var res = 'https://twitter.com/intent/tweet?url=' + encodeURIComponent(this.get('url')) + '&text=' + encodeURIComponent(this.get('text'));
    if(app_state.get('domain_settings.twitter_handle')) {
      res = res + '&related=' + encodeURIComponent(app_state.get('domain_settings.twitter_handle'));
    }
    return res;
  }),
  actions: {
    message: function(supervisor) {
      modal.open('confirm-notify-user', {user: supervisor, utterance: this.get('utterance'), sentence: this.get('utterance.sentence')});
    },
    share_via: function(medium) {
      if(this.get('native.' + medium)) {
        // TODO: download the image locally first??
        capabilities.sharing.share(medium, this.get('text'), this.get('url'), this.get('utterance.best_image_url'));
      } else if(medium == 'facebook') {
        capabilities.window_open(this.get('facebook_url'));
      } else if(medium == 'twitter') {
        capabilities.window_open(this.get('twitter_url'));
      } else if(medium == 'email') {
        modal.open('share-email', {url: this.get('url'), text: this.get('text'), utterance_id: this.get('utterance.id') });
      } else if(medium == 'clipboard' && this.get('clipboard_enabled')) {
        var $elem = $("#" + this.get('element_id'));
        window.getSelection().removeAllRanges();
        var text = $elem[0].innerText;
        if($elem[0].tagName == 'INPUT') {
          $elem.focus().select();
          text = $elem.val();
        } else {
          var range = document.createRange();
          range.selectNode($elem[0]);
          window.getSelection().addRange(range);
        }
        var res = document.execCommand('copy');
        if(!res) {
          var textArea = document.createElement('textArea');
          textArea.value = text;
          document.body.appendChild(textArea);
          var range = document.createRange();
          range.selectNodeContents(textArea);
          var selection = window.getSelection();
          selection.removeAllRanges();
          selection.addRange(range);
          textArea.setSelectionRange(0, 999999);
          res = document.execCommand('copy');
          document.body.removeChild(textArea);
        }
        window.getSelection().removeAllRanges();
        this.sendAction('copy_event', !!res);
      }
    }
  }
});<commit_msg>support native clipboard<commit_after>import Component from '@ember/component';
import $ from 'jquery';
import coughDropExtras from '../utils/extras';
import app_state from '../utils/app_state';
import modal from '../utils/modal';
import capabilities from '../utils/capabilities';
import i18n from '../utils/i18n';
import { computed } from '@ember/object';

export default Component.extend({
  tagName: 'span',
  didInsertElement: function() {
    if(this.get('utterance') && this.get('utterance').check_for_large_image_url) {
      this.get('utterance').check_for_large_image_url();
    }
    this.check_native_shares();
  },
  check_native_shares: function() {
    var _this = this;
    _this.set('native', {});
    capabilities.sharing.available().then(function(list) {
      if(list.indexOf('facebook') != -1) { _this.set('native.facebook', true); }
      if(list.indexOf('twitter') != -1) { _this.set('native.twitter', true); }
      if(list.indexOf('instagram') != -1) { _this.set('native.instagram', true); }
      if(list.indexOf('email') != -1) { _this.set('native.email', true); }
      if(list.indexOf('clipboard') != -1) { _this.set('native.clipboard', true); }
      if(list.indexOf('generic') != -1) { _this.set('native.generic', true); }
    });
  },
  facebook_enabled: computed('url', 'native.generic', 'native.facebook', function() {
    return !!(this.get('url') && (!this.get('native.generic') || this.get('native.facebook')));
  }),
  twitter_enabled: computed('url', 'native.generic', 'native.twitter', function() {
    return !!(this.get('url') && (!this.get('native.generic') || this.get('native.twitter')));
  }),
  email_enabled: computed('text', function() {
    return !!this.get('text');
  }),
  instagram_enabled: computed('url', 'native.instagram', 'utterance.best_image_url', function() {
    return !!(this.get('url') && this.get('native.instagram') && this.get('utterance.best_image_url'));
  }),
  clipboard_enabled: computed('native.clipboard', function() {
    if(document.queryCommandSupported && document.queryCommandSupported('copy')) {
      return true;
    } else {
      return !!this.get('native.clipboard');
    }
  }),
  generic_enabled: computed('url', 'native.generic', function() {
    return !!(this.get('url') && this.get('native.generic'));
  }),
  facebook_url: computed('url', function() {
    return 'https://www.facebook.com/sharer/sharer.php?u=' + encodeURIComponent(this.get('url'));
  }),
  twitter_url: computed('url', 'text', function() {
    var res = 'https://twitter.com/intent/tweet?url=' + encodeURIComponent(this.get('url')) + '&text=' + encodeURIComponent(this.get('text'));
    if(app_state.get('domain_settings.twitter_handle')) {
      res = res + '&related=' + encodeURIComponent(app_state.get('domain_settings.twitter_handle'));
    }
    return res;
  }),
  actions: {
    message: function(supervisor) {
      modal.open('confirm-notify-user', {user: supervisor, utterance: this.get('utterance'), sentence: this.get('utterance.sentence')});
    },
    share_via: function(medium) {
      if(this.get('native.' + medium)) {
        // TODO: download the image locally first??
        capabilities.sharing.share(medium, this.get('text'), this.get('url'), this.get('utterance.best_image_url'));
      } else if(medium == 'facebook') {
        capabilities.window_open(this.get('facebook_url'));
      } else if(medium == 'twitter') {
        capabilities.window_open(this.get('twitter_url'));
      } else if(medium == 'email') {
        modal.open('share-email', {url: this.get('url'), text: this.get('text'), utterance_id: this.get('utterance.id') });
      } else if(medium == 'clipboard' && this.get('clipboard_enabled')) {
        var res = false
        if(this.get('native.clipboard')) {
          capabilities.sharing.share('clipboard', this.get('text'));
          res = true;
        }
        if(!res) {
          var $elem = $("#" + this.get('element_id'));
          window.getSelection().removeAllRanges();
          var text = $elem[0].innerText;
          if($elem[0].tagName == 'INPUT') {
            $elem.focus().select();
            text = $elem.val();
          } else {
            var range = document.createRange();
            range.selectNode($elem[0]);
            window.getSelection().addRange(range);
          }
          res = document.execCommand('copy');
          if(!res) {
            var textArea = document.createElement('textArea');
            textArea.value = text;
            document.body.appendChild(textArea);
            var range = document.createRange();
            range.selectNodeContents(textArea);
            var selection = window.getSelection();
            selection.removeAllRanges();
            selection.addRange(range);
            textArea.setSelectionRange(0, 999999);
            res = document.execCommand('copy');
            document.body.removeChild(textArea);
          }
          window.getSelection().removeAllRanges();
        }
        this.sendAction('copy_event', !!res);
      }
    }
  }
});<|endoftext|>


<commit_before>import { defaultsDeep } from 'lodash'

const VECTOR_TILE_SERVER = `${window.location.protocol}//${window.location.host}${process.env.VUE_APP_VECTOR_TILE_BASE_URL}`

export const WELLS_SOURCE_ID = 'postgis_ftw.gwells_well_view'
export const WELLS_BASE_AND_ARTESIAN_LAYER_ID = 'wells-with-artesian'
export const WELLS_UNCORRELATED_LAYER_ID = 'wells-uncorrelated'
export const WELLS_EMS_LAYER_ID = 'wells-ems'

export const SEARCHED_WELLS_SOURCE_ID = 'searched-wells'
export const SEARCHED_WELLS_LAYER_ID = 'highlight-wells-with-artesian'

export const FOCUSED_WELLS_SOURCE_ID = 'focused-wells'
export const FOCUSED_WELLS_LAYER_ID = 'focused-wells'
export const FOCUSED_WELLS_ARTESIAN_LAYER_ID = 'focused-wells-artesian'
export const FOCUSED_WELL_IMAGE_ID = 'focused-well-image'
export const FOCUSED_WELL_ARTESIAN_IMAGE_ID = 'focused-artesian-well-image'

export const AQUIFERS_SOURCE_ID = 'postgis_ftw.gwells_aquifer_view'
export const AQUIFERS_LINE_LAYER_ID = 'aquifer-line'
export const AQUIFERS_FILL_LAYER_ID = 'aquifer-fill'

export const DATABC_ROADS_SOURCE_ID = 'DATABC-roads-source'
export const DATABC_ROADS_LAYER_ID = 'DATABC-roads-layer'

export const DATABC_CADASTREL_SOURCE_ID = 'DATABC-cadastrels-source'
export const DATABC_CADASTREL_LAYER_ID = 'DATABC-cadastrels-layer'

export const DATABC_ECOCAT_SOURCE_ID = 'DATABC-ecocat-source'
export const DATABC_ECOCAT_LAYER_ID = 'DATABC-ecocat-layer'

export const DATABC_WATER_LICENCES_SOURCE_ID = 'DATABC-water-licences-source'
export const DATABC_WATER_LICENCES_LAYER_ID = 'DATABC-water-licences-layer'

export const DATABC_OBSERVATION_WELLS_SOURCE_ID = 'DATABC-obswells-source'
export const DATABC_OBSERVATION_WELLS_LAYER_ID = 'DATABC-obswells-layer'

export const DATABC_ROADS_SOURCE = {
  type: 'raster',
  tiles: [
    'https://maps.gov.bc.ca/arcserver/rest/services/Province/roads_wm/MapServer/tile/{z}/{y}/{x}'
  ],
  minzoom: 0,
  maxzoom: 17,
  tileSize: 256
}

export const DATABC_CADASTREL_SOURCE = {
  type: 'raster',
  tiles: [
    'https://openmaps.gov.bc.ca/geo/pub/ows?&service=WMS&request=GetMap&layers=pub%3AWHSE_CADASTRE.PMBC_PARCEL_FABRIC_POLY_SVW&format=image%2Fpng&transparent=true&version=1.1.1&width=256&height=256&srs=EPSG:3857&bbox={bbox-epsg-3857}'
  ],
  minzoom: 14,
  maxzoom: 24,
  tileSize: 256
}

export const DATABC_ECOCAT_SOURCE = {
  type: 'raster',
  tiles: [
    'https://openmaps.gov.bc.ca/geo/pub/ows?&service=WMS&request=GetMap&layers=pub%3AWHSE_FISH.ACAT_REPORT_POINT_PUB_SVW&format=image%2Fpng&transparent=true&version=1.1.1&width=256&height=256&srs=EPSG:3857&bbox={bbox-epsg-3857}'
  ],
  minzoom: 7,
  maxzoom: 24,
  tileSize: 256
}

export const DATABC_WATER_LICENCES_SOURCE = {
  type: 'raster',
  tiles: [
    'https://openmaps.gov.bc.ca/geo/pub/ows?&service=WMS&request=GetMap&layers=pub%3AWHSE_WATER_MANAGEMENT.WLS_WATER_RIGHTS_LICENCES_SV&format=image%2Fpng&transparent=true&version=1.1.1&width=256&height=256&srs=EPSG:3857&bbox={bbox-epsg-3857}'
  ],
  minzoom: 6,
  maxzoom: 24,
  tileSize: 256
}

export const DATABC_OBSERVATION_WELLS_SOURCE = {
  type: 'raster',
  tiles: [
    'https://openmaps.gov.bc.ca/geo/pub/ows?&service=WMS&request=GetMap&layers=pub%3AWHSE_WATER_MANAGEMENT.GW_WATER_WELLS_WRBC_SVW&format=image%2Fpng&transparent=true&version=1.1.1&width=256&height=256&srs=EPSG:3857&bbox={bbox-epsg-3857}&styles=7707'
  ],
  minzoom: 4,
  maxzoom: 24,
  tileSize: 256
}

export const DATABC_ROADS_LAYER = {
  type: 'raster',
  id: DATABC_ROADS_LAYER_ID,
  source: DATABC_ROADS_SOURCE_ID
}

export const DATABC_CADASTREL_LAYER = {
  type: 'raster',
  id: DATABC_CADASTREL_LAYER_ID,
  source: DATABC_CADASTREL_SOURCE_ID
}

export const DATABC_ECOCAT_LAYER = {
  type: 'raster',
  id: DATABC_ECOCAT_LAYER_ID,
  source: DATABC_ECOCAT_SOURCE_ID,
  layout: {
    visibility: 'none'
  }
}

export const DATABC_WATER_LICENCES_LAYER = {
  type: 'raster',
  id: DATABC_WATER_LICENCES_LAYER_ID,
  source: DATABC_WATER_LICENCES_SOURCE_ID,
  layout: {
    visibility: 'none'
  }
}

export const DATABC_OBSERVATION_WELLS_LAYER = {
  type: 'raster',
  id: DATABC_OBSERVATION_WELLS_LAYER_ID,
  source: DATABC_OBSERVATION_WELLS_SOURCE_ID,
  layout: {
    visibility: 'none'
  }
}

export function vectorTileServerUrl (sourceLayerName) {
  return `${VECTOR_TILE_SERVER}${sourceLayerName}/{z}/{x}/{y}.pbf`
}

export function vectorSourceConfig (sourceLayerName, options = {}) {
  return {
    type: 'vector',
    tiles: [ vectorTileServerUrl(sourceLayerName) ],
    minzoom: 4,
    maxzoom: 17,
    ...options
  }
}

function vectorLayerConfig (id, source, painttype, paint = {}, layout = {}) {
  return {
    id,
    source,
    'source-layer': source,
    type: painttype,
    paint,
    layout
  }
}

function layerConfig (id, source, painttype, paint = {}, layout = {}) {
  return {
    id,
    source,
    type: painttype,
    paint,
    layout
  }
}

// Adds mouse event listeners to the map to highlight the hovered aquifer
export function setupAquiferHover (map, aquifersFillLayerId) {
  map.hoveredStateId = null

  map.on('mousemove', aquifersFillLayerId, (e) => {
    if (e.features.length > 0) {
      const newHoveredStateId = e.features[0].id
      if (newHoveredStateId !== map.hoveredStateId) {
        if (map.hoveredStateId) { // un-set hover state on previously hovered asquifer
          toggleAquiferHover(map, map.hoveredStateId, false)
        }

        toggleAquiferHover(map, newHoveredStateId, true)
        map.hoveredStateId = newHoveredStateId
      }
    }
  })

  // When the mouse leaves the state-fill layer, update the un-set the hover state of the
  // previously hovered aquifer.
  map.on('mouseleave', aquifersFillLayerId, () => {
    if (map.hoveredStateId) {
      toggleAquiferHover(map, map.hoveredStateId, false)
    }
    map.hoveredStateId = null
  })
}

export function toggleAquiferHover (map, aquiferId, hoveredState) {
  map.setFeatureState(
    { source: AQUIFERS_SOURCE_ID, id: aquiferId, sourceLayer: AQUIFERS_SOURCE_ID },
    { hover: hoveredState }
  )
}

// Builds MapBox layer config object for wells with artesian ones with a fuchsia outline
export function wellsBaseAndArtesianLayer (options = {}) {
  const layerId = options.id || WELLS_BASE_AND_ARTESIAN_LAYER_ID
  const styles = defaultsDeep(options.styles, {
    'circle-color': [
      'case',
      ['to-boolean', ['get', 'artesian']], '#1099FE',
      '#0162FE'
    ],
    'circle-radius': 3,
    'circle-stroke-color': [
      'case',
      ['to-boolean', ['get', 'artesian']], '#EE14CA',
      'transparent'
    ],
    'circle-stroke-width': 1
  })

  return vectorLayerConfig(layerId, options.source || WELLS_SOURCE_ID, options.layerType || 'circle', styles, options.layout)
}

// Builds MapBox layer config object for searched wells with artesian ones with a fuchsia outline
export function searchedWellsLayer (options = {}) {
  const layerId = options.id || SEARCHED_WELLS_LAYER_ID
  const styles = defaultsDeep(options.styles, {
    'circle-color': [
      'case',
      ['>', ['to-number', ['get', 'artesian_flow']], 0], '#1099FE',
      '#0162FE'
    ],
    'circle-radius': 5,
    'circle-stroke-color': [
      'case',
      ['>', ['to-number', ['get', 'artesian_flow']], 0], '#EE14CA',
      'black'
    ],
    'circle-stroke-width': 2
  })

  return layerConfig(layerId, options.source || SEARCHED_WELLS_SOURCE_ID, options.layerType || 'circle', styles, options.layout)
}

// Builds MapBox layer config object for focus wells (and artesian) images that pulse
export function focusedWellsLayer (options = {}) {
  const layerId = options.id || FOCUSED_WELLS_LAYER_ID
  const layout = defaultsDeep(options.layout, {
    'icon-image': [
      'case',
      ['>', ['to-number', ['get', 'artesian_flow']], 0], FOCUSED_WELL_ARTESIAN_IMAGE_ID,
      FOCUSED_WELL_IMAGE_ID
    ]
  })

  return layerConfig(layerId, options.source || FOCUSED_WELLS_SOURCE_ID, options.layerType || 'symbol', options.styles, layout)
}

// Builds MapBox layer config object for wells that are uncorrelated to any aquifer
export function wellsUncorrelatedLayer (options = {}) {
  const layerId = options.id || WELLS_UNCORRELATED_LAYER_ID
  const styles = defaultsDeep(options.styles, {
    'circle-color': [
      'case',
      ['to-boolean', ['get', 'aquifer_id']], 'transparent',
      '#FFFFFF'
    ],
    'circle-radius': 3,
    'circle-stroke-color': '#000',
    'circle-stroke-width': [
      'case',
      ['to-boolean', ['get', 'aquifer_id']], 0,
      1
    ]
  })

  return vectorLayerConfig(layerId, options.source || WELLS_SOURCE_ID, options.layerType || 'circle', styles, options.layout)
}

// Builds MapBox layer config object for wells that have EMS data
export function wellsEmsLayer (options = {}) {
  const layerId = options.id || WELLS_EMS_LAYER_ID
  const styles = defaultsDeep(options.styles, {
    'circle-color': [
      'case',
      ['to-boolean', ['get', 'ems']], '#0CA287',
      'transparent'
    ],
    'circle-radius': 3,
    'circle-stroke-color': '#000',
    'circle-stroke-width': [
      'case',
      ['to-boolean', ['get', 'ems']], 1,
      0
    ]
  })

  return vectorLayerConfig(layerId, options.source || WELLS_SOURCE_ID, options.layerType || 'circle', styles, options.layout)
}

// Builds MapBox layer config object for aquifer line outlines
export function aquifersLineLayer (options = {}) {
  const layerId = options.id || AQUIFERS_LINE_LAYER_ID
  const styles = defaultsDeep(options.styles, {
    'line-color': [
      'case',
      ['boolean', ['feature-state', 'focused'], false], 'purple',
      ['boolean', ['feature-state', 'selected'], false], 'green',
      ['boolean', ['feature-state', 'searchResult'], false], 'purple',
      '#FF6500'
    ],
    'line-width': [
      'case',
      ['boolean', ['feature-state', 'selected'], false], 2,
      ['boolean', ['feature-state', 'selected'], false], 2,
      1
    ]
  })

  return vectorLayerConfig(layerId, options.source || AQUIFERS_SOURCE_ID, options.layerType || 'line', styles, options.layout)
}

// Builds MapBox layer config object for aquifer fill
export function aquifersFillLayer (options = {}) {
  const layerId = options.id || AQUIFERS_FILL_LAYER_ID
  const styles = defaultsDeep(options.styles, {
    'fill-color': [
      'case',
      ['boolean', ['feature-state', 'focused'], false], 'purple',
      ['boolean', ['feature-state', 'selected'], false], 'green',
      ['boolean', ['feature-state', 'searchResult'], false], 'purple',
      '#FF6500'
    ],
    'fill-opacity': [
      'case',
      ['boolean', ['feature-state', 'hover'], false], 0.3,
      0.1
    ]
  })

  return vectorLayerConfig(layerId, options.source || AQUIFERS_SOURCE_ID, options.layerType || 'fill', styles, options.layout)
}
<commit_msg>Adds ?env= param to roads tile for CORS bug WATER-1183<commit_after>import { defaultsDeep } from 'lodash'

const VECTOR_TILE_SERVER = `${window.location.protocol}//${window.location.host}${process.env.VUE_APP_VECTOR_TILE_BASE_URL}`

export const WELLS_SOURCE_ID = 'postgis_ftw.gwells_well_view'
export const WELLS_BASE_AND_ARTESIAN_LAYER_ID = 'wells-with-artesian'
export const WELLS_UNCORRELATED_LAYER_ID = 'wells-uncorrelated'
export const WELLS_EMS_LAYER_ID = 'wells-ems'

export const SEARCHED_WELLS_SOURCE_ID = 'searched-wells'
export const SEARCHED_WELLS_LAYER_ID = 'highlight-wells-with-artesian'

export const FOCUSED_WELLS_SOURCE_ID = 'focused-wells'
export const FOCUSED_WELLS_LAYER_ID = 'focused-wells'
export const FOCUSED_WELLS_ARTESIAN_LAYER_ID = 'focused-wells-artesian'
export const FOCUSED_WELL_IMAGE_ID = 'focused-well-image'
export const FOCUSED_WELL_ARTESIAN_IMAGE_ID = 'focused-artesian-well-image'

export const AQUIFERS_SOURCE_ID = 'postgis_ftw.gwells_aquifer_view'
export const AQUIFERS_LINE_LAYER_ID = 'aquifer-line'
export const AQUIFERS_FILL_LAYER_ID = 'aquifer-fill'

export const DATABC_ROADS_SOURCE_ID = 'DATABC-roads-source'
export const DATABC_ROADS_LAYER_ID = 'DATABC-roads-layer'

export const DATABC_CADASTREL_SOURCE_ID = 'DATABC-cadastrels-source'
export const DATABC_CADASTREL_LAYER_ID = 'DATABC-cadastrels-layer'

export const DATABC_ECOCAT_SOURCE_ID = 'DATABC-ecocat-source'
export const DATABC_ECOCAT_LAYER_ID = 'DATABC-ecocat-layer'

export const DATABC_WATER_LICENCES_SOURCE_ID = 'DATABC-water-licences-source'
export const DATABC_WATER_LICENCES_LAYER_ID = 'DATABC-water-licences-layer'

export const DATABC_OBSERVATION_WELLS_SOURCE_ID = 'DATABC-obswells-source'
export const DATABC_OBSERVATION_WELLS_LAYER_ID = 'DATABC-obswells-layer'

export const DATABC_ROADS_SOURCE = {
  type: 'raster',
  tiles: [
    // NOTE: added ?env= param because of WATER-1183
    `https://maps.gov.bc.ca/arcserver/rest/services/Province/roads_wm/MapServer/tile/{z}/{y}/{x}?env=${window.location.hostname}`
  ],
  minzoom: 0,
  maxzoom: 17,
  tileSize: 256
}

export const DATABC_CADASTREL_SOURCE = {
  type: 'raster',
  tiles: [
    'https://openmaps.gov.bc.ca/geo/pub/ows?&service=WMS&request=GetMap&layers=pub%3AWHSE_CADASTRE.PMBC_PARCEL_FABRIC_POLY_SVW&format=image%2Fpng&transparent=true&version=1.1.1&width=256&height=256&srs=EPSG:3857&bbox={bbox-epsg-3857}'
  ],
  minzoom: 14,
  maxzoom: 24,
  tileSize: 256
}

export const DATABC_ECOCAT_SOURCE = {
  type: 'raster',
  tiles: [
    'https://openmaps.gov.bc.ca/geo/pub/ows?&service=WMS&request=GetMap&layers=pub%3AWHSE_FISH.ACAT_REPORT_POINT_PUB_SVW&format=image%2Fpng&transparent=true&version=1.1.1&width=256&height=256&srs=EPSG:3857&bbox={bbox-epsg-3857}'
  ],
  minzoom: 7,
  maxzoom: 24,
  tileSize: 256
}

export const DATABC_WATER_LICENCES_SOURCE = {
  type: 'raster',
  tiles: [
    'https://openmaps.gov.bc.ca/geo/pub/ows?&service=WMS&request=GetMap&layers=pub%3AWHSE_WATER_MANAGEMENT.WLS_WATER_RIGHTS_LICENCES_SV&format=image%2Fpng&transparent=true&version=1.1.1&width=256&height=256&srs=EPSG:3857&bbox={bbox-epsg-3857}'
  ],
  minzoom: 6,
  maxzoom: 24,
  tileSize: 256
}

export const DATABC_OBSERVATION_WELLS_SOURCE = {
  type: 'raster',
  tiles: [
    'https://openmaps.gov.bc.ca/geo/pub/ows?&service=WMS&request=GetMap&layers=pub%3AWHSE_WATER_MANAGEMENT.GW_WATER_WELLS_WRBC_SVW&format=image%2Fpng&transparent=true&version=1.1.1&width=256&height=256&srs=EPSG:3857&bbox={bbox-epsg-3857}&styles=7707'
  ],
  minzoom: 4,
  maxzoom: 24,
  tileSize: 256
}

export const DATABC_ROADS_LAYER = {
  type: 'raster',
  id: DATABC_ROADS_LAYER_ID,
  source: DATABC_ROADS_SOURCE_ID
}

export const DATABC_CADASTREL_LAYER = {
  type: 'raster',
  id: DATABC_CADASTREL_LAYER_ID,
  source: DATABC_CADASTREL_SOURCE_ID
}

export const DATABC_ECOCAT_LAYER = {
  type: 'raster',
  id: DATABC_ECOCAT_LAYER_ID,
  source: DATABC_ECOCAT_SOURCE_ID,
  layout: {
    visibility: 'none'
  }
}

export const DATABC_WATER_LICENCES_LAYER = {
  type: 'raster',
  id: DATABC_WATER_LICENCES_LAYER_ID,
  source: DATABC_WATER_LICENCES_SOURCE_ID,
  layout: {
    visibility: 'none'
  }
}

export const DATABC_OBSERVATION_WELLS_LAYER = {
  type: 'raster',
  id: DATABC_OBSERVATION_WELLS_LAYER_ID,
  source: DATABC_OBSERVATION_WELLS_SOURCE_ID,
  layout: {
    visibility: 'none'
  }
}

export function vectorTileServerUrl (sourceLayerName) {
  return `${VECTOR_TILE_SERVER}${sourceLayerName}/{z}/{x}/{y}.pbf`
}

export function vectorSourceConfig (sourceLayerName, options = {}) {
  return {
    type: 'vector',
    tiles: [ vectorTileServerUrl(sourceLayerName) ],
    minzoom: 4,
    maxzoom: 17,
    ...options
  }
}

function vectorLayerConfig (id, source, painttype, paint = {}, layout = {}) {
  return {
    id,
    source,
    'source-layer': source,
    type: painttype,
    paint,
    layout
  }
}

function layerConfig (id, source, painttype, paint = {}, layout = {}) {
  return {
    id,
    source,
    type: painttype,
    paint,
    layout
  }
}

// Adds mouse event listeners to the map to highlight the hovered aquifer
export function setupAquiferHover (map, aquifersFillLayerId) {
  map.hoveredStateId = null

  map.on('mousemove', aquifersFillLayerId, (e) => {
    if (e.features.length > 0) {
      const newHoveredStateId = e.features[0].id
      if (newHoveredStateId !== map.hoveredStateId) {
        if (map.hoveredStateId) { // un-set hover state on previously hovered asquifer
          toggleAquiferHover(map, map.hoveredStateId, false)
        }

        toggleAquiferHover(map, newHoveredStateId, true)
        map.hoveredStateId = newHoveredStateId
      }
    }
  })

  // When the mouse leaves the state-fill layer, update the un-set the hover state of the
  // previously hovered aquifer.
  map.on('mouseleave', aquifersFillLayerId, () => {
    if (map.hoveredStateId) {
      toggleAquiferHover(map, map.hoveredStateId, false)
    }
    map.hoveredStateId = null
  })
}

export function toggleAquiferHover (map, aquiferId, hoveredState) {
  map.setFeatureState(
    { source: AQUIFERS_SOURCE_ID, id: aquiferId, sourceLayer: AQUIFERS_SOURCE_ID },
    { hover: hoveredState }
  )
}

// Builds MapBox layer config object for wells with artesian ones with a fuchsia outline
export function wellsBaseAndArtesianLayer (options = {}) {
  const layerId = options.id || WELLS_BASE_AND_ARTESIAN_LAYER_ID
  const styles = defaultsDeep(options.styles, {
    'circle-color': [
      'case',
      ['to-boolean', ['get', 'artesian']], '#1099FE',
      '#0162FE'
    ],
    'circle-radius': 3,
    'circle-stroke-color': [
      'case',
      ['to-boolean', ['get', 'artesian']], '#EE14CA',
      'transparent'
    ],
    'circle-stroke-width': 1
  })

  return vectorLayerConfig(layerId, options.source || WELLS_SOURCE_ID, options.layerType || 'circle', styles, options.layout)
}

// Builds MapBox layer config object for searched wells with artesian ones with a fuchsia outline
export function searchedWellsLayer (options = {}) {
  const layerId = options.id || SEARCHED_WELLS_LAYER_ID
  const styles = defaultsDeep(options.styles, {
    'circle-color': [
      'case',
      ['>', ['to-number', ['get', 'artesian_flow']], 0], '#1099FE',
      '#0162FE'
    ],
    'circle-radius': 5,
    'circle-stroke-color': [
      'case',
      ['>', ['to-number', ['get', 'artesian_flow']], 0], '#EE14CA',
      'black'
    ],
    'circle-stroke-width': 2
  })

  return layerConfig(layerId, options.source || SEARCHED_WELLS_SOURCE_ID, options.layerType || 'circle', styles, options.layout)
}

// Builds MapBox layer config object for focus wells (and artesian) images that pulse
export function focusedWellsLayer (options = {}) {
  const layerId = options.id || FOCUSED_WELLS_LAYER_ID
  const layout = defaultsDeep(options.layout, {
    'icon-image': [
      'case',
      ['>', ['to-number', ['get', 'artesian_flow']], 0], FOCUSED_WELL_ARTESIAN_IMAGE_ID,
      FOCUSED_WELL_IMAGE_ID
    ]
  })

  return layerConfig(layerId, options.source || FOCUSED_WELLS_SOURCE_ID, options.layerType || 'symbol', options.styles, layout)
}

// Builds MapBox layer config object for wells that are uncorrelated to any aquifer
export function wellsUncorrelatedLayer (options = {}) {
  const layerId = options.id || WELLS_UNCORRELATED_LAYER_ID
  const styles = defaultsDeep(options.styles, {
    'circle-color': [
      'case',
      ['to-boolean', ['get', 'aquifer_id']], 'transparent',
      '#FFFFFF'
    ],
    'circle-radius': 3,
    'circle-stroke-color': '#000',
    'circle-stroke-width': [
      'case',
      ['to-boolean', ['get', 'aquifer_id']], 0,
      1
    ]
  })

  return vectorLayerConfig(layerId, options.source || WELLS_SOURCE_ID, options.layerType || 'circle', styles, options.layout)
}

// Builds MapBox layer config object for wells that have EMS data
export function wellsEmsLayer (options = {}) {
  const layerId = options.id || WELLS_EMS_LAYER_ID
  const styles = defaultsDeep(options.styles, {
    'circle-color': [
      'case',
      ['to-boolean', ['get', 'ems']], '#0CA287',
      'transparent'
    ],
    'circle-radius': 3,
    'circle-stroke-color': '#000',
    'circle-stroke-width': [
      'case',
      ['to-boolean', ['get', 'ems']], 1,
      0
    ]
  })

  return vectorLayerConfig(layerId, options.source || WELLS_SOURCE_ID, options.layerType || 'circle', styles, options.layout)
}

// Builds MapBox layer config object for aquifer line outlines
export function aquifersLineLayer (options = {}) {
  const layerId = options.id || AQUIFERS_LINE_LAYER_ID
  const styles = defaultsDeep(options.styles, {
    'line-color': [
      'case',
      ['boolean', ['feature-state', 'focused'], false], 'purple',
      ['boolean', ['feature-state', 'selected'], false], 'green',
      ['boolean', ['feature-state', 'searchResult'], false], 'purple',
      '#FF6500'
    ],
    'line-width': [
      'case',
      ['boolean', ['feature-state', 'selected'], false], 2,
      ['boolean', ['feature-state', 'selected'], false], 2,
      1
    ]
  })

  return vectorLayerConfig(layerId, options.source || AQUIFERS_SOURCE_ID, options.layerType || 'line', styles, options.layout)
}

// Builds MapBox layer config object for aquifer fill
export function aquifersFillLayer (options = {}) {
  const layerId = options.id || AQUIFERS_FILL_LAYER_ID
  const styles = defaultsDeep(options.styles, {
    'fill-color': [
      'case',
      ['boolean', ['feature-state', 'focused'], false], 'purple',
      ['boolean', ['feature-state', 'selected'], false], 'green',
      ['boolean', ['feature-state', 'searchResult'], false], 'purple',
      '#FF6500'
    ],
    'fill-opacity': [
      'case',
      ['boolean', ['feature-state', 'hover'], false], 0.3,
      0.1
    ]
  })

  return vectorLayerConfig(layerId, options.source || AQUIFERS_SOURCE_ID, options.layerType || 'fill', styles, options.layout)
}
<|endoftext|>


<commit_before>console.log('DadaTube: userscript.js loaded');

$(function () {
    'use strict';

    console.log('DadaTube: userscript.js ready');

    function convertToBoolean(value) {
        return !!value;
    }

    function addGlobalStyle(css) {
        var head, style;

        head = document.getElementsByTagName('head')[0];

        if (!head) {
            throw 'no head?!';
        }

        style = document.createElement('style');
        style.type = 'text/css';
        style.innerHTML = css;

        head.appendChild(style);

        console.log('DadaTube: added css', css);
    }

    function makeCss(selector, rules) {
        var rulesCss = $.map(rules, function (value, key) {
            return key + ': ' + value;
        }).join('; ');

        return selector + '{' + rulesCss + '}';
    }

    /**
     * Show/hide hidables in the view
     */
    var hidableView = {
        hide: function ($hidables, onComplete) {
            $hidables.addClass(hiddenClass);

            if (onComplete) {
                onComplete();
            }
        },
        show: function ($hidables, onComplete) {
            $hidables.removeClass(hiddenClass);

            if (onComplete) {
                onComplete();
            }
        }
    };

    var hidablesController = {
        showAll: function () {
            hidablesController.show($hidables);
        },
        hideAll: function () {
            hidablesController.hide($hidables);
        },
        show: function ($hidables) {
            $hidables.each(function () {
                hidablesStorage.remove(identifyHidable($(this)));
            });

            hidableView.show($hidables);
        },
        hide: function ($hidables) {
            $hidables.each(function () {
                hidablesStorage.add(identifyHidable($(this)));
            });

            hidableView.hide($hidables);
        },
        /**
         * @param {jQuery} $hidable
         */
        toggleVisibility: function ($hidable) {
            if ($hidable.hasClass(hiddenClass)) {
                hidablesController.show($hidable);
            } else {
                hidablesController.hide($hidable);
            }
        }
    };

    var HidablesStorage = function (prefix) {
        this.has = function (id, callback) {
            if (!id) {
                throw 'DadaTube: HidablesStorage: id must not be empty';
            }

            var storageKey = prefix + id;

            ldb.get(storageKey, function (value) {
                console.log('DadaTube: HidablesStorage.get', storageKey, value);

                callback(convertToBoolean(value));
            });
        };

        this.add = function (id) {
            console.log('DadaTube: HidablesStorage.add(' + id + ') called');

            var storageKey = prefix + id;

            ldb.set(storageKey, (new Date()).toJSON());

            ldb.get(storageKey, function (value) {
                console.log('DadaTube: value for "' + storageKey + '" was set: "' + value + '"');
            });
        };

        this.remove = function (id) {
            this.has(id, function (has) {
                if (has) {
                    ldb.set(prefix + id, null);
                }
            });
        };
    };

    /**
     * @param {jQuery} $items
     * @param {function} filterCallback
     * @param {function} returnCallback
     */
    function jQueryLazyFilter($items, filterCallback, returnCallback) {
        var $itemsToKeep = $();

        var itemsLength = $items.length;
        var itemsProcessed = 0;

        $items.each(function (index, item) {
            var $item = $(item);

            filterCallback($item, function (shouldBeKeptInResult) {
                itemsProcessed++;

                if (shouldBeKeptInResult) {
                    $itemsToKeep = $itemsToKeep.add($item);
                }

                if (itemsProcessed === itemsLength) {
                    returnCallback($itemsToKeep);
                }
            });
        });
    }

    /**
     * @param {HidablesStorage} hidablesStorage
     * @param {function} callback
     */
    function selectHidablesFromStorage(hidablesStorage, callback) {
        jQueryLazyFilter(
            $hidables,
            function filterCallback($hidable, callback) {
                hidablesStorage.has(identifyHidable($hidable), callback);
            },
            callback
        );
    }

    /**
     * Gets hidable identifying data
     */
    function identifyHidable($hidable) {
        var $onSingleVideoRelated = $hidable.find('a.thumb-link');

        if (1 === $onSingleVideoRelated.length) {
            return $onSingleVideoRelated
                .attr('href')
                .match('/watch\\?v=(.*)')[1];
        }

        var $onHomepage = $hidable.find('a.yt-uix-sessionlink:first');

        if (1 === $onHomepage.length) {
            return $onHomepage
                .attr('href')
                .match('/watch\\?v=(.*)')[1];
        }

        throw {
            'message': 'Could not identify hidable',
            '$hidable': $hidable,
            '$onSingleVideoRelated': $onSingleVideoRelated,
            '$onHomepage': $onHomepage
        };
    }

    function hideItemsInStorage(hidablesStorage, hidableView) {
        selectHidablesFromStorage(hidablesStorage, function ($found) {
            console.log('DadaTube: found to remove on start', $found);

            hidableView.hide($found);

            $found.each(function () {
                var $hidable = $(this);

                console.log('DadaTube: hiding on start', identifyHidable($hidable));

                hidableView.hide($hidable);
                // $found.remove();
            });
        });
    }

    var options = {
        hiddenOpacity: 0.3
    };

    var hiddenClass = 'dnthHidden';

    addGlobalStyle(makeCss('.' + hiddenClass, {
        border: '1px solid red',
        // opacity: options.hiddenOpacity,
        transition: 'opacity 0.2s ease-in-out'
    }));

    /**
     * Hidables IDs storage helper.
     * Keys have prefix to avoid collisions and easily find items.
     * Keys hold hidable IDs, values have the date they were hidden.
     */
    var hidablesStorage = new HidablesStorage('dnthHiddenHidable_');

    /**
     * Items to hide
     */
    var $hidables = $();

    // related items on single video page
    // first item is a playlist, we skip it
    $hidables = $hidables.add('#watch-related .related-list-item:not(:first-child)');

    // recommended on homepage
    $hidables = $hidables.add('.yt-lockup-video');

    // $hidables.each(function () {
    //     console.log('hidable on start', identifyHidable($(this)));
    // }).css('opacity', '0.2');

    /**
     * Clicking on a table row (hidable), hides it.
     */
    $hidables.click(function () {
        console.log('DadaTube: hidable clicked');

        hidablesController.toggleVisibility($(this));
    });

    /**
     * Page loaded: removing elements already hidden and saved to localStorage
     */
    hideItemsInStorage(hidablesStorage, hidableView);

    $('<button>hide all and close</button>')
        .addClass('yt-uix-button yt-uix-button-size-default yt-uix-button-expander')
        .insertAfter('#watch-more-related-button')
        .click(function () {
            hidablesController.hideAll();

            window.close();
        });

    /**
     * When switched from other window/tab,
     * we hide items that could have been hidden on other windows/tabs.
     */
    $(window).on('focus', function () {
        hideItemsInStorage(hidablesStorage, hidableView);
    });
});
<commit_msg>always logging hidables on start<commit_after>console.log('DadaTube: userscript.js loaded');

$(function () {
    'use strict';

    console.log('DadaTube: userscript.js ready');

    function convertToBoolean(value) {
        return !!value;
    }

    function addGlobalStyle(css) {
        var head, style;

        head = document.getElementsByTagName('head')[0];

        if (!head) {
            throw 'no head?!';
        }

        style = document.createElement('style');
        style.type = 'text/css';
        style.innerHTML = css;

        head.appendChild(style);

        console.log('DadaTube: added css', css);
    }

    function makeCss(selector, rules) {
        var rulesCss = $.map(rules, function (value, key) {
            return key + ': ' + value;
        }).join('; ');

        return selector + '{' + rulesCss + '}';
    }

    /**
     * Show/hide hidables in the view
     */
    var hidableView = {
        hide: function ($hidables, onComplete) {
            $hidables.addClass(hiddenClass);

            if (onComplete) {
                onComplete();
            }
        },
        show: function ($hidables, onComplete) {
            $hidables.removeClass(hiddenClass);

            if (onComplete) {
                onComplete();
            }
        }
    };

    var hidablesController = {
        showAll: function () {
            hidablesController.show($hidables);
        },
        hideAll: function () {
            hidablesController.hide($hidables);
        },
        show: function ($hidables) {
            $hidables.each(function () {
                hidablesStorage.remove(identifyHidable($(this)));
            });

            hidableView.show($hidables);
        },
        hide: function ($hidables) {
            $hidables.each(function () {
                hidablesStorage.add(identifyHidable($(this)));
            });

            hidableView.hide($hidables);
        },
        /**
         * @param {jQuery} $hidable
         */
        toggleVisibility: function ($hidable) {
            if ($hidable.hasClass(hiddenClass)) {
                hidablesController.show($hidable);
            } else {
                hidablesController.hide($hidable);
            }
        }
    };

    var HidablesStorage = function (prefix) {
        this.has = function (id, callback) {
            if (!id) {
                throw 'DadaTube: HidablesStorage: id must not be empty';
            }

            var storageKey = prefix + id;

            ldb.get(storageKey, function (value) {
                console.log('DadaTube: HidablesStorage.get', storageKey, value);

                callback(convertToBoolean(value));
            });
        };

        this.add = function (id) {
            console.log('DadaTube: HidablesStorage.add(' + id + ') called');

            var storageKey = prefix + id;

            ldb.set(storageKey, (new Date()).toJSON());

            ldb.get(storageKey, function (value) {
                console.log('DadaTube: value for "' + storageKey + '" was set: "' + value + '"');
            });
        };

        this.remove = function (id) {
            this.has(id, function (has) {
                if (has) {
                    ldb.set(prefix + id, null);
                }
            });
        };
    };

    /**
     * @param {jQuery} $items
     * @param {function} filterCallback
     * @param {function} returnCallback
     */
    function jQueryLazyFilter($items, filterCallback, returnCallback) {
        var $itemsToKeep = $();

        var itemsLength = $items.length;
        var itemsProcessed = 0;

        $items.each(function (index, item) {
            var $item = $(item);

            filterCallback($item, function (shouldBeKeptInResult) {
                itemsProcessed++;

                if (shouldBeKeptInResult) {
                    $itemsToKeep = $itemsToKeep.add($item);
                }

                if (itemsProcessed === itemsLength) {
                    returnCallback($itemsToKeep);
                }
            });
        });
    }

    /**
     * @param {HidablesStorage} hidablesStorage
     * @param {function} callback
     */
    function selectHidablesFromStorage(hidablesStorage, callback) {
        jQueryLazyFilter(
            $hidables,
            function filterCallback($hidable, callback) {
                hidablesStorage.has(identifyHidable($hidable), callback);
            },
            callback
        );
    }

    /**
     * Gets hidable identifying data
     */
    function identifyHidable($hidable) {
        var $onSingleVideoRelated = $hidable.find('a.thumb-link');

        if (1 === $onSingleVideoRelated.length) {
            return $onSingleVideoRelated
                .attr('href')
                .match('/watch\\?v=(.*)')[1];
        }

        var $onHomepage = $hidable.find('a.yt-uix-sessionlink:first');

        if (1 === $onHomepage.length) {
            return $onHomepage
                .attr('href')
                .match('/watch\\?v=(.*)')[1];
        }

        throw {
            'message': 'Could not identify hidable',
            '$hidable': $hidable,
            '$onSingleVideoRelated': $onSingleVideoRelated,
            '$onHomepage': $onHomepage
        };
    }

    function hideItemsInStorage(hidablesStorage, hidableView) {
        selectHidablesFromStorage(hidablesStorage, function ($found) {
            console.log('DadaTube: found to remove on start', $found);

            hidableView.hide($found);

            $found.each(function () {
                var $hidable = $(this);

                console.log('DadaTube: hiding on start', identifyHidable($hidable));

                hidableView.hide($hidable);
                // $found.remove();
            });
        });
    }

    var options = {
        hiddenOpacity: 0.3
    };

    var hiddenClass = 'dnthHidden';

    addGlobalStyle(makeCss('.' + hiddenClass, {
        border: '1px solid red',
        // opacity: options.hiddenOpacity,
        transition: 'opacity 0.2s ease-in-out'
    }));

    /**
     * Hidables IDs storage helper.
     * Keys have prefix to avoid collisions and easily find items.
     * Keys hold hidable IDs, values have the date they were hidden.
     */
    var hidablesStorage = new HidablesStorage('dnthHiddenHidable_');

    /**
     * Items to hide
     */
    var $hidables = $();

    // related items on single video page
    // first item is a playlist, we skip it
    $hidables = $hidables.add('#watch-related .related-list-item:not(:first-child)');

    // recommended on homepage
    $hidables = $hidables.add('.yt-lockup-video');

    $hidables.each(function () {
        console.log('hidable on start', identifyHidable($(this)));
    });

    // $hidables.css('opacity', '0.2');

    /**
     * Clicking on a table row (hidable), hides it.
     */
    $hidables.click(function () {
        console.log('DadaTube: hidable clicked');

        hidablesController.toggleVisibility($(this));
    });

    /**
     * Page loaded: removing elements already hidden and saved to localStorage
     */
    hideItemsInStorage(hidablesStorage, hidableView);

    $('<button>hide all and close</button>')
        .addClass('yt-uix-button yt-uix-button-size-default yt-uix-button-expander')
        .insertAfter('#watch-more-related-button')
        .click(function () {
            hidablesController.hideAll();

            window.close();
        });

    /**
     * When switched from other window/tab,
     * we hide items that could have been hidden on other windows/tabs.
     */
    $(window).on('focus', function () {
        hideItemsInStorage(hidablesStorage, hidableView);
    });
});
<|endoftext|>


<commit_before>// ==UserScript==
// @name        PHP SDK Entity generator
// @namespace   php
// @description Generates php class that can be used in SDK
// @include     https://start.exactonline.nl/docs/HlpRestAPIResourcesDetails.aspx?*
// @version     1
// @grant       none
// ==/UserScript==

(function() {
  var instant_download = false;

  /** Add textarea to display php code **/
  // Push current content to the left.
  $('body > form').css('float', 'left');
  $('body > form').css('width', '50%');
  $('body > form').css('overflow', 'auto');

  // Add textarea to body, css might need some work.
  $('', {
    id : 'php_download',
    text: 'Download Code',
    style: 'margin: 10px; padding: 10px; color: white; background-color: red'
  }).appendTo('body');

  $('

').appendTo('body');

  $('<textarea/>', {
    id : 'php',
    style: 'min-height:800px; width: 47%; margin-left:10px;'
  }).appendTo('body');

  /** Initialize variables **/
  var primarykey = 'ID';
  var data = {};
  // Fetch entity URL and strip '/api/v1/{division}/'
  var url = $('#serviceUri').text().replace(/^\/api\/v[0-9]\/[^/]+\//, '');
  var classname = url.replace(/.+\/(.+?)s?$/,'$1'); // Last part after slash should be the (plural) classname.
  var mapType = function(type) {
      switch (type.toLowerCase()) {
          case "guid":
          case "datetime":
              return "string";
          case "byte":
          case "int32":
          case "int16":
              return "int";
          case "double":
              return "float";
          case "boolean":
              return "bool";
          default:
              return type.toLowerCase()
      }
  }

  /** Fetch attribute information **/
  $('#referencetable tr input').each(function() {
    data[$(this).attr('name')] = {
      'type' : $(this).attr('data-type').replace('Edm.', ''),
      'description' : $(this).parent().siblings('td:last-child').text().trim()
    };

    // Set primarykey when found. Should be first itteration.
    if ($(this).attr('data-key') == "True") {
      primarykey = $(this).attr('name');
    }
  });

  /** Build php code **/
  phptxt = "<?php\n\nnamespace Picqer\\Financials\\Exact;\n\n/**";

  // Build docblock
  phptxt += "\n * Class " + classname;
  phptxt += "\n *\n * @package Picqer\\Financials\\Exact";
  phptxt += "\n * @see " + window.location.href;
  phptxt += "\n *";
  $.each(data,function(attribute, info){
    phptxt += "\n * @property " + mapType(info.type) + " $" + attribute + " " + info.description;
  });
  phptxt += "\n */";

  // Build class
  phptxt += "\nclass " + classname + " extends Model\n{\n    use Query\\Findable;\n    use Persistance\\Storable;";
  if (primarykey != 'ID') {
    phptxt += "\n\n    protected $primaryKey = '" + primarykey + "';";
  }
  phptxt += "\n\n    protected $fillable = [";
  $.each(Object.keys(data), function(){
    phptxt += "\n        '" + this + "',";
  });
  phptxt += "\n    ];";
  phptxt += "\n\n    protected $url = '" + url + "';";
  phptxt += "\n}\n";

  // Display php code
  $('#php').text(phptxt);

  // Present the php code as a download
  $('#php_download').attr("href",
    URL.createObjectURL(
      new Blob([phptxt], {
        type: "text/plain"
      })
    )
  ).attr('download', classname + '.php');

  if (instant_download)
  {
    $('#php_download')[0].click();
  }
})();
<commit_msg>Fix userscript for docs page with query params in function URI.<commit_after>// ==UserScript==
// @name        PHP SDK Entity generator
// @namespace   php
// @description Generates php class that can be used in SDK
// @include     https://start.exactonline.nl/docs/HlpRestAPIResourcesDetails.aspx?*
// @version     1
// @grant       none
// ==/UserScript==

(function() {
  var instant_download = false;

  /** Add textarea to display php code **/
  // Push current content to the left.
  $('body > form').css('float', 'left');
  $('body > form').css('width', '50%');
  $('body > form').css('overflow', 'auto');

  // Add textarea to body, css might need some work.
  $('', {
    id : 'php_download',
    text: 'Download Code',
    style: 'margin: 10px; padding: 10px; color: white; background-color: red'
  }).appendTo('body');

  $('

').appendTo('body');

  $('<textarea/>', {
    id : 'php',
    style: 'min-height:800px; width: 47%; margin-left:10px;'
  }).appendTo('body');

  /** Initialize variables **/
  var primarykey = 'ID';
  var data = {};
  // Fetch entity URL and strip '/api/v1/{division}/'
  var url = $('#serviceUri').text().replace(/^\/api\/v[0-9]\/[^/]+\//, '');
  // Last part after slash should be the (plural) class name without the query part
  var classname = url.replace(/.+\/(.+?)s?$/,'$1').replace(/\?.*/,'');
  var mapType = function(type) {
      switch (type.toLowerCase()) {
          case "guid":
          case "datetime":
              return "string";
          case "byte":
          case "int32":
          case "int16":
              return "int";
          case "double":
              return "float";
          case "boolean":
              return "bool";
          default:
              return type.toLowerCase()
      }
  }

  /** Fetch attribute information **/
  $('#referencetable tr input').each(function() {
    data[$(this).attr('name')] = {
      'type' : $(this).attr('data-type').replace('Edm.', ''),
      'description' : $(this).parent().siblings('td:last-child').text().trim()
    };

    // Set primarykey when found. Should be first itteration.
    if ($(this).attr('data-key') == "True") {
      primarykey = $(this).attr('name');
    }
  });

  /** Build php code **/
  phptxt = "<?php\n\nnamespace Picqer\\Financials\\Exact;\n\n/**";

  // Build docblock
  phptxt += "\n * Class " + classname;
  phptxt += "\n *\n * @package Picqer\\Financials\\Exact";
  phptxt += "\n * @see " + window.location.href;
  phptxt += "\n *";
  $.each(data,function(attribute, info){
    phptxt += "\n * @property " + mapType(info.type) + " $" + attribute + " " + info.description;
  });
  phptxt += "\n */";

  // Build class
  phptxt += "\nclass " + classname + " extends Model\n{\n    use Query\\Findable;\n    use Persistance\\Storable;";
  if (primarykey != 'ID') {
    phptxt += "\n\n    protected $primaryKey = '" + primarykey + "';";
  }
  phptxt += "\n\n    protected $fillable = [";
  $.each(Object.keys(data), function(){
    phptxt += "\n        '" + this + "',";
  });
  phptxt += "\n    ];";
  phptxt += "\n\n    protected $url = '" + url + "';";
  phptxt += "\n}\n";

  // Display php code
  $('#php').text(phptxt);

  // Present the php code as a download
  $('#php_download').attr("href",
    URL.createObjectURL(
      new Blob([phptxt], {
        type: "text/plain"
      })
    )
  ).attr('download', classname + '.php');

  if (instant_download)
  {
    $('#php_download')[0].click();
  }
})();
<|endoftext|>


<commit_before>/* globals jQuery */
var opg = opg || {};

/**
 * Handles Transfer operations
 * Prototype version. Refactor if needed
 */
(function ($, opg) {
    "use strict";

    var Transfers = function (options) {
        this.that = this;

        this.statusElement = options.statusElement;
        this.removeAtStart = options.removeAtStart;
        this.showAtStart = options.showAtStart;
        this.wrapper = options.wrapper;
        this.saveEndpoint = options.saveEndpoint;
        this.deleteEndpoint = options.deleteEndpoint;
        this.noTransfersEndpoint = options.noTransfersEndpoint;
        this.renderDeleteButtonAfterEndpointCalled = options.renderDeleteButtonAfterEndpointCalled;
        this.noTransferWrapperSelector = options.noTransferWrapperSelector;
        this.noTransferWrapper = $(this.noTransferWrapperSelector);
        this.thereAreNoRecords = options.thereAreNoRecords;
        this.emptyRow = options.emptyRow;
        this.cardSelectionList = options.cardSelectionList;

        this.init();
        this.attachEvents();
        this.attachGlobalEvents();
    };

    Transfers.prototype.isFormValid = function (form) {
        var fromVal = parseInt(form.find('input.account:nth(0)').val());
        var toVal = parseInt(form.find('input.account:nth(1)').val());
        var amountVal = parseFloat(form.find('input[name=amount]').val());
        return fromVal > 0 && toVal > 0 && amountVal > 0 && form.find('input.account').length === 2;
    };

    Transfers.prototype.setStatus = function (text) {
        this.statusElement.text(text);
    };

    Transfers.prototype.init = function () {
        var _this = this.that;

        this.removeAtStart.remove();
        this.showAtStart.show();
    };

    Transfers.prototype.filterCards = function () {

    };

    // find the data.id of the sibling card-item (traverse up to column-one-half)
    Transfers.prototype.getSiblingDataId = function (el) {
        // find sibling
        var column = el.parents('.column-one-half');
        if (column.next().length === 1) {
            return column.next().find('.card-item').data('id');
        } else if (column.prev().length === 1) {
            return column.prev().find('.card-item').data('id');
        }
        return null;
    };

    Transfers.prototype.attachEvents = function () {
        var _this = this.that;

        // show card selection
        this.wrapper.on('click', '.card-item.expandable', function (e) {
            console.log('expand');
            e.stopPropagation();
            var el = $(this);
            var cards = $(_this.cardSelectionList.clone());

            // set grey and last position for the card selected on the other side
            var idSibling = _this.getSiblingDataId(el);
            if (idSibling) {
                cards.find('.card-item').filter(function () {
                    return parseInt($(this).data('id')) === parseInt(idSibling);
                }).appendTo(cards).find('.card').addClass('disabled');
            }

            el.parent('.card-list').html(cards.html());
        });

        // selecting one from list
        this.wrapper.on('click', '.card-item.not-expandable', function (e) {
            console.log('selecting one');
            e.stopPropagation();
            _this.setStatus('');
            var selectedCard = $(this);
            var cardsList = selectedCard.parent('ul.card-list');
            var form = selectedCard.parents('form');

            // remove cards except the selected one
            cardsList.find('li').filter(function () {
                return parseInt($(this).data('id')) !== parseInt(selectedCard.data('id'));
            }).remove();
            // re-add expandable class for future clicks
            cardsList.find('li.not-expandable').addClass('expandable');

            // restore original class
            selectedCard.find('.card').removeClass('disabled');

            _this.saveTransfer(form);
        });

        // when editable fields change
        this.wrapper.on('change', 'input.balance', function (e) {
            _this.setStatus('');
            var form = $(e.target).parents('form');
            _this.saveTransfer(form);
        });

        // noTransfers checkbox click
        this.wrapper.on('click', _this.noTransferWrapperSelector + ' input[type=checkbox]', function () {
            _this.setStatus('');
            var form = $(this).parents('form');

            $.post(_this.noTransferWrapperSelector, form.serialize());
        });

        // on delete
        this.wrapper.on('click', '.delete-button', function (e) {
            _this.setStatus('');
            e.preventDefault();

            var form = $(this).parents('form');
            $.ajax({
                type: "DELETE",
                url: _this.deleteEndpoint,
                data: form.serialize(),
                dataType: "json",
                success: function () {
                    var li = form.parents('li.transfer');
                    li.remove();
                    if (_this.thereAreNoRecords(_this.wrapper)) {
                        _this.noTransferWrapper.show();
                    }
                }
            });
        });

        // disable ENTER key on input boxes
        $('input.balance').bind('keypress', function (e) {
            if (e.keyCode == 13)
            {
                return false;
            }
        });
    };

    Transfers.prototype.attachGlobalEvents = function () {
        var _this = this.that;

        $(document).bind("ajaxSend", function () {
            _this.setStatus('');
        }).bind("ajaxSuccess", function () {
            _this.setStatus('Saved');
        }).bind("ajaxError", function () {
            _this.setStatus('Not saved');
        });
    };

    // save callback
    Transfers.prototype.saveTransfer = function (form) {
        var _this = this.that;

        if (!_this.isFormValid(form)) {
            return;
        }

        var idElement = form.find('input[name=id]');
        var isNewRecord = parseInt(idElement.val()) === 0;

        if (isNewRecord) {
            $.post(_this.saveEndpoint, form.serialize())
                    .success(function (data) {
                        // if a new record is added: set <input name=id > value for future editing, add new empty row, and add delete button
                        idElement.val(data.transferId);
                        _this.addEmptyRow(form.parents('li.transfer'));
                        _this.addDeleteButton(form, data);
                        // remove noTransfers checkbox
                        _this.noTransferWrapper.hide().find('input[type=checkbox]').attr('checked', false);
                    });
        } else {
            $.ajax({
                type: "PUT",
                url: _this.saveEndpoint,
                data: form.serialize(),
                dataType: "json"
            });
        }

    };

    Transfers.prototype.addEmptyRow = function (after) {
        var _this = this.that;

        after.after(_this.emptyRow.html());
    };

    Transfers.prototype.addDeleteButton = function (form, data) {
        var _this = this.that;

        form.find('.delete-button-container').html(_this.renderDeleteButtonAfterEndpointCalled(data));
    };

    opg.Transfers = Transfers;

})(jQuery, opg);
<commit_msg>dd-1419-transfers-1440 refactor<commit_after>/* globals jQuery */
var opg = opg || {};

/**
 * Handles Transfer operations
 * Prototype version. Refactor if needed
 */
(function ($, opg) {
    "use strict";

    var Transfers = function (options) {
        this.that = this;

        this.statusElement = options.statusElement;
        this.removeAtStart = options.removeAtStart;
        this.showAtStart = options.showAtStart;
        this.wrapper = options.wrapper;
        this.saveEndpoint = options.saveEndpoint;
        this.deleteEndpoint = options.deleteEndpoint;
        this.noTransfersEndpoint = options.noTransfersEndpoint;
        this.renderDeleteButtonAfterEndpointCalled = options.renderDeleteButtonAfterEndpointCalled;
        this.noTransferWrapperSelector = options.noTransferWrapperSelector;
        this.noTransferWrapper = $(this.noTransferWrapperSelector);
        this.thereAreNoRecords = options.thereAreNoRecords;
        this.emptyRow = options.emptyRow;
        this.cardSelectionList = options.cardSelectionList;

        this.init();
        this.attachEvents();
        this.attachGlobalEvents();
    };

    Transfers.prototype.isFormValid = function (form) {
        var fromVal = parseInt(form.find('input.account:nth(0)').val());
        var toVal = parseInt(form.find('input.account:nth(1)').val());
        var amountVal = parseFloat(form.find('input[name=amount]').val());
        return fromVal > 0 && toVal > 0 && amountVal > 0 && form.find('input.account').length === 2;
    };

    Transfers.prototype.setStatus = function (text) {
        this.statusElement.text(text);
    };

    Transfers.prototype.init = function () {
        var _this = this.that;

        this.removeAtStart.remove();
        this.showAtStart.show();
    };

    Transfers.prototype.filterCards = function () {

    };

    // find the data.id of the sibling card-item (traverse up to column-one-half)
    Transfers.prototype.getSiblingDataId = function (el) {
        // find sibling
        var column = el.parents('.column-one-half');
        if (column.next().length === 1) {
            return column.next().find('.card-item').data('id');
        } else if (column.prev().length === 1) {
            return column.prev().find('.card-item').data('id');
        }
        return null;
    };

    // find the data.id of the sibling card-item (traverse up to column-one-half)
    Transfers.prototype.getCardsList = function (idSibling) {
        var _this = this.that;

        var cards = $(_this.cardSelectionList.clone());

        // set grey and last position for the card selected on the other side
        if (idSibling) {
            cards.find('.card-item').filter(function () {
                return parseInt($(this).data('id')) === parseInt(idSibling);
            }).appendTo(cards).find('.card').addClass('disabled');
        }

        return cards;
    };

    Transfers.prototype.attachEvents = function () {
        var _this = this.that;

        // show card selection
        this.wrapper.on('click', '.card-item.expandable', function (e) {
            console.log('expand');
            e.stopPropagation();
            var el = $(this);

            var dataIdSelectedBySibling = _this.getSiblingDataId(el);
            var cards = _this.getCardsList(dataIdSelectedBySibling);

            el.parent('.card-list').html(cards.html());
        });

        // selecting one from list
        this.wrapper.on('click', '.card-item.not-expandable', function (e) {
            console.log('selecting one');
            e.stopPropagation();
            _this.setStatus('');
            var selectedCard = $(this);
            var cardsList = selectedCard.parent('ul.card-list');
            var form = selectedCard.parents('form');

            // remove cards except the selected one
            cardsList.find('li').filter(function () {
                return parseInt($(this).data('id')) !== parseInt(selectedCard.data('id'));
            }).remove();
            // re-add expandable class for future clicks
            cardsList.find('li.not-expandable').addClass('expandable');

            // restore original class
            selectedCard.find('.card').removeClass('disabled');

            _this.saveTransfer(form);
        });

        // when editable fields change
        this.wrapper.on('change', 'input.balance', function (e) {
            _this.setStatus('');
            var form = $(e.target).parents('form');
            _this.saveTransfer(form);
        });

        // noTransfers checkbox click
        this.wrapper.on('click', _this.noTransferWrapperSelector + ' input[type=checkbox]', function () {
            _this.setStatus('');
            var form = $(this).parents('form');

            $.post(_this.noTransferWrapperSelector, form.serialize());
        });

        // on delete
        this.wrapper.on('click', '.delete-button', function (e) {
            _this.setStatus('');
            e.preventDefault();

            var form = $(this).parents('form');
            $.ajax({
                type: "DELETE",
                url: _this.deleteEndpoint,
                data: form.serialize(),
                dataType: "json",
                success: function () {
                    var li = form.parents('li.transfer');
                    li.remove();
                    if (_this.thereAreNoRecords(_this.wrapper)) {
                        _this.noTransferWrapper.show();
                    }
                }
            });
        });

        // disable ENTER key on input boxes
        $('input.balance').bind('keypress', function (e) {
            if (e.keyCode == 13)
            {
                return false;
            }
        });
    };

    Transfers.prototype.attachGlobalEvents = function () {
        var _this = this.that;

        $(document).bind("ajaxSend", function () {
            _this.setStatus('');
        }).bind("ajaxSuccess", function () {
            _this.setStatus('Saved');
        }).bind("ajaxError", function () {
            _this.setStatus('Not saved');
        });
    };

    // save callback
    Transfers.prototype.saveTransfer = function (form) {
        var _this = this.that;

        if (!_this.isFormValid(form)) {
            return;
        }

        var idElement = form.find('input[name=id]');
        var isNewRecord = parseInt(idElement.val()) === 0;

        if (isNewRecord) {
            $.post(_this.saveEndpoint, form.serialize())
                    .success(function (data) {
                        // if a new record is added: set <input name=id > value for future editing, add new empty row, and add delete button
                        idElement.val(data.transferId);
                        _this.addEmptyRow(form.parents('li.transfer'));
                        _this.addDeleteButton(form, data);
                        // remove noTransfers checkbox
                        _this.noTransferWrapper.hide().find('input[type=checkbox]').attr('checked', false);
                    });
        } else {
            $.ajax({
                type: "PUT",
                url: _this.saveEndpoint,
                data: form.serialize(),
                dataType: "json"
            });
        }

    };

    Transfers.prototype.addEmptyRow = function (after) {
        var _this = this.that;

        after.after(_this.emptyRow.html());
    };

    Transfers.prototype.addDeleteButton = function (form, data) {
        var _this = this.that;

        form.find('.delete-button-container').html(_this.renderDeleteButtonAfterEndpointCalled(data));
    };

    opg.Transfers = Transfers;

})(jQuery, opg);
<|endoftext|>


<commit_before>/**
 * Created by Freddy on 15/05/14.
 */

(function() {
    var NS = null;

    var __isNode = (typeof module !== 'undefined' && typeof module.exports !== 'undefined');
    if (__isNode) {
        require("./extensions/string.ext.js");

        NS = exports;
    } else {
        //Add to Visionscapers namespace
        NS = window["__VI__"] || window;
    }

    //using underscore.js _ as base object
    //changing and augmenting it where we want to

    NS.extendWithUtils = function (utils, log) {

        if (typeof(log) != "object") {
            console.warn("UtilsBase : no logging object provided, using browser console logger");
            log = console;
        }

        if ((typeof(utils) != "object") && (typeof(utils) != "function")) {
            log.error("UtilsBase", "no valid utils object given, unable to extend");
            return;
        }

        //Using these functions (in the particular way as used below) to ensure that Webstorm (or other IDE) can find
        // the method definition, while still providing feedback when a method already exists

        var _mustNOTexist = function (name) {
            if ((utils[name] !== null) && (utils[name] !== undefined)) {
                log.warn("UtilsBase", "property or method {0} already exists, not overwriting".fmt(name));
            }
        };
        var _mustExist = function (name) {
            if ((utils[name] === null) || (utils[name] === undefined)) {
                log.warn("UtilsBase", "property or method {0} does not exists, will not be available".fmt(name));
            }
        };

        _mustNOTexist("_mustNOTexist");
        utils._mustNOTexist = utils._mustNOTexist || _mustNOTexist;

        _mustNOTexist("_mustExist");
        utils._mustExist = utils._mustExist || _mustExist;

        /**************************************************
         *
         * Register utils component
         *
         **************************************************/

            //Different util components are registered here
            //This allows us to check in a simple way if certain functionality is available
        _mustNOTexist("_utilsComponents");
        utils._utilsComponents = utils._utilsComponents || {
            base: true
        };

        /**************************************************
         *
         * END Register utils component
         *
         **************************************************/

        _mustNOTexist("def");
        utils.def = utils.def || function (v) {
            return ((v !== null) && (v !== undefined));
        };

        _mustNOTexist("obj");
        _mustExist("isObject");
        utils.obj = utils.obj || utils.isObject;

        _mustNOTexist("bool");
        _mustExist("isBoolean");
        utils.bool = utils.bool || utils.isBoolean;

        _mustNOTexist("number");
        _mustExist("isNumber");
        utils.number = utils.number || utils.isNumber;

        _mustNOTexist("string");
        _mustExist("isString");
        utils.string = utils.string || utils.isString;

        _mustNOTexist("array");
        _mustExist("isArray");
        utils.array = utils.array || utils.isArray;

        _mustNOTexist("func");
        _mustExist("isFunction");
        utils.func = utils.func || utils.isFunction;

        _mustNOTexist("date");
        _mustExist("isDate");
        utils.date = utils.date || utils.isDate;

        _mustNOTexist("empty");
        _mustExist("isEmpty");
        utils.empty = utils.empty || utils.isEmpty;

        _mustNOTexist("ensureFunc");
        utils.ensureFunc = utils.ensureFunc || function (f) {
            return (utils.func(f) ? f : function () {
            });
        };

        _mustNOTexist("now");
        utils.now = utils.now || function () {
            return (new Date()).getTime();
        };

        _mustNOTexist("get");
        utils.get = utils.get || function (obj, path, objName) {
            var me = "Utils::get";
            var value = null;

            var describe = !utils.empty(objName);

            if (!utils.obj(obj)) {
                if (describe) {
                    log.error(me, "object {0} is invalid, can't get property {1}".fmt(objName, path));
                }
                return value;
            }

            if (!utils.string(path) || utils.empty(path)) {
                if (describe) {
                    log.error(me, "path to property is invalid, can't get property of {0} object".fmt(objName));
                }
                return value;
            }

            var props = path.split(".");
            var numProps = props.length;
            var prop = null;

            var pathTravelled = "";

            var value = obj;
            for (var idx = 0; idx < numProps; idx++) {
                prop = props[idx];

                if (_.obj(value)) {
                    value = value[prop];
                } else {
                    if (describe) {
                        log.warn(me, "{0} of object {1} is not an object, unable to get property {2}".fmt(
                                pathTravelled,
                                objName,
                                path
                        ));
                    }

                    value = null;
                    break;
                }

                if (describe) {
                    pathTravelled += ((idx > 0) ? '.' : '') + prop;
                }
            }

            return value;
        };

        _mustNOTexist("set");
        utils.set = utils.set || function (obj, path, value, objName) {
            var me = "utils::set";
            var success = false;

            var describe = !utils.empty(objName);

            if (!utils.obj(obj)) {
                if (describe) {
                    log.error(me, "object {0} is invalid, can't set property {1}".fmt(objName, path));
                }
                return success;
            }

            if (!utils.string(path) || utils.empty(path)) {
                if (describe) {
                    log.error(me, "path to property is invalid, can't set property of {0} object".fmt(objName));
                }
                return success;
            }

            var props = path.split(".");
            var numProps = props.length;
            var prop = null;

            var pathTravelled = "";

            var targetObj = obj;
            for (var idx = 0; idx < numProps; idx++) {
                prop = props[idx];

                if (_.obj(targetObj)) {
                    if (idx < numProps - 1) {
                        targetObj = targetObj[prop];
                    } else {
                        success = true;
                        targetObj[prop] = value;
                    }
                } else {
                    if (describe) {
                        log.warn(me, "{0} of object {1} is not an object, unable to set property {2}".fmt(
                                pathTravelled,
                                objName,
                                path
                        ));
                    }

                    break;
                }

                if (describe) {
                    pathTravelled += ((idx > 0) ? '.' : '') + prop;
                }
            }

            return success;
        };

        _mustNOTexist("stringify");
        utils.stringify = utils.stringify || function(obj) {
            var me  = "Utils::stringify";

            var s   = null;
            try {
                s = JSON.stringify(obj);
            } catch(e) {
                log.error(me, "Unable to stringify object : ", utils.get(e, "message"));
                s = "[Unable to stringify object]";
            }

            return s;
        }
    };

})();<commit_msg>Fixed bug in get and set of utils base<commit_after>/**
 * Created by Freddy on 15/05/14.
 */

(function() {
    var NS = null;

    var __isNode = (typeof module !== 'undefined' && typeof module.exports !== 'undefined');
    if (__isNode) {
        require("./extensions/string.ext.js");

        NS = exports;
    } else {
        //Add to Visionscapers namespace
        NS = window["__VI__"] || window;
    }

    //using underscore.js _ as base object
    //changing and augmenting it where we want to

    NS.extendWithUtils = function (utils, log) {

        if (typeof(log) != "object") {
            console.warn("UtilsBase : no logging object provided, using browser console logger");
            log = console;
        }

        if ((typeof(utils) != "object") && (typeof(utils) != "function")) {
            log.error("UtilsBase", "no valid utils object given, unable to extend");
            return;
        }

        //Using these functions (in the particular way as used below) to ensure that Webstorm (or other IDE) can find
        // the method definition, while still providing feedback when a method already exists

        var _mustNOTexist = function (name) {
            if ((utils[name] !== null) && (utils[name] !== undefined)) {
                log.warn("UtilsBase", "property or method {0} already exists, not overwriting".fmt(name));
            }
        };
        var _mustExist = function (name) {
            if ((utils[name] === null) || (utils[name] === undefined)) {
                log.warn("UtilsBase", "property or method {0} does not exists, will not be available".fmt(name));
            }
        };

        _mustNOTexist("_mustNOTexist");
        utils._mustNOTexist = utils._mustNOTexist || _mustNOTexist;

        _mustNOTexist("_mustExist");
        utils._mustExist = utils._mustExist || _mustExist;

        /**************************************************
         *
         * Register utils component
         *
         **************************************************/

            //Different util components are registered here
            //This allows us to check in a simple way if certain functionality is available
        _mustNOTexist("_utilsComponents");
        utils._utilsComponents = utils._utilsComponents || {
            base: true
        };

        /**************************************************
         *
         * END Register utils component
         *
         **************************************************/

        _mustNOTexist("def");
        utils.def = utils.def || function (v) {
            return ((v !== null) && (v !== undefined));
        };

        _mustNOTexist("obj");
        _mustExist("isObject");
        utils.obj = utils.obj || utils.isObject;

        _mustNOTexist("bool");
        _mustExist("isBoolean");
        utils.bool = utils.bool || utils.isBoolean;

        _mustNOTexist("number");
        _mustExist("isNumber");
        utils.number = utils.number || utils.isNumber;

        _mustNOTexist("string");
        _mustExist("isString");
        utils.string = utils.string || utils.isString;

        _mustNOTexist("array");
        _mustExist("isArray");
        utils.array = utils.array || utils.isArray;

        _mustNOTexist("func");
        _mustExist("isFunction");
        utils.func = utils.func || utils.isFunction;

        _mustNOTexist("date");
        _mustExist("isDate");
        utils.date = utils.date || utils.isDate;

        _mustNOTexist("empty");
        _mustExist("isEmpty");
        utils.empty = utils.empty || utils.isEmpty;

        _mustNOTexist("ensureFunc");
        utils.ensureFunc = utils.ensureFunc || function (f) {
            return (utils.func(f) ? f : function () {
            });
        };

        _mustNOTexist("now");
        utils.now = utils.now || function () {
            return (new Date()).getTime();
        };

        _mustNOTexist("get");
        utils.get = utils.get || function (obj, path, objName) {
            var me = "Utils::get";
            var value = null;

            var describe = !utils.empty(objName);

            if (!utils.obj(obj)) {
                if (describe) {
                    log.error(me, "object {0} is invalid, can't get property {1}".fmt(objName, path));
                }
                return value;
            }

            if (!utils.string(path) || utils.empty(path)) {
                if (describe) {
                    log.error(me, "path to property is invalid, can't get property of {0} object".fmt(objName));
                }
                return value;
            }

            var props = path.split(".");
            var numProps = props.length;
            var prop = null;

            var pathTravelled = "";

            var value = obj;
            for (var idx = 0; idx < numProps; idx++) {
                prop = props[idx];

                if (utils.obj(value)) {
                    value = value[prop];
                } else {
                    if (describe) {
                        log.warn(me, "{0} of object {1} is not an object, unable to get property {2}".fmt(
                                pathTravelled,
                                objName,
                                path
                        ));
                    }

                    value = null;
                    break;
                }

                if (describe) {
                    pathTravelled += ((idx > 0) ? '.' : '') + prop;
                }
            }

            return value;
        };

        _mustNOTexist("set");
        utils.set = utils.set || function (obj, path, value, objName) {
            var me = "utils::set";
            var success = false;

            var describe = !utils.empty(objName);

            if (!utils.obj(obj)) {
                if (describe) {
                    log.error(me, "object {0} is invalid, can't set property {1}".fmt(objName, path));
                }
                return success;
            }

            if (!utils.string(path) || utils.empty(path)) {
                if (describe) {
                    log.error(me, "path to property is invalid, can't set property of {0} object".fmt(objName));
                }
                return success;
            }

            var props = path.split(".");
            var numProps = props.length;
            var prop = null;

            var pathTravelled = "";

            var targetObj = obj;
            for (var idx = 0; idx < numProps; idx++) {
                prop = props[idx];

                if (utils.obj(targetObj)) {
                    if (idx < numProps - 1) {
                        targetObj = targetObj[prop];
                    } else {
                        success = true;
                        targetObj[prop] = value;
                    }
                } else {
                    if (describe) {
                        log.warn(me, "{0} of object {1} is not an object, unable to set property {2}".fmt(
                                pathTravelled,
                                objName,
                                path
                        ));
                    }

                    break;
                }

                if (describe) {
                    pathTravelled += ((idx > 0) ? '.' : '') + prop;
                }
            }

            return success;
        };

        _mustNOTexist("stringify");
        utils.stringify = utils.stringify || function(obj) {
            var me  = "Utils::stringify";

            var s   = null;
            try {
                s = JSON.stringify(obj);
            } catch(e) {
                log.error(me, "Unable to stringify object : ", utils.get(e, "message"));
                s = "[Unable to stringify object]";
            }

            return s;
        }
    };

})();<|endoftext|>


<commit_before>#!/usr/bin/env/ node

const theo = require('theo');
const path = require('path');
const fs = require('fs-extra');

theo.registerTransform('cedar-web', ['color/hex']);

// MIXIN FORMATTER
theo.registerFormat('mixin', result => {
  let mixins = [];

  result.get('props').map(prop => {
    let name = prop.get('name');
    let value = prop.get('value');
    let declarations = [];
    let mixin = '';

    value.map((value,key) => {
      declarations.push(`${key}: ${value};`);
    });

    mixin = `@mixin ${name}() {
  ${declarations.join('\n  ')}
}`;

    mixins.push(mixin);
  });

  return `${mixins.join('\n\n')}\n`;
});

// OUTPUT MIXINS
theo
  .convert({
    transform: {
      type: 'web',
      file: path.join(__dirname, '..', 'tokens/m_index.yml'),
    },
    format: {
      type: 'mixin',
    },
  })
  .then((data) => {
    fs.writeFileSync('src/css/settings/mixins.pcss', data);
  })
  .catch(error => console.log(`Something went wrong: ${error}`));

// OUTPUT VARIABLES
theo
  .convert({
    transform: {
      type: 'cedar-web',
      file: path.join(__dirname, '..', 'tokens/v_index.yml'),
    },
    format: {
      type: 'scss',
    },
  })
  .then((data) => {
    fs.writeFileSync('src/css/settings/tokens.pcss', data);
  })
  .catch(error => console.log(`Something went wrong: ${error}`));
<commit_msg>refactor(theo): fix theo eslint errors<commit_after>#!/usr/bin/env/ node

const theo = require('theo');
const path = require('path');
const fs = require('fs-extra');

theo.registerTransform('cedar-web', ['color/hex']);

// MIXIN FORMATTER
theo.registerFormat('mixin', (result) => {
  const mixins = [];

  result.get('props').forEach((prop) => {
    const name = prop.get('name');
    const value = prop.get('value');
    const declarations = [];
    let mixin = '';

    value.forEach((val, key) => {
      declarations.push(`${key}: ${val};`);
    });

    mixin = `@mixin ${name}() {
  ${declarations.join('\n  ')}
}`;

    mixins.push(mixin);
  });

  return `${mixins.join('\n\n')}\n`;
});

// OUTPUT MIXINS
theo
  .convert({
    transform: {
      type: 'web',
      file: path.join(__dirname, '..', 'tokens/m_index.yml'),
    },
    format: {
      type: 'mixin',
    },
  })
  .then((data) => {
    fs.writeFileSync('src/css/settings/mixins.pcss', data);
  })
  .catch(error => console.log(`Something went wrong: ${error}`));

// OUTPUT VARIABLES
theo
  .convert({
    transform: {
      type: 'cedar-web',
      file: path.join(__dirname, '..', 'tokens/v_index.yml'),
    },
    format: {
      type: 'scss',
    },
  })
  .then((data) => {
    fs.writeFileSync('src/css/settings/tokens.pcss', data);
  })
  .catch(error => console.log(`Something went wrong: ${error}`));
<|endoftext|>


<commit_before>/**
 * Created by timowelde on 06.12.13.
 */

function initIndex(pathRemovePic) {
    // Collapse other groups
    $('.group-content').hide();

    // Hide actions
    $('.actions').hide();

    // Hide usernames and enable showUsernamesHandler
    usernamesHandler();
    // Add Submithandler to the newuser form
    newUserHandler();

    // Hide flash messages with a click
    flashmessages.clickHandler();

    // Add Handler for "remove group"
    removeGroupHandler($('.group_delete'));

    // initialise group picture upload
    var uploadGroupPicture = new UploadGroupPicture({
        pathRemovePic: pathRemovePic,
        pathOrigPic: $('#headerpic').attr('src')
    });

    // Prepare newpadforms
    var newpadform = $('.pads .newpadform');
    // Add submit handler for the newpadforms
    newPadFormSubmitHandler(newpadform, uploadGroupPicture);
    // Ajax call for expanding group, if clicked
    expandGroupHandler($('#groups .group-name'), newpadform, uploadGroupPicture);

    // show action icons when mouseover groupname
    showActionsHandler($('#groups .group-name'))

    var search = location.search.substring(1).split('=')[1];
    search = decodeURIComponent(search)
    if(!search) {
        // Trigger click for first group
        $('.group:first .group-link').click();
    }
    else {
        openFromSearch(search)
        history.replaceState(true, '', null);
    }

    window.onpopstate = function(event) {
        if(event.state) {
            var search = location.search.substring(1).split('=')[1];
            search = decodeURIComponent(search)
            openFromSearch(search)
        }
    }

    function openFromSearch(search) {
        // Try to open pad and group from hash
        search = search.split('/')
        var groupid = search[0];
        var group = $('#group-'+groupid);
        expandGroup(group, newpadform, uploadGroupPicture, function(padscontent) {
            group.find('[data-name="'+search[1]+'"]').click();

        })
    }

    // Show group_edit button (This functionality is hidden, when js is disabled)
    var editgroup = $('.group .editgroup').show();
    // Edit groupname click handler
    renameGroupClickHandler(editgroup);

    // groupname form submit handler
    renameGroupFormHandler($('.group .editform'));

    // show/hide groups
    $('#togglegroups').click(function(e){
        e.preventDefault();
        $('#groups-menu').toggle();
        $('#pad').toggleClass('fullwidth');
        $(this).find('img').toggle();
    });

    // renew cookie every x seconds
    renewCookieHandler()
}

function renewCookieHandler() {
    var renewObj = $('#renewCookie')
    var url = renewObj.attr('href')

    var delay = parseInt(renewObj.data('expires'))*1000

    timeoutFunc = function(delay) {
        renewCookieTimeout = setTimeout(function(){
            $.get(url, function(data, textStatus, jqXHR) {
                var delay = parseInt(data)*1000
                timeoutFunc(delay)
            })
        }, delay)
    }

    timeoutFunc(delay)

}<commit_msg>fix for when no query param available<commit_after>/**
 * Created by timowelde on 06.12.13.
 */

function initIndex(pathRemovePic) {
    // Collapse other groups
    $('.group-content').hide();

    // Hide actions
    $('.actions').hide();

    // Hide usernames and enable showUsernamesHandler
    usernamesHandler();
    // Add Submithandler to the newuser form
    newUserHandler();

    // Hide flash messages with a click
    flashmessages.clickHandler();

    // Add Handler for "remove group"
    removeGroupHandler($('.group_delete'));

    // initialise group picture upload
    var uploadGroupPicture = new UploadGroupPicture({
        pathRemovePic: pathRemovePic,
        pathOrigPic: $('#headerpic').attr('src')
    });

    // Prepare newpadforms
    var newpadform = $('.pads .newpadform');
    // Add submit handler for the newpadforms
    newPadFormSubmitHandler(newpadform, uploadGroupPicture);
    // Ajax call for expanding group, if clicked
    expandGroupHandler($('#groups .group-name'), newpadform, uploadGroupPicture);

    // show action icons when mouseover groupname
    showActionsHandler($('#groups .group-name'))

    var search = location.search.substring(1).split('=')[1];
    if(!search) {
        // Trigger click for first group
        $('.group:first .group-link').click();
    }
    else {
        search = decodeURIComponent(search)
        openFromSearch(search)
        history.replaceState(true, '', null);
    }

    window.onpopstate = function(event) {
        if(event.state) {
            var search = location.search.substring(1).split('=')[1];
            search = decodeURIComponent(search)
            openFromSearch(search)
        }
    }

    function openFromSearch(search) {
        // Try to open pad and group from hash
        search = search.split('/')
        var groupid = search[0];
        var group = $('#group-'+groupid);
        expandGroup(group, newpadform, uploadGroupPicture, function(padscontent) {
            group.find('[data-name="'+search[1]+'"]').click();

        })
    }

    // Show group_edit button (This functionality is hidden, when js is disabled)
    var editgroup = $('.group .editgroup').show();
    // Edit groupname click handler
    renameGroupClickHandler(editgroup);

    // groupname form submit handler
    renameGroupFormHandler($('.group .editform'));

    // show/hide groups
    $('#togglegroups').click(function(e){
        e.preventDefault();
        $('#groups-menu').toggle();
        $('#pad').toggleClass('fullwidth');
        $(this).find('img').toggle();
    });

    // renew cookie every x seconds
    renewCookieHandler()
}

function renewCookieHandler() {
    var renewObj = $('#renewCookie')
    var url = renewObj.attr('href')

    var delay = parseInt(renewObj.data('expires'))*1000

    timeoutFunc = function(delay) {
        renewCookieTimeout = setTimeout(function(){
            $.get(url, function(data, textStatus, jqXHR) {
                var delay = parseInt(data)*1000
                timeoutFunc(delay)
            })
        }, delay)
    }

    timeoutFunc(delay)

}<|endoftext|>


<commit_before>/**
* @jsx React.DOM
*/

/*jslint node: true*/
'use strict';
var React         = require('react');
var AutoCompleteEditor  = require('./AutoCompleteEditor');

var AutoCompleteAsyncEditor =  React.createClass({

  propTypes : {
	cacheResults: React.PropTypes.bool,
  	column: React.PropTypes.object,
  	rowMetaData: React.PropTypes.object,
	height: React.PropTypes.number,
	label: React.PropTypes.string,
	onCommit: React.PropTypes.func,
	onKeyDown: React.PropTypes.func,
	resultIdentifier: React.PropTypes.string,
	searchSourceArgs: React.PropTypes.array,
	searchUrl: React.PropTypes.func,
	value: React.PropTypes.string,
	valueParams: React.PropTypes.arrayOf(React.PropTypes.string)
  },

  getSearchParams() {
    var rowMetaData = this.props.rowMetaData;
    var searchParams =  this.props.searchSourceArgs.map(arg => {
      if(!rowMetaData[arg]){
        throw ("Cannot find Search Source Paramater " + arg + " in rowMetaData. You must add an entry for this in models/GridColumn.js")
      }
      return rowMetaData[arg]
    });
    return searchParams;
  },

  getInputNode(): HTMLInputElement{
    return this.getDOMNode().getElementsByTagName("input")[0];
  },

  getValue(){
    return this.refs.autocomplete.getValue();
  },

  hasResults(){
    return this.refs.autocomplete.hasResults();
  },

  _searchRemote(options, searchTerm, cb) {
    var searchParams = this.getSearchParams();
    //add onSuccessCallback at end of search params array
    searchParams.push(this._onXHRSuccess.bind(null, cb, searchTerm));
    this.props.searchUrl.apply(this, searchParams);
  },

  _onXHRSuccess(cb, searchTerm, data, status, xhr) {
    cb(null, this._filterData(data, searchTerm))
  },

  _onXHRError(cb, xhr, status, err) {
    cb(err)
  },

  _filterData(data, searchTerm) {
    var regexp = new RegExp(searchTerm, 'i')
    var results = []
    var label = this.props.label ? this.props.label : 'title';
	for (var i = 0, len = data.length; i < len; i++) {
      if (regexp.exec(data[i][label])) {
        results.push(data[i])
      }
    }
    return results.slice(0, 100)
  },

  render() {
    return (
      <AutoCompleteEditor
		ref="autocomplete" {...this.props}
		options={[]}
		search={this._searchRemote}
		value={this.props.value}
		label={this.props.label}
		resultIdentifier={this.props.resultIdentifier}
	  />
    )
  }
});

module.exports = AutoCompleteAsyncEditor;
<commit_msg>call static format funcion in autocomplete async<commit_after>/**
* @jsx React.DOM
*/

/*jslint node: true*/
'use strict';
var React         = require('react');
var AutoCompleteEditor  = require('./AutoCompleteEditor');

var AutoCompleteAsyncEditor =  React.createClass({

  propTypes : {
	cacheResults: React.PropTypes.bool,
  	column: React.PropTypes.object,
  	rowMetaData: React.PropTypes.object,
	height: React.PropTypes.number,
	label: React.PropTypes.string,
	onCommit: React.PropTypes.func,
	onKeyDown: React.PropTypes.func,
	resultIdentifier: React.PropTypes.string,
	searchSourceArgs: React.PropTypes.array,
	searchUrl: React.PropTypes.func,
	value: React.PropTypes.string,
	valueParams: React.PropTypes.arrayOf(React.PropTypes.string)
  },

  getSearchParams() {
    var rowMetaData = this.props.rowMetaData;
    var searchParams =  this.props.searchSourceArgs.map(arg => {
      if(!rowMetaData[arg]){
        throw ("Cannot find Search Source Paramater " + arg + " in rowMetaData. You must add an entry for this in models/GridColumn.js")
      }
      return rowMetaData[arg]
    });
    return searchParams;
  },

  getInputNode(): HTMLInputElement{
    return this.getDOMNode().getElementsByTagName("input")[0];
  },

  getValue(){
    return this.refs.autocomplete.getValue();
  },

  hasResults(){
    return this.refs.autocomplete.hasResults();
  },

  _searchRemote(options, searchTerm, cb) {
    var searchParams = this.getSearchParams();
    //add onSuccessCallback at end of search params array
    searchParams.push(this._onXHRSuccess.bind(null, cb, searchTerm));
    this.props.searchUrl.apply(this, searchParams);
  },

  _onXHRSuccess(cb, searchTerm, data, status, xhr) {
    cb(null, this._filterData(data, searchTerm))
  },

  _onXHRError(cb, xhr, status, err) {
    cb(err)
  },

  _filterData(data, searchTerm) {
    var regexp = new RegExp(searchTerm, 'i')
    var results = []
    var label = this.props.label ? this.props.label : 'title';
	for (var i = 0, len = data.length; i < len; i++) {
      if (regexp.exec(data[i][label])) {
        results.push(data[i])
      }
    }
    return results.slice(0, 100)
  },

  render() {
    var value;
    var Formatter = this.props.column.formatter;
    if(typeof Formatter === 'function' && typeof Formatter.format === 'function'){
      value = Formatter.format(this.props.value);
    }else{
      value = this.props.value;
    }
    return (
      <AutoCompleteEditor
		ref="autocomplete" {...this.props}
		options={[]}
		search={this._searchRemote}
		value={value}
		label={this.props.label}
		resultIdentifier={this.props.resultIdentifier}
	  />
    )
  }
});

module.exports = AutoCompleteAsyncEditor;
<|endoftext|>