<commit_before>uis.directive('uiSelectChoices',
  ['uiSelectConfig', 'uisRepeatParser', 'uiSelectMinErr', '$compile', '$window',
  function(uiSelectConfig, RepeatParser, uiSelectMinErr, $compile, $window) {

  return {
    restrict: 'EA',
    require: '^uiSelect',
    replace: true,
    transclude: true,
    templateUrl: function(tElement) {
      // Needed so the uiSelect can detect the transcluded content
      tElement.addClass('ui-select-choices');

      // Gets theme attribute from parent (ui-select)
      var theme = tElement.parent().attr('theme') || uiSelectConfig.theme;
      return theme + '/choices.tpl.html';
    },

    compile: function(tElement, tAttrs) {

      if (!tAttrs.repeat) throw uiSelectMinErr('repeat', "Expected 'repeat' expression.");

      // var repeat = RepeatParser.parse(attrs.repeat);
      var groupByExp = tAttrs.groupBy;
      var groupFilterExp = tAttrs.groupFilter;

      if (groupByExp) {
        var groups = tElement.querySelectorAll('.ui-select-choices-group');
        if (groups.length !== 1) throw uiSelectMinErr('rows', "Expected 1 .ui-select-choices-group but got '{0}'.", groups.length);
        groups.attr('ng-repeat', RepeatParser.getGroupNgRepeatExpression());
      }

      var parserResult = RepeatParser.parse(tAttrs.repeat);

      var choices = tElement.querySelectorAll('.ui-select-choices-row');
      if (choices.length !== 1) {
        throw uiSelectMinErr('rows', "Expected 1 .ui-select-choices-row but got '{0}'.", choices.length);
      }

      choices.attr('ng-repeat', parserResult.repeatExpression(groupByExp))
             .attr('ng-if', '$select.open'); //Prevent unnecessary watches when dropdown is closed

      var rowsInner = tElement.querySelectorAll('.ui-select-choices-row-inner');
      if (rowsInner.length !== 1) {
        throw uiSelectMinErr('rows', "Expected 1 .ui-select-choices-row-inner but got '{0}'.", rowsInner.length);
      }
      rowsInner.attr('uis-transclude-append', ''); //Adding uisTranscludeAppend directive to row element after choices element has ngRepeat

      // If IE8 then need to target rowsInner to apply the ng-click attr as choices will not capture the event.
      var clickTarget = $window.document.addEventListener ? choices : rowsInner;
      clickTarget.attr('ng-click', '$select.select(' + parserResult.itemName + ',$select.skipFocusser,$event)');

      return function link(scope, element, attrs, $select) {

        $select.parseRepeatAttr(attrs.repeat, groupByExp, groupFilterExp); //Result ready at $select.parserResult

        $select.disableChoiceExpression = attrs.uiDisableChoice;
        $select.onHighlightCallback = attrs.onHighlight;

        $select.dropdownPosition = attrs.position ? attrs.position.toLowerCase() : uiSelectConfig.dropdownPosition;

        scope.$on('$destroy', function() {
          choices.remove();
        });

        scope.$watch('$select.search', function(newValue) {
          if(newValue && !$select.open && $select.multiple) $select.activate(false, true);
          $select.activeIndex = $select.tagging.isActivated ? -1 : 0;
          if (!attrs.minimumInputLength || $select.search.length >= attrs.minimumInputLength) {
            $select.refresh(attrs.refresh);
          } else {
            $select.items = [];
          }
        });

        attrs.$observe('refreshDelay', function() {
          // $eval() is needed otherwise we get a string instead of a number
          var refreshDelay = scope.$eval(attrs.refreshDelay);
          $select.refreshDelay = refreshDelay !== undefined ? refreshDelay : uiSelectConfig.refreshDelay;
        });

        scope.$watch('$select.open', function(open) {
          if (open) {
            tElement.attr('role', 'listbox');
          } else {
            tElement.removeAttr('role');
          }
        });
      };
    }
  };
}]);
<commit_msg>fix(uiSelectChoices): prevent template element from being modified (#1850)<commit_after>uis.directive('uiSelectChoices',
  ['uiSelectConfig', 'uisRepeatParser', 'uiSelectMinErr', '$compile', '$window',
  function(uiSelectConfig, RepeatParser, uiSelectMinErr, $compile, $window) {

  return {
    restrict: 'EA',
    require: '^uiSelect',
    replace: true,
    transclude: true,
    templateUrl: function(tElement) {
      // Needed so the uiSelect can detect the transcluded content
      tElement.addClass('ui-select-choices');

      // Gets theme attribute from parent (ui-select)
      var theme = tElement.parent().attr('theme') || uiSelectConfig.theme;
      return theme + '/choices.tpl.html';
    },

    compile: function(tElement, tAttrs) {

      if (!tAttrs.repeat) throw uiSelectMinErr('repeat', "Expected 'repeat' expression.");

      // var repeat = RepeatParser.parse(attrs.repeat);
      var groupByExp = tAttrs.groupBy;
      var groupFilterExp = tAttrs.groupFilter;

      if (groupByExp) {
        var groups = tElement.querySelectorAll('.ui-select-choices-group');
        if (groups.length !== 1) throw uiSelectMinErr('rows', "Expected 1 .ui-select-choices-group but got '{0}'.", groups.length);
        groups.attr('ng-repeat', RepeatParser.getGroupNgRepeatExpression());
      }

      var parserResult = RepeatParser.parse(tAttrs.repeat);

      var choices = tElement.querySelectorAll('.ui-select-choices-row');
      if (choices.length !== 1) {
        throw uiSelectMinErr('rows', "Expected 1 .ui-select-choices-row but got '{0}'.", choices.length);
      }

      choices.attr('ng-repeat', parserResult.repeatExpression(groupByExp))
             .attr('ng-if', '$select.open'); //Prevent unnecessary watches when dropdown is closed

      var rowsInner = tElement.querySelectorAll('.ui-select-choices-row-inner');
      if (rowsInner.length !== 1) {
        throw uiSelectMinErr('rows', "Expected 1 .ui-select-choices-row-inner but got '{0}'.", rowsInner.length);
      }
      rowsInner.attr('uis-transclude-append', ''); //Adding uisTranscludeAppend directive to row element after choices element has ngRepeat

      // If IE8 then need to target rowsInner to apply the ng-click attr as choices will not capture the event.
      var clickTarget = $window.document.addEventListener ? choices : rowsInner;
      clickTarget.attr('ng-click', '$select.select(' + parserResult.itemName + ',$select.skipFocusser,$event)');

      return function link(scope, element, attrs, $select) {

        $select.parseRepeatAttr(attrs.repeat, groupByExp, groupFilterExp); //Result ready at $select.parserResult

        $select.disableChoiceExpression = attrs.uiDisableChoice;
        $select.onHighlightCallback = attrs.onHighlight;

        $select.dropdownPosition = attrs.position ? attrs.position.toLowerCase() : uiSelectConfig.dropdownPosition;

        scope.$watch('$select.search', function(newValue) {
          if(newValue && !$select.open && $select.multiple) $select.activate(false, true);
          $select.activeIndex = $select.tagging.isActivated ? -1 : 0;
          if (!attrs.minimumInputLength || $select.search.length >= attrs.minimumInputLength) {
            $select.refresh(attrs.refresh);
          } else {
            $select.items = [];
          }
        });

        attrs.$observe('refreshDelay', function() {
          // $eval() is needed otherwise we get a string instead of a number
          var refreshDelay = scope.$eval(attrs.refreshDelay);
          $select.refreshDelay = refreshDelay !== undefined ? refreshDelay : uiSelectConfig.refreshDelay;
        });

        scope.$watch('$select.open', function(open) {
          if (open) {
            element.attr('role', 'listbox');
          } else {
            element.removeAttr('role');
          }
        });
      };
    }
  };
}]);
<|endoftext|>


<commit_before>import buildfire from 'buildfire';
import {filter, find} from 'lodash';
import "./lib/markercluster.js";

import "../css/general.css";
import "../css/slider.css";
import "./filterControl.js";
import "./map.js";
import "./list.js";
import "./detail.js";
import "./router.js";
import PlacesSort from "./PlacesSort.js";

window.app = {
    goBack: null,
    settings: {
        viewStates: {map: 'map', list: 'list', detail: 'detail'},
        sortOptions: {alpha: 'alpha', alphaDesc: 'alphaDesc', manual: 'manual'},
        placesTag: 'places',
        cloudImg: {
            domain:'https://czi3m2qn.cloudimg.io',
            operations: {
                cdn: '/cdn/n/n',
                width: '/s/width',
                crop: '/s/crop'
            }
        }
    },
    views: {
        listView: document.getElementById('listView'),
        mapView: document.getElementById('mapView'),
        detailView: document.getElementById('detailView'),
        sideNav: document.getElementById('sideNav'),
    },
    state: {
        mapInitiated: false,
        mode: null,
        activeView: null,
        places: [],
        markers: [],
        bounds: null,
        filteredPlaces: [],
        selectedPlace: [],
        sortBy: null,
        categories: [],
        navHistory: [],
        isBackNav: false
    },
    backButtonInit: () => {
        window.app.goBack = window.buildfire.navigation.onBackButtonClick;

        buildfire.navigation.onBackButtonClick = function() {
            const isLauncher = window.location.href.includes('launcherPlugin');

            if (window.app.state.navHistory.length > 0) {

                //Remove the current state
                if(window.app.state.mode === window.app.state.navHistory[window.app.state.navHistory.length-1]){

                    //Don't remove last state, if launcher plugin
                    if(!isLauncher || window.app.state.navHistory.length != 1){
                        window.app.state.navHistory.pop();
                    }
                }

                //Navigate to the previous state
                let lastNavState = window.app.state.navHistory[window.app.state.navHistory.length-1];

                window.app.state.isBackNav = true;

                window.router.navigate(lastNavState);
            }
            else{
                window.app.goBack();
            }
        };
    },
    init: (placesCallback, positionCallback) => {
        window.buildfire.appearance.titlebar.show();

        window.app.backButtonInit();

        buildfire.datastore.get (window.app.settings.placesTag, function(err, results){
            if(err){
              console.error('datastore.get error', err);
              return;
            }

            let places,
                data = results.data;

            if(data && data.places){
              if(data.categories){
                window.app.state.categories = data.categories.map(category => {
                    return {name: category, isActive: true};
                });
              }

              window.app.state.mode = data.defaultView;

              let sortBy = window.PlacesSort[data.sortBy];
              places = data.places.sort(sortBy);

              window.app.state.places = places;
              window.app.state.filteredPlaces = places;
              window.app.state.sortBy = data.sortBy;
              window.app.state.defaultView = data.defaultView;
            }

            placesCallback(null, places);
        });

        console.log('Calling getCurrentPosition');

        buildfire.geo.getCurrentPosition({}, (err, position) => {
            console.log('getCurrentPosition result', err, position);
            if(err){
                console.error('getCurrentPosition', err);
                return;
            }

            if(position && position.coords){
                positionCallback(null, position.coords);
            }
        });

        buildfire.datastore.onUpdate(function(event) {
          if(event.tag === window.app.settings.placesTag){

              console.log('Got update');
              location.reload(); // TEMPORARY SOLUTION FOR THE DEMO

              let currentPlaces = window.app.state.places;
              let newPlaces = event.data.places;
              let currentSortOrder = window.app.state.sortBy;
              let newSortOrder = event.data.sortBy;
              let newViewState = event.data.defaultView;
              let currentDefaultView = window.app.state.defaultView;
              let newDefaultView = event.data.defaultView;

              /**
               * SORT ORDER
               */
              if(currentSortOrder != newSortOrder){
                  window.app.state.sortBy = newSortOrder;
                  let sortBy = PlacesSort[window.app.state.sortBy];
                  window.app.state.places.sort(sortBy);

                  if(window.app.state.mode === window.app.settings.viewStates.list)
                    window.loadList(window.app.state.places);

                  return;
              }

              let defaultViewChanged = currentDefaultView !== newDefaultView;
              let notInDefaultView = newDefaultView !== window.app.state.mode;

              // We want to update the widget to reflect the new default view if the setting
              // was changed and the user is not in that view already
              if (defaultViewChanged && notInDefaultView) {
                window.router.navigate(newViewState);
                window.app.state.mode = newViewState;
                return;
              }

              //Do comparison to see what's changed
              let updatedPlaces = filter(newPlaces, (newPlace) => { return !find(currentPlaces, newPlace)});

              if(window.app.state.mode === window.app.settings.viewStates.map){
                  window.mapView.updateMap(updatedPlaces);
              }else{
                  //Load new items
                  window.listView.updateList(updatedPlaces);
              }
          }
        });
    },
    gotPieceOfData() {
      if (window.app.state.places && window.app.state.location) {
        let { location } = window.app.state;
        let destinations = [];

        window.app.state.places.forEach(place => {
          destinations.push(new window.google.maps.LatLng(place.address.lat, place.address.lng));
        });

        let origin = [{lat: location.latitude, lng: location.longitude}];

        let service = new window.google.maps.DistanceMatrixService();

        service.getDistanceMatrix({
            origins: origin,
            destinations: destinations,
            travelMode: window.google.maps.TravelMode.DRIVING,
            unitSystem: window.google.maps.UnitSystem.IMPERIAL //google.maps.UnitSystem.METRIC
        }, (response) => {
            //Update places with distance
            window.app.state.places.map((place, index)=>{
                if(response.rows[0].elements[index].distance)
                    place.distance = response.rows[0].elements[index].distance.text;
                    place.distanceInMeters = response.rows[0].elements[index].distance.value;
            });

            window.listView.updateDistances(window.app.state.filteredPlaces);
        });
      }
    },
    gotPlaces(err, places) {
        if(window.app.state.mode === window.app.settings.viewStates.list){
            window.initList(places, true);
            //We can not pre-init the map, as it needs to be visible
        }
        else{
            window.initMap(places, true);
            window.initList(places);
        }
        window.app.gotPieceOfData();
    },

    gotLocation(err, location) {
        window.app.state.location = location;
        window.app.gotPieceOfData();
    }
};

//document.addEventListener('DOMContentLoaded', () => window.app.init( window.app.gotPlaces, window.app.gotLocation));
app.init(app.gotPlaces, app.gotLocation);
window.initRouter();
<commit_msg>Safeguard object access on widget<commit_after>import buildfire from 'buildfire';
import {filter, find} from 'lodash';
import "./lib/markercluster.js";

import "../css/general.css";
import "../css/slider.css";
import "./filterControl.js";
import "./map.js";
import "./list.js";
import "./detail.js";
import "./router.js";
import PlacesSort from "./PlacesSort.js";

window.app = {
    goBack: null,
    settings: {
        viewStates: {map: 'map', list: 'list', detail: 'detail'},
        sortOptions: {alpha: 'alpha', alphaDesc: 'alphaDesc', manual: 'manual'},
        placesTag: 'places',
        cloudImg: {
            domain:'https://czi3m2qn.cloudimg.io',
            operations: {
                cdn: '/cdn/n/n',
                width: '/s/width',
                crop: '/s/crop'
            }
        }
    },
    views: {
        listView: document.getElementById('listView'),
        mapView: document.getElementById('mapView'),
        detailView: document.getElementById('detailView'),
        sideNav: document.getElementById('sideNav'),
    },
    state: {
        mapInitiated: false,
        mode: null,
        activeView: null,
        places: [],
        markers: [],
        bounds: null,
        filteredPlaces: [],
        selectedPlace: [],
        sortBy: null,
        categories: [],
        navHistory: [],
        isBackNav: false
    },
    backButtonInit: () => {
        window.app.goBack = window.buildfire.navigation.onBackButtonClick;

        buildfire.navigation.onBackButtonClick = function() {
            const isLauncher = window.location.href.includes('launcherPlugin');

            if (window.app.state.navHistory.length > 0) {

                //Remove the current state
                if(window.app.state.mode === window.app.state.navHistory[window.app.state.navHistory.length-1]){

                    //Don't remove last state, if launcher plugin
                    if(!isLauncher || window.app.state.navHistory.length != 1){
                        window.app.state.navHistory.pop();
                    }
                }

                //Navigate to the previous state
                let lastNavState = window.app.state.navHistory[window.app.state.navHistory.length-1];

                window.app.state.isBackNav = true;

                window.router.navigate(lastNavState);
            }
            else{
                window.app.goBack();
            }
        };
    },
    init: (placesCallback, positionCallback) => {
        window.buildfire.appearance.titlebar.show();

        window.app.backButtonInit();

        buildfire.datastore.get (window.app.settings.placesTag, function(err, results){
            if(err){
              console.error('datastore.get error', err);
              return;
            }

            let places,
                data = results.data;

            if(data && data.places){
              if(data.categories){
                window.app.state.categories = data.categories.map(category => {
                    return {name: category, isActive: true};
                });
              }

              window.app.state.mode = data.defaultView;

              let sortBy = window.PlacesSort[data.sortBy];
              places = data.places.sort(sortBy);

              window.app.state.places = places;
              window.app.state.filteredPlaces = places;
              window.app.state.sortBy = data.sortBy;
              window.app.state.defaultView = data.defaultView;
            }

            placesCallback(null, places);
        });

        console.log('Calling getCurrentPosition');

        buildfire.geo.getCurrentPosition({}, (err, position) => {
            console.log('getCurrentPosition result', err, position);
            if(err){
                console.error('getCurrentPosition', err);
                return;
            }

            if(position && position.coords){
                positionCallback(null, position.coords);
            }
        });

        buildfire.datastore.onUpdate(function(event) {
          if(event.tag === window.app.settings.placesTag){

              console.log('Got update');
              location.reload(); // TEMPORARY SOLUTION FOR THE DEMO

              let currentPlaces = window.app.state.places;
              let newPlaces = event.data.places;
              let currentSortOrder = window.app.state.sortBy;
              let newSortOrder = event.data.sortBy;
              let newViewState = event.data.defaultView;
              let currentDefaultView = window.app.state.defaultView;
              let newDefaultView = event.data.defaultView;

              /**
               * SORT ORDER
               */
              if(currentSortOrder != newSortOrder){
                  window.app.state.sortBy = newSortOrder;
                  let sortBy = PlacesSort[window.app.state.sortBy];
                  window.app.state.places.sort(sortBy);

                  if(window.app.state.mode === window.app.settings.viewStates.list)
                    window.loadList(window.app.state.places);

                  return;
              }

              let defaultViewChanged = currentDefaultView !== newDefaultView;
              let notInDefaultView = newDefaultView !== window.app.state.mode;

              // We want to update the widget to reflect the new default view if the setting
              // was changed and the user is not in that view already
              if (defaultViewChanged && notInDefaultView) {
                window.router.navigate(newViewState);
                window.app.state.mode = newViewState;
                return;
              }

              //Do comparison to see what's changed
              let updatedPlaces = filter(newPlaces, (newPlace) => { return !find(currentPlaces, newPlace)});

              if(window.app.state.mode === window.app.settings.viewStates.map){
                  window.mapView.updateMap(updatedPlaces);
              }else{
                  //Load new items
                  window.listView.updateList(updatedPlaces);
              }
          }
        });
    },
    gotPieceOfData() {
      if (window.app.state.places && window.app.state.location) {
        let { location } = window.app.state;
        let destinations = [];

        window.app.state.places.forEach(place => {
          destinations.push(new window.google.maps.LatLng(place.address.lat, place.address.lng));
        });

        let origin = [{lat: location.latitude, lng: location.longitude}];

        let service = new window.google.maps.DistanceMatrixService();

        service.getDistanceMatrix({
            origins: origin,
            destinations: destinations,
            travelMode: window.google.maps.TravelMode.DRIVING,
            unitSystem: window.google.maps.UnitSystem.IMPERIAL //google.maps.UnitSystem.METRIC
        }, (response) => {
            //Update places with distance
            window.app.state.places.map((place, index)=>{
                if(response.rows && response.rows[0].elements[index] && response.rows[0].elements[index].distance)
                    place.distance = response.rows[0].elements[index].distance.text;
                    place.distanceInMeters = response.rows[0].elements[index].distance
                      ? response.rows[0].elements[index].distance.value
                      : null;
            });

            window.listView.updateDistances(window.app.state.filteredPlaces);
        });
      }
    },
    gotPlaces(err, places) {
        if(window.app.state.mode === window.app.settings.viewStates.list){
            window.initList(places, true);
            //We can not pre-init the map, as it needs to be visible
        }
        else{
            window.initMap(places, true);
            window.initList(places);
        }
        window.app.gotPieceOfData();
    },

    gotLocation(err, location) {
        window.app.state.location = location;
        window.app.gotPieceOfData();
    }
};

//document.addEventListener('DOMContentLoaded', () => window.app.init( window.app.gotPlaces, window.app.gotLocation));
app.init(app.gotPlaces, app.gotLocation);
window.initRouter();
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2013-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @flow
 * @providesModule RelayCompilerContext
 */

'use strict';

const immutable = require('immutable');
const invariant = require('invariant');

import type {
  Fragment,
  Root,
} from 'RelayIR';
import type {GraphQLSchema} from 'graphql';

const {
  List: ImmutableList,
  OrderedMap: ImmutableOrderedMap,
  Record,
} = immutable;

const Document = Record({
  errors: null,
  name: null,
  node: null,
});

/**
 * An immutable representation of a corpus of documents being compiled together.
 * For each document, the context stores the IR and any validation errors.
 */
class RelayCompilerContext {
  _documents: ImmutableOrderedMap<string, Document>;
  schema: GraphQLSchema;

  constructor(schema: GraphQLSchema) {
    this._documents = new ImmutableOrderedMap();
    this.schema = schema;
  }

  /**
   * Returns the documents for the context in the order they were added.
   */
  documents(): Array<Fragment | Root> {
    return this._documents.valueSeq().map(doc => doc.get('node')).toJS();
  }

  updateSchema(schema: GraphQLSchema): RelayCompilerContext {
    const context = new RelayCompilerContext(schema);
    context._documents = this._documents;
    return context;
  }

  add(node: Fragment | Root): RelayCompilerContext {
    invariant(
      !this._documents.has(node.name),
      'RelayCompilerContext: Duplicate document named `%s`. GraphQL ' +
      'fragments and roots must have unique names.',
      node.name
    );
    return this._update(
      this._documents.set(node.name, new Document({
        name: node.name,
        node,
      }))
    );
  }

  addAll(nodes: Array<Fragment | Root>): RelayCompilerContext {
    return nodes.reduce(
      (ctx: RelayCompilerContext, definition: Fragment | Root) => ctx.add(definition),
      this,
    );
  }

  addError(name: string, error: Error): RelayCompilerContext {
    const record = this._get(name);
    let errors = record.get('errors');
    if (errors) {
      errors = errors.push(error);
    } else {
      errors = ImmutableList([error]);
    }
    return this._update(
      (this._documents.set(name, record.set('errors', errors)): $FlowFixMe)
    );
  }

  get(name: string): ?(Fragment | Root) {
    const record = this._documents.get(name);
    return record && record.get('node');
  }

  getFragment(name: string): Fragment {
    const record = this._documents.get(name);
    const node = record && record.get('node');
    invariant(
      node && node.kind === 'Fragment',
      'RelayCompilerContext: Expected `%s` to be a fragment, got `%s`.',
      name,
      node && node.kind
    );
    return node;
  }

  getRoot(name: string): Root {
    const record = this._documents.get(name);
    const node = record && record.get('node');
    invariant(
      node && node.kind === 'Root',
      'RelayCompilerContext: Expected `%s` to be a root, got `%s`.',
      name,
      node && node.kind
    );
    return node;
  }

  getErrors(name: string): ?ImmutableList<Error> {
    return this._get(name).get('errors');
  }

  remove(name: string): RelayCompilerContext {
    return this._update(
      this._documents.delete(name)
    );
  }

  _get(name: string): Document {
    const record = this._documents.get(name);
    invariant(
      record,
      'RelayCompilerContext: Unknown document `%s`.',
      name
    );
    return record;
  }

  _update(documents: ImmutableOrderedMap<string, Document>): RelayCompilerContext {
    const context = new RelayCompilerContext(this.schema);
    context._documents = documents;
    return context;
  }
}

module.exports = RelayCompilerContext;
<commit_msg>Fix last remaining flow issue<commit_after>/**
 * Copyright (c) 2013-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @flow
 * @providesModule RelayCompilerContext
 */

'use strict';

const immutable = require('immutable');
const invariant = require('invariant');

import type {
  Fragment,
  Root,
} from 'RelayIR';
import type {GraphQLSchema} from 'graphql';

const {
  List: ImmutableList,
  OrderedMap: ImmutableOrderedMap,
  Record,
} = immutable;

const Document = Record({
  errors: null,
  name: null,
  node: null,
});

/**
 * An immutable representation of a corpus of documents being compiled together.
 * For each document, the context stores the IR and any validation errors.
 */
class RelayCompilerContext {
  _documents: ImmutableOrderedMap<string, Document>;
  schema: GraphQLSchema;

  constructor(schema: GraphQLSchema) {
    this._documents = new ImmutableOrderedMap();
    this.schema = schema;
  }

  /**
   * Returns the documents for the context in the order they were added.
   */
  documents(): Array<Fragment | Root> {
    return this._documents.valueSeq().map(doc => doc.get('node')).toJS();
  }

  updateSchema(schema: GraphQLSchema): RelayCompilerContext {
    const context = new RelayCompilerContext(schema);
    context._documents = this._documents;
    return context;
  }

  add(node: Fragment | Root): RelayCompilerContext {
    invariant(
      !this._documents.has(node.name),
      'RelayCompilerContext: Duplicate document named `%s`. GraphQL ' +
      'fragments and roots must have unique names.',
      node.name
    );
    return this._update(
      (this._documents.set(node.name, new Document({
        name: node.name,
        node,
      })): $FlowFixMe)
    );
  }

  addAll(nodes: Array<Fragment | Root>): RelayCompilerContext {
    return nodes.reduce(
      (ctx: RelayCompilerContext, definition: Fragment | Root) => ctx.add(definition),
      this,
    );
  }

  addError(name: string, error: Error): RelayCompilerContext {
    const record = this._get(name);
    let errors = record.get('errors');
    if (errors) {
      errors = errors.push(error);
    } else {
      errors = ImmutableList([error]);
    }
    return this._update(
      (this._documents.set(name, record.set('errors', errors)): $FlowFixMe)
    );
  }

  get(name: string): ?(Fragment | Root) {
    const record = this._documents.get(name);
    return record && record.get('node');
  }

  getFragment(name: string): Fragment {
    const record = this._documents.get(name);
    const node = record && record.get('node');
    invariant(
      node && node.kind === 'Fragment',
      'RelayCompilerContext: Expected `%s` to be a fragment, got `%s`.',
      name,
      node && node.kind
    );
    return node;
  }

  getRoot(name: string): Root {
    const record = this._documents.get(name);
    const node = record && record.get('node');
    invariant(
      node && node.kind === 'Root',
      'RelayCompilerContext: Expected `%s` to be a root, got `%s`.',
      name,
      node && node.kind
    );
    return node;
  }

  getErrors(name: string): ?ImmutableList<Error> {
    return this._get(name).get('errors');
  }

  remove(name: string): RelayCompilerContext {
    return this._update(
      this._documents.delete(name)
    );
  }

  _get(name: string): Document {
    const record = this._documents.get(name);
    invariant(
      record,
      'RelayCompilerContext: Unknown document `%s`.',
      name
    );
    return record;
  }

  _update(documents: ImmutableOrderedMap<string, Document>): RelayCompilerContext {
    const context = new RelayCompilerContext(this.schema);
    context._documents = documents;
    return context;
  }
}

module.exports = RelayCompilerContext;
<|endoftext|>


<commit_before>(function(){

	function questionController($scope, $rootScope, $http, $q, $state, $stateParams, questionService) {

	// VARIABLE DECLARATION
		mainVm.pageName = "question"
		questionVm = this;
		questionVm.optionsCount = 4;

		marked.setOptions({
	    renderer: new marked.Renderer(),
	    gfm: true,
	    tables: true,
	    breaks: false,
	    pedantic: false,
	    sanitize: false, // if false -> allow plain old HTML ;)
	    smartLists: true,
	    smartypants: false,
	    highlight: function (code, lang) {
	      // in case, there is code without language specified
	      if (lang) {
	        return hljs.highlight(lang, code).value;
	      } else {
	        return hljs.highlightAuto(code).value;
	      }
    	}
	  });

		// See if update
		var qid = $stateParams.qid;

	// FUNCTION DECLARATION
		questionVm.addNewTag = addNewTag;
		questionVm.validateInput = validateInput;
		questionVm.initCodeMirror = initCodeMirror;
		questionVm.isCorrect = isCorrect;
		questionVm.getAllTags = getAllTags;
		questionVm.getUniqueTags = getUniqueTags;
		questionVm.onTagSelect = onTagSelect;
		questionVm.markDownFormat = markDownFormat;
		questionVm.getAllTags();

	// FUNCTION DEFINITION

		function initCodeMirror(){
			$scope.cmOption = {}
			setTimeout(function() {
				$scope.cmOption = {
			    lineNumbers: true,
			    indentWithTabs: true,
			    // mode: 'javascript',
			  }
			}, 200);
		}

		function markDownFormat(content) {
			return marked(content);
		}

		// Get all Tags
		function getAllTags() {
			mainVm.getAllTags().then(function(data){
				var data = JSON.parse(data);
				questionVm.allTags = getUniqueTags(data.debug[0].question);
			}, function(err){
				console.log(err);
			})
		}

		function addNewTag(new_tag) {
			return {
				"id": "",
				name: new_tag
			}
		}

		function getUniqueTags(allTags) {
			if(!allTags) {
				return []
			}
			var allUniqueTags = [];
			for(var i=0; i< allTags.length; i++) {
				var tagsArr = allTags[i]["question.tag"];
				if(tagsArr) {
					for (var j =0; j< tagsArr.length; j++) {
						isUnique = mainVm.indexOfObject(allUniqueTags, tagsArr[j]) == -1;
						if(isUnique) {
							allUniqueTags.push(tagsArr[j]);
						}
					}
				}
			}
			// var allUniqueTags = {};
			// var tagsLength = allTags.length;
			// for(var i = 0; i < tagsLength; i ++ ) {
			// 	allUniqueTags[allTags[i]._uid_] = allTags[i];
			// }
			return allUniqueTags;
		}

		function validateInput(inputs) {
			console.log(inputs)
			if(!inputs.name) {
				return "Please enter valid question name"
			}
			if(!inputs.text) {
				return "Please enter valid question text"
			}
			if(!inputs.positive) {
				return "Please enter valid positve marks"
			}
			if(!inputs.negative) {
				return "Please enter valid negative marks"
			}
			if(Object.keys(inputs.options).length != questionVm.optionsCount) {
				return "Please enter all the options"
			}

			hasCorrectAnswer = false
			angular.forEach(inputs.options, function(value, key) {
				if(value.is_correct) {
					hasCorrectAnswer = true;
				}
			});
			if(!hasCorrectAnswer) {
				return "Please mark atleast one correct answer"
			}

			if(!inputs.tags.length) {
				return "Please minimum one tag is required"
			}

			return false;
		}

		function isCorrect(option, correct_options) {
			var uid = option._uid_;
			if(!correct_options) {
				return false
			}
			var optLength = correct_options.length;

			for(var i = 0; i < optLength; i++) {
				if(correct_options[i]._uid_ == uid) {
					option.is_correct = true
					return true
				}
			}
			return false
		}

		function onTagSelect(item, model) {
			for(var i = 0; i < questionVm.allTags.length; i++) {
				if(item.name == questionVm.allTags[i].name && !item._uid_){
					delete model.id;
					delete model.isTag;
					model._uid_ = questionVm.allTags[i]._uid_;
				}
			}
		}
	}

	function addQuestionController($scope, $rootScope, $http, $q, $state, $stateParams, questionService) {
		// See if update
		addQueVm = this;
		addQueVm.newQuestion = {};
		addQueVm.newQuestion.tags = [];
		addQueVm.cmModel = "";

		$scope.$watch('addQueVm.cmModel', function(current, original) {
        addQueVm.outputMarked = marked(current);
    });

		//FUnction Declaration
		addQueVm.addQuestionForm = addQuestionForm;
		addQueVm.resetForm = resetForm;

		// Check if user is authorized
		function addQuestionForm() {
			var options = []
			var newOptions = angular.copy(addQueVm.newQuestion.optionsBak)
			angular.forEach(newOptions, function(value, key) {
				if(!value.is_correct) {
					value.is_correct = false;
				}
			  options.push(value);
			});
			addQueVm.newQuestion.options = options;
			addQueVm.newQuestion.text = escape(addQueVm.cmModel);
			areInValidateInput = questionVm.validateInput(addQueVm.newQuestion);
			if(areInValidateInput) {
				SNACKBAR({
					message: areInValidateInput,
					messageType: "error",
				})
				return
			}

			// Hit the API
			questionService.saveQuestion(JSON.stringify(addQueVm.newQuestion))
			.then(function(data){
				addQueVm.newQuestion = {};
				addQueVm.cmModel = "";

				if(data.code == "Error") {
					SNACKBAR({
						message: data.message,
						messageType: "error",
					})
				}
				if(data.Success) {
					SNACKBAR({
						message: data.Message,
						// messageType: "error",
					})
				}
				$state.transitionTo("question.all")
			}, function(err){
				console.log(err);
			})
		}

		$rootScope.$on('$viewContentLoaded', function() {
			questionVm.initCodeMirror();
		});

		questionVm.initCodeMirror();

		function resetForm() {
			addQueVm.cmModel = "";
			addQueVm.newQuestion = {};
			addQueVm.newQuestion.tags = [];
			$(".mdl-textfield.is-dirty").removeClass("is-dirty");
		}
	}

	function allQuestionController($scope, $rootScope, $http, $q, $state, $stateParams, questionService) {
		// VARIABLE DECLARATION
		allQVm = this;
		allQVm.showLazyLoader = false;
		allQVm.lazyStatus = true;
		allQVm.noItemFound = false;
		mainVm.allQuestions = [];

		// FUNCTION DECLARATION
		allQVm.getAllQuestions = getAllQuestions;
		allQVm.setQuestion = setQuestion;

		// INITITIALIZERS
		allQVm.getAllQuestions();
		questionVm.getAllTags();

		// FUNCTION DEFINITIONS
		function getAllQuestions(questionID) {
			if(questionID && !allQVm.lazyStatus && allQVm.noItemFound) {
				return
			}
			// API HIT
			var data = {
				"id": questionID || "",
			};
			var hideLoader = questionID ? true : false;

			allQVm.showLazyLoader = true;
			questionService.getAllQuestions(data, hideLoader).then(function(data){
				var data = JSON.parse(data);
				if(data.code == "ErrorInvalidRequest" || !data.debug[0].question) {
					allQVm.noItemFound = true;
					allQVm.showLazyLoader = false;
					return
				}

				var dataArray = data.debug[0].question;
				if(data.debug && dataArray) {
					if(mainVm.allQuestions && mainVm.allQuestions.length) {
						dataArrayLength = dataArray.length;
						for(var i = 0; i < dataArrayLength; i++) {
               mainVm.allQuestions.push(dataArray[i]);
            }
					} else {
						mainVm.allQuestions = data.debug[0].question;
						allQVm.setQuestion(mainVm.allQuestions[0], 0);
					}

					mainVm.allQuestionsBak = angular.copy(mainVm.allQuestions);
					allQVm.lastQuestion = mainVm.allQuestions[mainVm.allQuestions.length - 1]._uid_;
				}

				allQVm.lazyStatus = true;
				allQVm.showLazyLoader = false;
			}, function(err){
				allQVm.showLazyLoader = false;
				console.log(err)
			});
		}

		$(document).ready(function(){

			$(document).on("click", ".mdl-tabs__tab", function(e) {
				e.preventDefault();
			});

			$(window).unbind('scroll');
			setTimeout(function() {
				window.addEventListener('scroll', function(){
				  if($("#question-listing").length){
				    var contentLen = $('.mdl-layout__content').scrollTop() + $('.mdl-layout__content').height();
				    var docHeight = getDocHeight("question-listing");
						if(contentLen >= docHeight && allQVm.lazyStatus && mainVm.allQuestions && mainVm.allQuestions.length) {
							allQVm.getAllQuestions(allQVm.lastQuestion);
							allQVm.lazyStatus = false;
						}
					}
				}, true);
			}, 100);

		});

		function setQuestion(question, index) {
			allQVm.question = question;
			allQVm.questionIndex = index;
		}

	} // AllQuestionController

	function editQuestionController($scope, $state, $stateParams, questionService) {
		editQuesVm = this;
		editQuesVm.newQuestion = {};

		// Functin Declaratin
		editQuesVm.updateQuestionForm = updateQuestionForm;
		editQuesVm.onRemoveTag = onRemoveTag;
		editQuesVm.initMarkeDownPreview = initMarkeDownPreview;

		// INITIALIZERS
		questionVm.initCodeMirror();
		questionVm.getAllTags();

		questionService.getQuestion($stateParams.quesID)
		.then(function(data){
			editQuesVm.newQuestion = data.root[0];
			editQuesVm.cmModel = unescape(editQuesVm.newQuestion.text);
			editQuesVm.newQuestion.optionsBak = angular.copy(data.root[0]['question.option']);
			editQuesVm.newQuestion.positive = parseFloat(data.root[0].positive);
			editQuesVm.newQuestion.negative = parseFloat(data.root[0].negative);

			editQuesVm.originalQuestion = angular.copy(editQuesVm.newQuestion);

			editQuesVm.initMarkeDownPreview();
		}, function(err){
			console.log(err);
		})

		function updateQuestionForm() {

			if(editQuesVm.newQuestion.deletedTag) {
				editQuesVm.newQuestion.tags = editQuesVm.newQuestion["question.tag"].concat(editQuesVm.newQuestion.deletedTag);
			} else {
				editQuesVm.newQuestion.tags = editQuesVm.newQuestion["question.tag"];
			}

			editQuesVm.newQuestion.options = editQuesVm.newQuestion.optionsBak;
			editQuesVm.newQuestion.text = escape(editQuesVm.cmModel);
			console.log(editQuesVm.newQuestion);
			questionService.editQuestion(editQuesVm.newQuestion).then(function(data){
				SNACKBAR({
					message: data.Message,
				});
				$state.transitionTo("question.all")
			}, function(err){
				console.log(err);
			})
		}

		function resetQuestion(index) {
			editQuesVm.newQuestion = angular.copy(editQuesVm.originalQuestion);

			$rootScope.updgradeMDL();
		}

		function onRemoveTag(tag, model, question) {
			if(tag._uid_) {
				tag.is_delete = true;
				question.deletedTag = question.deletedTag || [];
				question.deletedTag.push(tag);
			}
		}

		function initMarkeDownPreview() {
			$scope.$watch('editQuesVm.cmModel', function(current, original) {
	        editQuesVm.outputMarked = marked(current);
	    });
		}
	}

	var editQuestionDependency = [
			"$scope",
	    "$state",
	    "$stateParams",
	    "questionService",
	    editQuestionController
	];
	angular.module('GruiApp').controller('editQuestionController', editQuestionDependency);

	var allQuestionDependency = [
	    "$scope",
	    "$rootScope",
	    "$http",
	    "$q",
	    "$state",
	    "$stateParams",
	    "questionService",
	    allQuestionController
	];
	angular.module('GruiApp').controller('allQuestionController', allQuestionDependency);

	var addQuestionDependency = [
	    "$scope",
	    "$rootScope",
	    "$http",
	    "$q",
	    "$state",
	    "$stateParams",
	    "questionService",
	    addQuestionController
	];
	angular.module('GruiApp').controller('addQuestionController', addQuestionDependency);

	var questionDependency = [
	    "$scope",
	    "$rootScope",
	    "$http",
	    "$q",
	    "$state",
	    "$stateParams",
	    "questionService",
	    questionController
	];
	angular.module('GruiApp').controller('questionController', questionDependency);

})();<commit_msg>You ought to fix what you break even if its Angular<commit_after>(function(){

	function questionController($scope, $rootScope, $http, $q, $state, $stateParams, questionService) {

	// VARIABLE DECLARATION
		mainVm.pageName = "question"
		questionVm = this;
		questionVm.optionsCount = 4;

		marked.setOptions({
	    renderer: new marked.Renderer(),
	    gfm: true,
	    tables: true,
	    breaks: false,
	    pedantic: false,
	    sanitize: false, // if false -> allow plain old HTML ;)
	    smartLists: true,
	    smartypants: false,
	    highlight: function (code, lang) {
	      // in case, there is code without language specified
	      if (lang) {
	        return hljs.highlight(lang, code).value;
	      } else {
	        return hljs.highlightAuto(code).value;
	      }
    	}
	  });

		// See if update
		var qid = $stateParams.qid;

	// FUNCTION DECLARATION
		questionVm.addNewTag = addNewTag;
		questionVm.validateInput = validateInput;
		questionVm.initCodeMirror = initCodeMirror;
		questionVm.isCorrect = isCorrect;
		questionVm.getAllTags = getAllTags;
		questionVm.getUniqueTags = getUniqueTags;
		questionVm.onTagSelect = onTagSelect;
		questionVm.markDownFormat = markDownFormat;
		questionVm.getAllTags();

	// FUNCTION DEFINITION

		function initCodeMirror(){
			$scope.cmOption = {}
			setTimeout(function() {
				$scope.cmOption = {
			    lineNumbers: true,
			    indentWithTabs: true,
			    // mode: 'javascript',
			  }
			}, 200);
		}

		function markDownFormat(content) {
			return marked(content);
		}

		// Get all Tags
		function getAllTags() {
			mainVm.getAllTags().then(function(data){
				var data = JSON.parse(data);
				questionVm.allTags = getUniqueTags(data.debug[0].question);
			}, function(err){
				console.log(err);
			})
		}

		function addNewTag(new_tag) {
			return {
				"id": "",
				name: new_tag
			}
		}

		function getUniqueTags(allTags) {
			if(!allTags) {
				return []
			}
			var allUniqueTags = [];
			for(var i=0; i< allTags.length; i++) {
				var tagsArr = allTags[i]["question.tag"];
				if(tagsArr) {
					for (var j =0; j< tagsArr.length; j++) {
						isUnique = mainVm.indexOfObject(allUniqueTags, tagsArr[j]) == -1;
						if(isUnique) {
							allUniqueTags.push(tagsArr[j]);
						}
					}
				}
			}
			// var allUniqueTags = {};
			// var tagsLength = allTags.length;
			// for(var i = 0; i < tagsLength; i ++ ) {
			// 	allUniqueTags[allTags[i]._uid_] = allTags[i];
			// }
			return allUniqueTags;
		}

		function validateInput(inputs) {
			console.log(inputs)
			if(!inputs.name) {
				return "Please enter valid question name"
			}
			if(!inputs.text) {
				return "Please enter valid question text"
			}
			if(!inputs.positive) {
				return "Please enter valid positve marks"
			}
			if(!inputs.negative) {
				return "Please enter valid negative marks"
			}
			if(Object.keys(inputs.options).length != questionVm.optionsCount) {
				return "Please enter all the options"
			}

			hasCorrectAnswer = false
			angular.forEach(inputs.options, function(value, key) {
				if(value.is_correct) {
					hasCorrectAnswer = true;
				}
			});
			if(!hasCorrectAnswer) {
				return "Please mark atleast one correct answer"
			}

			if(!inputs.tags.length) {
				return "Please minimum one tag is required"
			}

			return false;
		}

		function isCorrect(option, correct_options) {
			var uid = option._uid_;
			if(!correct_options) {
				return false
			}
			var optLength = correct_options.length;

			for(var i = 0; i < optLength; i++) {
				if(correct_options[i]._uid_ == uid) {
					option.is_correct = true
					return true
				}
			}
			return false
		}

		function onTagSelect(item, model) {
			for(var i = 0; i < questionVm.allTags.length; i++) {
				if(item.name == questionVm.allTags[i].name && !item._uid_){
					delete model.id;
					delete model.isTag;
					model._uid_ = questionVm.allTags[i]._uid_;
				}
			}
		}
	}

	function addQuestionController($scope, $rootScope, $http, $q, $state, $stateParams, questionService) {
		// See if update
		addQueVm = this;
		addQueVm.newQuestion = {};
		addQueVm.newQuestion.tags = [];
		addQueVm.cmModel = "";

		$scope.$watch('addQueVm.cmModel', function(current, original) {
        addQueVm.outputMarked = marked(current);
    });

		//FUnction Declaration
		addQueVm.addQuestionForm = addQuestionForm;
		addQueVm.resetForm = resetForm;

		// Check if user is authorized
		function addQuestionForm() {
			var options = []
			var newOptions = angular.copy(addQueVm.newQuestion.optionsBak)
			angular.forEach(newOptions, function(value, key) {
				if(!value.is_correct) {
					value.is_correct = false;
				}
			  options.push(value);
			});
			addQueVm.newQuestion.options = options;
			addQueVm.newQuestion.text = escape(addQueVm.cmModel);
			areInValidateInput = questionVm.validateInput(addQueVm.newQuestion);
			if(areInValidateInput) {
				SNACKBAR({
					message: areInValidateInput,
					messageType: "error",
				})
				return
			}

			// Hit the API
			questionService.saveQuestion(JSON.stringify(addQueVm.newQuestion))
			.then(function(data){
				addQueVm.newQuestion = {};
				addQueVm.cmModel = "";

				if(data.code == "Error") {
					SNACKBAR({
						message: data.message,
						messageType: "error",
					})
				}
				if(data.Success) {
					SNACKBAR({
						message: data.Message,
						// messageType: "error",
					})
				}
				$state.transitionTo("question.all")
			}, function(err){
				console.log(err);
			})
		}

		$rootScope.$on('$viewContentLoaded', function() {
			questionVm.initCodeMirror();
		});

		questionVm.initCodeMirror();

		function resetForm() {
			addQueVm.cmModel = "";
			addQueVm.newQuestion = {};
			addQueVm.newQuestion.tags = [];
			$(".mdl-textfield.is-dirty").removeClass("is-dirty");
		}
	}

	function allQuestionController($scope, $rootScope, $http, $q, $state, $stateParams, questionService) {
		// VARIABLE DECLARATION
		allQVm = this;
		allQVm.showLazyLoader = false;
		allQVm.lazyStatus = true;
		allQVm.noItemFound = false;
		mainVm.allQuestions = [];

		// FUNCTION DECLARATION
		allQVm.getAllQuestions = getAllQuestions;
		allQVm.setQuestion = setQuestion;

		// INITITIALIZERS
		allQVm.getAllQuestions();
		questionVm.getAllTags();

		// FUNCTION DEFINITIONS
		function getAllQuestions(questionID) {
			if(questionID && !allQVm.lazyStatus && allQVm.noItemFound) {
				return
			}
			// API HIT
			var data = {
				"id": questionID || "",
			};
			var hideLoader = questionID ? true : false;

			allQVm.showLazyLoader = true;
			questionService.getAllQuestions(data, hideLoader).then(function(data){
				if(data.code == "ErrorInvalidRequest" || !data.debug[0].question) {
					allQVm.noItemFound = true;
					allQVm.showLazyLoader = false;
					return
				}

				var dataArray = data.debug[0].question;
				if(data.debug && dataArray) {
					if(mainVm.allQuestions && mainVm.allQuestions.length) {
						dataArrayLength = dataArray.length;
						for(var i = 0; i < dataArrayLength; i++) {
               mainVm.allQuestions.push(dataArray[i]);
            }
					} else {
						mainVm.allQuestions = data.debug[0].question;
						allQVm.setQuestion(mainVm.allQuestions[0], 0);
					}

					mainVm.allQuestionsBak = angular.copy(mainVm.allQuestions);
					allQVm.lastQuestion = mainVm.allQuestions[mainVm.allQuestions.length - 1]._uid_;
				}

				allQVm.lazyStatus = true;
				allQVm.showLazyLoader = false;
			}, function(err){
				allQVm.showLazyLoader = false;
				console.log(err)
			});
		}

		$(document).ready(function(){

			$(document).on("click", ".mdl-tabs__tab", function(e) {
				e.preventDefault();
			});

			$(window).unbind('scroll');
			setTimeout(function() {
				window.addEventListener('scroll', function(){
				  if($("#question-listing").length){
				    var contentLen = $('.mdl-layout__content').scrollTop() + $('.mdl-layout__content').height();
				    var docHeight = getDocHeight("question-listing");
						if(contentLen >= docHeight && allQVm.lazyStatus && mainVm.allQuestions && mainVm.allQuestions.length) {
							allQVm.getAllQuestions(allQVm.lastQuestion);
							allQVm.lazyStatus = false;
						}
					}
				}, true);
			}, 100);

		});

		function setQuestion(question, index) {
			allQVm.question = question;
			allQVm.questionIndex = index;
		}

	} // AllQuestionController

	function editQuestionController($scope, $state, $stateParams, questionService) {
		editQuesVm = this;
		editQuesVm.newQuestion = {};

		// Functin Declaratin
		editQuesVm.updateQuestionForm = updateQuestionForm;
		editQuesVm.onRemoveTag = onRemoveTag;
		editQuesVm.initMarkeDownPreview = initMarkeDownPreview;

		// INITIALIZERS
		questionVm.initCodeMirror();
		questionVm.getAllTags();

		questionService.getQuestion($stateParams.quesID)
		.then(function(data){
			editQuesVm.newQuestion = data.root[0];
			editQuesVm.cmModel = unescape(editQuesVm.newQuestion.text);
			editQuesVm.newQuestion.optionsBak = angular.copy(data.root[0]['question.option']);
			editQuesVm.newQuestion.positive = parseFloat(data.root[0].positive);
			editQuesVm.newQuestion.negative = parseFloat(data.root[0].negative);

			editQuesVm.originalQuestion = angular.copy(editQuesVm.newQuestion);

			editQuesVm.initMarkeDownPreview();
		}, function(err){
			console.log(err);
		})

		function updateQuestionForm() {

			if(editQuesVm.newQuestion.deletedTag) {
				editQuesVm.newQuestion.tags = editQuesVm.newQuestion["question.tag"].concat(editQuesVm.newQuestion.deletedTag);
			} else {
				editQuesVm.newQuestion.tags = editQuesVm.newQuestion["question.tag"];
			}

			editQuesVm.newQuestion.options = editQuesVm.newQuestion.optionsBak;
			editQuesVm.newQuestion.text = escape(editQuesVm.cmModel);
			console.log(editQuesVm.newQuestion);
			questionService.editQuestion(editQuesVm.newQuestion).then(function(data){
				SNACKBAR({
					message: data.Message,
				});
				$state.transitionTo("question.all")
			}, function(err){
				console.log(err);
			})
		}

		function resetQuestion(index) {
			editQuesVm.newQuestion = angular.copy(editQuesVm.originalQuestion);

			$rootScope.updgradeMDL();
		}

		function onRemoveTag(tag, model, question) {
			if(tag._uid_) {
				tag.is_delete = true;
				question.deletedTag = question.deletedTag || [];
				question.deletedTag.push(tag);
			}
		}

		function initMarkeDownPreview() {
			$scope.$watch('editQuesVm.cmModel', function(current, original) {
	        editQuesVm.outputMarked = marked(current);
	    });
		}
	}

	var editQuestionDependency = [
			"$scope",
	    "$state",
	    "$stateParams",
	    "questionService",
	    editQuestionController
	];
	angular.module('GruiApp').controller('editQuestionController', editQuestionDependency);

	var allQuestionDependency = [
	    "$scope",
	    "$rootScope",
	    "$http",
	    "$q",
	    "$state",
	    "$stateParams",
	    "questionService",
	    allQuestionController
	];
	angular.module('GruiApp').controller('allQuestionController', allQuestionDependency);

	var addQuestionDependency = [
	    "$scope",
	    "$rootScope",
	    "$http",
	    "$q",
	    "$state",
	    "$stateParams",
	    "questionService",
	    addQuestionController
	];
	angular.module('GruiApp').controller('addQuestionController', addQuestionDependency);

	var questionDependency = [
	    "$scope",
	    "$rootScope",
	    "$http",
	    "$q",
	    "$state",
	    "$stateParams",
	    "questionService",
	    questionController
	];
	angular.module('GruiApp').controller('questionController', questionDependency);

})();
<|endoftext|>


<commit_before>/**
 * A base class for a comment and the line of code following it.
 * @hide
 */
DocumentJS.Class.extend("DocumentJS.Pair",
/* @Static */
{
    code_match: function(){ return null},
    classes: [],
    /**
     * From the comment and code, guesses at the type of comment and creates a new
     * instance of that type.
     * @param {String} comment - the comment
     * @param {String} code - the first line of source following the comment
     * @param {DocumentJS.Pair} scope - The current scope of documentation.
     * This is typically a Class, Constructor, Static, or Prototype
     * @return {DocumentJS.Pair} - If a type can be found, the new Doc object; otherwise, null.
     */
    create: function(comment, code, scope){
        var check =  comment.match(/^@(\w+)/), type

        if(!(type = this.has_type(check ? check[1] : null)) ){ //try code
            type = this.guess_type(code);
        }
        if(!type) return null;

		return new type(comment, code, scope)
    },
    /**
     * Looks for a Doc class with a shortName for the given type
     * @param {String} type a potential shortName
     */
    has_type: function(type){
        if(!type) return null;
		for(var i=0;i< this.classes.length; i++){
            if(this.classes[i].shortName.toLowerCase() == type.toLowerCase() )
                return this.classes[i];
        }
        return null;
    },
    /**
     * Tries to guess at a piece of code's type.
     * @param {Object} code
     */
    guess_type: function(code){

		for(var i=0;i< this.classes.length; i++){
            if(this.classes[i].code_match(code) )
                return this.classes[i];
        }
        return null;
    },
	suggest_type : function(incorrect, line){
		var lowest = 1000, suggest = "";
		for(var i=0;i< this.classes.length; i++){
            var dist = DocumentJS.distance(incorrect.toLowerCase(), this.classes[i].shortName.toLowerCase())
			if(dist < lowest ){
				lowest = dist
				suggest = this.classes[i].shortName.toLowerCase()
			}
        }
		for(var i=0;i< DocumentJS.Directive.directives.length; i++){
            var dist = DocumentJS.distance(incorrect.toLowerCase(),  DocumentJS.Directive.directives[i].toLowerCase())
			if(dist < lowest ){
				lowest = dist
				suggest = DocumentJS.Directive.directives[i].toLowerCase()
			}
        }
		if(suggest){
			print("\nWarning!!\nThere is no @"+incorrect+" directive. did you mean @"+suggest+" ?\n")
		}
	},
    starts_scope: false,
    /**
     * Given a and b, sorts by their full_name property.
     * @param {Object} a
     * @param {Object} b
     */
    sort_by_full_name : function(a, b){
       var af = a.full_name ? a.full_name.toLowerCase() : a.full_name
       var bf = b.full_name ? b.full_name.toLowerCase() : a.full_name
       if(af == bf) return 0;
       return af > bf ? 1: -1;
    },
    sort_by_name : function(a, b){
       var af = a.name ? a.name.toLowerCase() : a.name
       var bf = b.name ? b.name.toLowerCase() : a.name

       if(af == bf) return 0;
       return af > bf ? 1: -1;
    },
    /**
     * Loads a template to use to render different doc types.
     */
    init : function(){
		if(this.shortName){
			 if(DocumentJS.Pair)
			 	DocumentJS.Pair.classes.push(this)
        }
		this.listing = [];
    },
    /**
     * Adds [DocumentJS.Directive|directives] to this class.
     * @codestart
     * {
     *   init: function(){
     *     this._super();
     *     this.add(DocumentJS.Directive.Return, DocumentJS.Directive.Param)
     *   }
     * }
     * @codeend
     */
    add : function(){
        var args = DocumentJS.makeArray(arguments)
        for(var i = 0; i < args.length; i++){
            this._add(args[i]);
        }
    },
    _add : function(directive){
        var start = directive.shortName.toLowerCase()+"_"
        this.prototype[start+"add"] = directive.prototype.add
        if(directive.prototype.add_more)
            this.prototype[start+"add_more"] = directive.prototype.add_more
    },
    matchDirective : /^\s*@(\w+)/
},
/* @Prototype */
{
    /**
     * Saves coment, code.  Adds self to parent.  Calls code_setup and comment_setup.
     * Finally, adds to DocumentJS.objects.
     * @param {String} comment
     * @param {String} code
     * @param {DocumentJS.Pair} scope
     */
    init : function(comment, code, scope ){
		this.children = [];
		this.shallowParents = [];
        this.comment = comment;
        this.code = code;

        if(this.Class.code_match(this.code))
            this.code_setup();
        this.comment_setup();

		//we need to add to a class if we
		this.add_parent(scope);

        var par = this;
        while(par && !par.url){
            par = par.parent;
        }
        if(par){
            DocumentJS.objects[this.full_name()] = par.url()+(this.url ? "" : "#"+this.full_name() );
        }
		this.Class.listing.push(this);
		if(DocumentJS.Directive.Parent.waiting.hasOwnProperty(this.name)){
			var addOns = DocumentJS.Directive.Parent.waiting[this.name]
			this.children = this.children.concat(addOns)
			for(var i=0;i< addOns.length;i++){
				addOns[i].shallowParents.push(this);
			}
		}
    },
    add: function(child){
        this.children.push(child);
    },
    add_parent : function(scope){
         this.parent = scope;
         this.parent.add(this);
    },
    scope: function(){
        return this.Class.starts_scope ? this : this.parent
    },
    code_setup: function(){},
	jsonp: function(){
		return "C("+$.toJSON(this.json())+")";
	},
    full_name: function(){
        var par = ""
        //print("has parent "+this.parent)
		if(!this.parent){
            print(this.name+" has no parent ")
        }else
            par = this.parent.full_name();
        //print(par+" - "+this.name)
		return (par ? par+"." : "")+this.name ;
    },
    make : function(arr){
        var res = ["
"];
        //we should alphabetize by name

        for(var c=0; c<arr.length; c++){
            var child = arr[c];
            res.push(child.toHTML());
        }
        res.push("
");
        return res.join("");
    },
	/**
	 * Checks if this child should not add its children for the given parent
	 */
	shallowParent : function(parent){
		for(var i = 0; i < this.shallowParents.length;i++){
			if(this.shallowParents[i] === parent){
				return true;
			}
		}
		return false;
	},
    linker : function(stealSelf, parent){
        var result = stealSelf ? [ {name: this.full_name(), shortName : this.Class.shortName.toLowerCase(), title: this.title, hide: (this.hide ? true: false) }] : [];
		if(this.children && ! this.shallowParent(parent)){
            //print(this.name)
			for(var c=0; c<this.children.length; c++){
                var adds = this.children[c].linker(true, this);
                if(adds)
                    result = result.concat( adds );
            }
        }
        return result;
    },
    /**
     * Orders params into an array.
     */
    ordered_params : function(){
            var arr = [];
            for(var n in this.params){
                var param = this.params[n];
                arr[param.order] = param;
            }
            return arr;
    },
    /**
     * Goes through the comment line by line.  Searches for lines starting with a @directive.
     * If a line with a directive is found, it sees if the instance has a function that matches
     * directive_add exists.  If it does, directive_add is called on that object.
     * If following lines do not have a directive, the directive_add_more function is called
     * on the instance
     *

     * Initial comments are added to real_comment.

     * This function is shared by Class and Constructor.
     */
    comment_setup: function(){
        var i = 0,
			lines = this.comment.split("\n"),
			last,
			last_data; //what data we are going to be called with

		this.real_comment = '';
        if(!this.params) this.params = {};
        if(!this.ret) this.ret = {type: 'undefined',description: ""};

		this._last; //what we should be adding too.

        for(var l=0; l < lines.length; l++){
            var line = lines[l];
            var match = line.match(DocumentJS.Pair.matchDirective)
            if(match){

                var fname = (match[1]+'_add').toLowerCase();
                if(! this[fname]) {
                    if(!DocumentJS.Pair.has_type(match[1])){
						DocumentJS.Pair.suggest_type(match[1])
					}

					this.real_comment+= line+"\n"
                    continue;
                }
                last_data = this[fname](line, last_data);
                //horrible ... fix
				if (last_data && last_data.length == 2 && last_data[0] == 'keep') {
					last_data = last_data[1]
				}else if (last_data) {
					this._last = match[1].toLowerCase();
				}
				else {
					this._last = null;
				}

            }
            else if(!line.match(/^constructor/i) && !this._last )
                this.real_comment+= line+"\n"
            else if(this._last && this[this._last+'_add_more']){
                this[this._last+'_add_more'](line, last_data);
            }
        }
        if(this.comment_setup_complete) this.comment_setup_complete();
    },
	shortName : function(){
		return this.Class.shortName;
	}
})<commit_msg>handles @@<commit_after>/**
 * A base class for a comment and the line of code following it.
 * @hide
 */
DocumentJS.Class.extend("DocumentJS.Pair",
/* @Static */
{
    code_match: function(){ return null},
    classes: [],
    /**
     * From the comment and code, guesses at the type of comment and creates a new
     * instance of that type.
     * @param {String} comment - the comment
     * @param {String} code - the first line of source following the comment
     * @param {DocumentJS.Pair} scope - The current scope of documentation.
     * This is typically a Class, Constructor, Static, or Prototype
     * @return {DocumentJS.Pair} - If a type can be found, the new Doc object; otherwise, null.
     */
    create: function(comment, code, scope){
        var check =  comment.match(/^@(\w+)/), type

        if(!(type = this.has_type(check ? check[1] : null)) ){ //try code
            type = this.guess_type(code);
        }
        if(!type) return null;

		return new type(comment, code, scope)
    },
    /**
     * Looks for a Doc class with a shortName for the given type
     * @param {String} type a potential shortName
     */
    has_type: function(type){
        if(!type) return null;
		for(var i=0;i< this.classes.length; i++){
            if(this.classes[i].shortName.toLowerCase() == type.toLowerCase() )
                return this.classes[i];
        }
        return null;
    },
    /**
     * Tries to guess at a piece of code's type.
     * @param {Object} code
     */
    guess_type: function(code){

		for(var i=0;i< this.classes.length; i++){
            if(this.classes[i].code_match(code) )
                return this.classes[i];
        }
        return null;
    },
	suggest_type : function(incorrect, line){
		var lowest = 1000, suggest = "";
		for(var i=0;i< this.classes.length; i++){
            var dist = DocumentJS.distance(incorrect.toLowerCase(), this.classes[i].shortName.toLowerCase())
			if(dist < lowest ){
				lowest = dist
				suggest = this.classes[i].shortName.toLowerCase()
			}
        }
		for(var i=0;i< DocumentJS.Directive.directives.length; i++){
            var dist = DocumentJS.distance(incorrect.toLowerCase(),  DocumentJS.Directive.directives[i].toLowerCase())
			if(dist < lowest ){
				lowest = dist
				suggest = DocumentJS.Directive.directives[i].toLowerCase()
			}
        }
		if(suggest){
			print("\nWarning!!\nThere is no @"+incorrect+" directive. did you mean @"+suggest+" ?\n")
		}
	},
    starts_scope: false,
    /**
     * Given a and b, sorts by their full_name property.
     * @param {Object} a
     * @param {Object} b
     */
    sort_by_full_name : function(a, b){
       var af = a.full_name ? a.full_name.toLowerCase() : a.full_name
       var bf = b.full_name ? b.full_name.toLowerCase() : a.full_name
       if(af == bf) return 0;
       return af > bf ? 1: -1;
    },
    sort_by_name : function(a, b){
       var af = a.name ? a.name.toLowerCase() : a.name
       var bf = b.name ? b.name.toLowerCase() : a.name

       if(af == bf) return 0;
       return af > bf ? 1: -1;
    },
    /**
     * Loads a template to use to render different doc types.
     */
    init : function(){
		if(this.shortName){
			 if(DocumentJS.Pair)
			 	DocumentJS.Pair.classes.push(this)
        }
		this.listing = [];
    },
    /**
     * Adds [DocumentJS.Directive|directives] to this class.
     * @codestart
     * {
     *   init: function(){
     *     this._super();
     *     this.add(DocumentJS.Directive.Return, DocumentJS.Directive.Param)
     *   }
     * }
     * @codeend
     */
    add : function(){
        var args = DocumentJS.makeArray(arguments)
        for(var i = 0; i < args.length; i++){
            this._add(args[i]);
        }
    },
    _add : function(directive){
        var start = directive.shortName.toLowerCase()+"_"
        this.prototype[start+"add"] = directive.prototype.add
        if(directive.prototype.add_more)
            this.prototype[start+"add_more"] = directive.prototype.add_more
    },
    matchDirective : /^\s*@(\w+)/
},
/* @Prototype */
{
    /**
     * Saves coment, code.  Adds self to parent.  Calls code_setup and comment_setup.
     * Finally, adds to DocumentJS.objects.
     * @param {String} comment
     * @param {String} code
     * @param {DocumentJS.Pair} scope
     */
    init : function(comment, code, scope ){
		this.children = [];
		this.shallowParents = [];
        this.comment = comment;
        this.code = code;

        if(this.Class.code_match(this.code))
            this.code_setup();
        this.comment_setup();

		//we need to add to a class if we
		this.add_parent(scope);

        var par = this;
        while(par && !par.url){
            par = par.parent;
        }
        if(par){
            DocumentJS.objects[this.full_name()] = par.url()+(this.url ? "" : "#"+this.full_name() );
        }
		this.Class.listing.push(this);
		if(DocumentJS.Directive.Parent.waiting.hasOwnProperty(this.name)){
			var addOns = DocumentJS.Directive.Parent.waiting[this.name]
			this.children = this.children.concat(addOns)
			for(var i=0;i< addOns.length;i++){
				addOns[i].shallowParents.push(this);
			}
		}
    },
    add: function(child){
        this.children.push(child);
    },
    add_parent : function(scope){
         this.parent = scope;
         this.parent.add(this);
    },
    scope: function(){
        return this.Class.starts_scope ? this : this.parent
    },
    code_setup: function(){},
	jsonp: function(){
		return "C("+$.toJSON(this.json())+")";
	},
    full_name: function(){
        var par = ""
        //print("has parent "+this.parent)
		if(!this.parent){
            print(this.name+" has no parent ")
        }else
            par = this.parent.full_name();
        //print(par+" - "+this.name)
		return (par ? par+"." : "")+this.name ;
    },
    make : function(arr){
        var res = ["
"];
        //we should alphabetize by name

        for(var c=0; c<arr.length; c++){
            var child = arr[c];
            res.push(child.toHTML());
        }
        res.push("
");
        return res.join("");
    },
	/**
	 * Checks if this child should not add its children for the given parent
	 */
	shallowParent : function(parent){
		for(var i = 0; i < this.shallowParents.length;i++){
			if(this.shallowParents[i] === parent){
				return true;
			}
		}
		return false;
	},
    linker : function(stealSelf, parent){
        var result = stealSelf ? [ {name: this.full_name(), shortName : this.Class.shortName.toLowerCase(), title: this.title, hide: (this.hide ? true: false) }] : [];
		if(this.children && ! this.shallowParent(parent)){
            //print(this.name)
			for(var c=0; c<this.children.length; c++){
                var adds = this.children[c].linker(true, this);
                if(adds)
                    result = result.concat( adds );
            }
        }
        return result;
    },
    /**
     * Orders params into an array.
     */
    ordered_params : function(){
            var arr = [];
            for(var n in this.params){
                var param = this.params[n];
                arr[param.order] = param;
            }
            return arr;
    },
    /**
     * Goes through the comment line by line.  Searches for lines starting with a @directive.
     * If a line with a directive is found, it sees if the instance has a function that matches
     * directive_add exists.  If it does, directive_add is called on that object.
     * If following lines do not have a directive, the directive_add_more function is called
     * on the instance
     *

     * Initial comments are added to real_comment.

     * This function is shared by Class and Constructor.
     */
    comment_setup: function(){
        var i = 0,
			lines = this.comment.split("\n"),
			last,
			last_data; //what data we are going to be called with

		this.real_comment = '';
        if(!this.params) this.params = {};
        if(!this.ret) this.ret = {type: 'undefined',description: ""};

		this._last; //what we should be adding too.

        for(var l=0; l < lines.length; l++){
            var line = lines[l],
				match = line.match(DocumentJS.Pair.matchDirective)

			if (match) {

				var fname = (match[1] + '_add').toLowerCase();
				if (!this[fname]) {
					if (!DocumentJS.Pair.has_type(match[1])) {
						DocumentJS.Pair.suggest_type(match[1])
					}

					this.real_comment += line + "\n"
					continue;
				}
				last_data = this[fname](line, last_data);
				//horrible ... fix
				if (last_data && last_data.length == 2 && last_data[0] == 'keep') {
					last_data = last_data[1]
				}
				else
					if (last_data) {
						this._last = match[1].toLowerCase();
					}
					else {
						this._last = null;
					}

			}
			else {
				line = line.replace(/@@/g,"@")
				if (!line.match(/^constructor/i) && !this._last) {
					this.real_comment += line + "\n"
				}
				else if (this._last && this[this._last + '_add_more']) {
					this[this._last + '_add_more'](line, last_data);
				}
			}
        }
        if(this.comment_setup_complete) this.comment_setup_complete();
    },
	shortName : function(){
		return this.Class.shortName;
	}
})<|endoftext|>