<commit_before>import _ from 'underscore';
import $ from 'jquery';
import is from 'is_js';
import baseVw from '../baseVw';
import loadTemplate from '../../utils/loadTemplate';
import app from '../../app';
import { openSimpleMessage } from '../modals/SimpleMessage';
import Dialog from '../modals/Dialog';
import Results from './Results';
import ResultsCol from '../../collections/Results';
import Providers from './SearchProviders';
import ProviderMd from '../../models/search/SearchProvider';
import { selectEmojis } from '../../utils';
import { getCurrentConnection } from '../../utils/serverConnect';

export default class extends baseVw {
  constructor(options = {}) {
    const opts = {
      initialState: {
        fetching: false,
        ...options.initialState,
      },
      ...options,
    };

    super(opts);
    this.options = opts;

    this.searchProviders = this.createChild(Providers, { usingTor: this.usingTor });
    this.listenTo(this.searchProviders, 'activateProvider', pOpts => this.activateProvider(pOpts));

    if (options.query) {
      // the user arrived here from the address bar, use the default provider
      this.sProvider = app.searchProviders[`default${this.torString}Provider`];
    } else {
      // the user arrived from the discover button, use the active provider
      this.sProvider = app.searchProviders[`active${this.torString}Provider`];
    }

    // if the  provider returns a bad URL, reset to the original provider
    // this should never happen unless the local data is manually altered or corrupted
    if (is.not.url(this.providerUrl)) {
      this.sProvider = app.searchProviders.at(0);
    }

    const tempUrl = new URL(`${this.providerUrl}?${options.query || ''}`);
    let queryParams = tempUrl.searchParams;

    // if a url with parameters was in the query in, use the parameters in it instead.
    if (queryParams.get('providerQ')) {
      const subURL = new URL(queryParams.get('providerQ'));
      queryParams = subURL.searchParams;
      const base = `${subURL.origin}${subURL.pathname}`;
      const matchedProvider =
        app.searchProviders.filter(p =>
          base === p.get('listings') || base === p.get('torlistings'));

      /* if the query provider doesn't exist, create a temporary provider model for it.
         One quirk to note: if a tor url is passed in while the user is in clear mode, and an
         existing provider has that tor url, that provider will be activated but will use its
         clear url if it has one. The opposite is also true.
       */
      if (!matchedProvider.length) {
        const queryOpts = {};
        queryOpts[`${this.usingTor ? 'tor' : ''}listings`] = `${subURL.origin}${subURL.pathname}`;
        this.queryProvider = new ProviderMd(queryOpts);
      } else {
        this.sProvider = matchedProvider[0];
        this.queryProvider = null;
      }
    }

    const params = {};

    for (const param of queryParams.entries()) {
      params[param[0]] = param[1];
    }

    // use the parameters from the query unless they were overridden in the options
    this.serverPage = options.serverPage || params.p || 0;
    this.pageSize = options.pageSize || params.ps || 12;
    this.term = options.term || params.q || '';
    this.sortBySelected = options.sortBySelected || params.sortBy || '';
    // all parameters not specified above are assumed to be filters
    this.filters = _.omit(params, ['q', 'p', 'ps', 'sortBy', 'providerQ']);

    this.processTerm(this.term);

    // TODO: remove the ability to set the default in the settings
  }

  className() {
    return 'search';
  }

  events() {
    return {
      'click .js-searchBtn': 'clickSearchBtn',
      'change .js-sortBy': 'changeSortBy',
      'change .js-filterWrapper select': 'changeFilter',
      'change .js-filterWrapper input': 'changeFilter',
      'keyup .js-searchInput': 'onKeyupSearchInput',
      'click .js-deleteProvider': 'clickDeleteProvider',
      'click .js-makeDefaultProvider': 'clickMakeDefaultProvider',
      'click .js-addQueryProvider': 'clickAddQueryProvider',
    };
  }

  get usingOriginal() {
    return this.sProvider === app.searchProviders.at(0);
  }

  get usingTor() {
    return app.serverConfig.tor && getCurrentConnection().server.get('useTor');
  }

  get torString() {
    return this.usingTor ? 'Tor' : '';
  }

  get providerUrl() {
    // if a provider was created by the address bar query, use it instead
    const currentProvider = this.queryProvider || this.sProvider;
    return currentProvider.get(`${this.usingTor ? 'tor' : ''}listings`);
  }

  /**
   * This will set either the current active or default provider. If the user is currently in
   * Tor mode, the active or default Tor provider will be set.
   * @param md the search provider model
   * @param type should be active or default
   */
  activateProvider(md, type = 'active') {
    const types = ['active', 'default'];
    if (!md || !(md instanceof ProviderMd)) {
      throw new Error('Please provide a search provider model.');
    }
    if (!type || types.indexOf(type) === -1) {
      throw new Error('You must use a valid provider type.');
    }
    if (app.searchProviders.indexOf(md) === -1) {
      throw new Error('The provider must be in the collection.');
    }
    app.searchProviders[`${type}${this.torString}Provider`] = md;
    this.sProvider = md;
    this.queryProvider = null;
    this.processTerm(this.term);
  }

  deleteProvider(md = this.sProvider) {
    if (md.get('locked')) {
      openSimpleMessage(app.polyglot.t('search.errors.locked'));
    } else {
      md.destroy();
      if (app.searchProviders.length) this.activateProvider(app.searchProviders.at(0));
    }
  }

  clickDeleteProvider() {
    this.deleteProvider();
  }

  makeDefaultProvider() {
    app.searchProviders.defaultProvider = this.sProvider;
    this.getCachedEl('.js-makeDefaultProvider').addClass('hide');
  }

  clickMakeDefaultProvider() {
    this.makeDefaultProvider();
  }

  addQueryProvider() {
    if (this.queryProvider) app.searchProviders.add(this.queryProvider);
    this.activateProvider(this.queryProvider);
  }

  clickAddQueryProvider() {
    this.addQueryProvider();
  }

  /**
   * This will create a url with the term and other query parameters
   * @param {string} term
   */
  processTerm(term) {
    this.term = term || '';
    // if term is false, search for *
    const query = `q=${encodeURIComponent(term || '*')}`;
    const page = `&p=${this.serverPage}&ps=${this.pageSize}`;
    const sortBy = this.sortBySelected ? `&sortBy=${encodeURIComponent(this.sortBySelected)}` : '';
    let filters = $.param(this.filters);
    filters = filters ? `&${filters}` : '';
    const newURL = `${this.providerUrl}?${query}${sortBy}${page}${filters}`;
    this.callSearchProvider(newURL);
  }

  callSearchProvider(searchUrl) {
    // remove a pending search if it exists
    if (this.callSearch) this.callSearch.abort();

    this.setState({
      fetching: true,
    });

    // initial render to show the loading spinner
    this.render();

    // query the search provider
    this.callSearch = $.get({
      url: searchUrl,
      dataType: 'json',
    })
        .always(() => {
          this.setState({
            fetching: false,
          });
        })
        .done((data, status, xhr) => {
        // make sure minimal data is present
          if (data.name && data.links) {
            // if data about the provider is recieved, update the model
            const update = { name: data.name };
            if (data.logo && is.url(data.logo)) update.logo = data.logo;
            if (data.links) {
              if (data.links.search && is.url(data.links.search)) {
                update.search = data.links.search;
              }
              if (data.links.listings && is.url(data.links.listings)) {
                update.listings = data.links.listings;
              }
              if (data.links.tor) {
                if (data.links.tor.search && is.url(data.links.tor.search)) {
                  update.torsearch = data.links.tor.search;
                }
                if (data.links.tor.listings && is.url(data.links.tor.listings)) {
                  update.torlistings = data.links.tor.listings;
                }
              }
            }
            this.sProvider.set(update);
            this.sProvider.save();
            this.render(data, searchUrl);
          } else {
            this.render({}, searchUrl, xhr);
          }
        })
        .fail((xhr) => {
          if (xhr.statusText !== 'abort') {
            this.render({}, searchUrl, xhr);
          }
        });
  }

  showSearchError(xhr = {}) {
    const title = app.polyglot.t('search.errors.searchFailTitle', { provider: this.sProvider });
    const failReason = xhr.responseJSON ? xhr.responseJSON.reason : '';
    const msg = failReason ?
                app.polyglot.t('search.errors.searchFailReason', { error: failReason }) : '';
    const buttons = [];
    if (this.usingOriginal) {
      buttons.push({
        text: app.polyglot.t('search.changeProvider'),
        fragment: 'changeProvider',
      });
    } else {
      buttons.push({
        text: app.polyglot.t('search.useDefault',
          {
            term: this.term,
            defaultProvider: app.searchProviders[`default${this.torString}Provider`],
          }),
        fragment: 'useDefault',
      });
    }

    const errorDialog = new Dialog({
      title,
      msg,
      buttons,
      showCloseButton: false,
      removeOnClose: true,
    }).render().open();
    this.listenTo(errorDialog, 'click-changeProvider', () => {
      errorDialog.close();
    });
    this.listenTo(errorDialog, 'click-useDefault', () => {
      this.activateProvider(app.searchProviders.at(0));
      errorDialog.close();
    });
  }

  createResults(data, searchUrl) {
    this.resultsCol = new ResultsCol();
    this.resultsCol.add(this.resultsCol.parse(data));

    const resultsView = this.createChild(Results, {
      searchUrl,
      total: data.results ? data.results.total : 0,
      morePages: data.results ? data.results.morePages : false,
      serverPage: this.serverPage,
      pageSize: this.pageSize,
      initCol: this.resultsCol,
    });

    this.$resultsWrapper.html(resultsView.render().el);

    this.listenTo(resultsView, 'searchError', (xhr) => this.showSearchError(xhr));
    this.listenTo(resultsView, 'loadingPage', () => this.scrollToTop());
  }

  clickSearchBtn() {
    this.processTerm(this.$searchInput.val());
  }

  onKeyupSearchInput(e) {
    if (e.which === 13) {
      this.processTerm(this.$searchInput.val());
    }
  }

  changeSortBy(e) {
    this.sortBySelected = $(e.target).val();
    this.processTerm(this.term);
  }

  changeFilter(e) {
    const targ = $(e.target);
    this.filters[targ.prop('name')] = targ.val();
    this.processTerm(this.term);
  }

  scrollToTop() {
    this.$el[0].scrollIntoView();
  }

  remove() {
    if (this.callSearch) this.callSearch.abort();
    super.remove();
  }

  render(data, searchUrl, xhr) {
    if (data && !searchUrl) {
      throw new Error('Please provide the search URL along with the data.');
    }

    let errTitle;
    let errMsg;
    const state = this.getState();
    // check to see if the call to the provider failed, or returned an empty result
    const emptyData = $.isEmptyObject(data);

    if (xhr) {
      errTitle = app.polyglot.t('search.errors.searchFailTitle', { provider: searchUrl });
      const failReason = xhr.responseJSON ? xhr.responseJSON.reason : '';
      errMsg = failReason ?
        app.polyglot.t('search.errors.searchFailReason', { error: failReason }) : '';
    }

    loadTemplate('search/Search.html', (t) => {
      this.$el.html(t({
        term: this.term === '*' ? '' : this.term,
        sortBySelected: this.sortBySelected,
        filterVals: this.filters,
        errTitle,
        errMsg,
        providerLocked: this.sProvider.get('locked'),
        isQueryProvider: !!this.queryProvider,
        isDefaultProvider: this.sProvider === app.searchProviders.defaultProvider,
        emptyData,
        ...state,
        ...this.sProvider,
        ...data,
      }));
    });
    this.$sortBy = this.$('#sortBy');
    this.$sortBy.select2({
      // disables the search box
      minimumResultsForSearch: Infinity,
      templateResult: selectEmojis,
      templateSelection: selectEmojis,
    });
    const filterWrapper = this.$('.js-filterWrapper');
    filterWrapper.find('select').select2({
      // disables the search box
      minimumResultsForSearch: Infinity,
      templateResult: selectEmojis,
      templateSelection: selectEmojis,
    });
    this.$filters = filterWrapper.find('select, input');
    this.$resultsWrapper = this.$('.js-resultsWrapper');
    this.$searchInput = this.$('.js-searchInput');
    this.$searchLogo = this.$('.js-searchLogo');

    this.$searchLogo.find('img').on('error', () => {
      this.$searchLogo.addClass('loadError');
    });

    this.searchProviders.delegateEvents();
    this.searchProviders.currentProviderId = this.queryProvider ? '' : this.sProvider.id;
    this.$('.js-searchProviders').append(this.searchProviders.render().el);

    // use the initial set of results data to create the results view
    if (data) this.createResults(data, searchUrl);

    return this;
  }
}
<commit_msg>Add the network query.<commit_after>import _ from 'underscore';
import $ from 'jquery';
import is from 'is_js';
import baseVw from '../baseVw';
import loadTemplate from '../../utils/loadTemplate';
import app from '../../app';
import { openSimpleMessage } from '../modals/SimpleMessage';
import Dialog from '../modals/Dialog';
import Results from './Results';
import ResultsCol from '../../collections/Results';
import Providers from './SearchProviders';
import ProviderMd from '../../models/search/SearchProvider';
import { selectEmojis } from '../../utils';
import { getCurrentConnection } from '../../utils/serverConnect';

export default class extends baseVw {
  constructor(options = {}) {
    const opts = {
      initialState: {
        fetching: false,
        ...options.initialState,
      },
      ...options,
    };

    super(opts);
    this.options = opts;

    this.searchProviders = this.createChild(Providers, { usingTor: this.usingTor });
    this.listenTo(this.searchProviders, 'activateProvider', pOpts => this.activateProvider(pOpts));

    if (options.query) {
      // the user arrived here from the address bar, use the default provider
      this.sProvider = app.searchProviders[`default${this.torString}Provider`];
    } else {
      // the user arrived from the discover button, use the active provider
      this.sProvider = app.searchProviders[`active${this.torString}Provider`];
    }

    // if the  provider returns a bad URL, reset to the original provider
    // this should never happen unless the local data is manually altered or corrupted
    if (is.not.url(this.providerUrl)) {
      this.sProvider = app.searchProviders.at(0);
    }

    const tempUrl = new URL(`${this.providerUrl}?${options.query || ''}`);
    let queryParams = tempUrl.searchParams;

    // if a url with parameters was in the query in, use the parameters in it instead.
    if (queryParams.get('providerQ')) {
      const subURL = new URL(queryParams.get('providerQ'));
      queryParams = subURL.searchParams;
      const base = `${subURL.origin}${subURL.pathname}`;
      const matchedProvider =
        app.searchProviders.filter(p =>
          base === p.get('listings') || base === p.get('torlistings'));

      /* if the query provider doesn't exist, create a temporary provider model for it.
         One quirk to note: if a tor url is passed in while the user is in clear mode, and an
         existing provider has that tor url, that provider will be activated but will use its
         clear url if it has one. The opposite is also true.
       */
      if (!matchedProvider.length) {
        const queryOpts = {};
        queryOpts[`${this.usingTor ? 'tor' : ''}listings`] = `${subURL.origin}${subURL.pathname}`;
        this.queryProvider = new ProviderMd(queryOpts);
      } else {
        this.sProvider = matchedProvider[0];
        this.queryProvider = null;
      }
    }

    const params = {};

    for (const param of queryParams.entries()) {
      params[param[0]] = param[1];
    }

    // use the parameters from the query unless they were overridden in the options
    this.serverPage = options.serverPage || params.p || 0;
    this.pageSize = options.pageSize || params.ps || 12;
    this.term = options.term || params.q || '';
    this.sortBySelected = options.sortBySelected || params.sortBy || '';
    // all parameters not specified above are assumed to be filters
    this.filters = _.omit(params, ['q', 'p', 'ps', 'sortBy', 'providerQ']);

    this.processTerm(this.term);

    // TODO: remove the ability to set the default in the settings
  }

  className() {
    return 'search';
  }

  events() {
    return {
      'click .js-searchBtn': 'clickSearchBtn',
      'change .js-sortBy': 'changeSortBy',
      'change .js-filterWrapper select': 'changeFilter',
      'change .js-filterWrapper input': 'changeFilter',
      'keyup .js-searchInput': 'onKeyupSearchInput',
      'click .js-deleteProvider': 'clickDeleteProvider',
      'click .js-makeDefaultProvider': 'clickMakeDefaultProvider',
      'click .js-addQueryProvider': 'clickAddQueryProvider',
    };
  }

  get usingOriginal() {
    return this.sProvider === app.searchProviders.at(0);
  }

  get usingTor() {
    return app.serverConfig.tor && getCurrentConnection().server.get('useTor');
  }

  get torString() {
    return this.usingTor ? 'Tor' : '';
  }

  get providerUrl() {
    // if a provider was created by the address bar query, use it instead
    const currentProvider = this.queryProvider || this.sProvider;
    return currentProvider.get(`${this.usingTor ? 'tor' : ''}listings`);
  }

  /**
   * This will create a url with the term and other query parameters
   * @param {string} term
   */
  processTerm(term) {
    this.term = term || '';
    // if term is false, search for *
    const query = `q=${encodeURIComponent(term || '*')}`;
    const page = `&p=${this.serverPage}&ps=${this.pageSize}`;
    const sortBy = this.sortBySelected ? `&sortBy=${encodeURIComponent(this.sortBySelected)}` : '';
    const network = `&network=${!!app.serverConfig.testnet ? 'testnet' : 'mainnet'}`;
    let filters = $.param(this.filters);
    filters = filters ? `&${filters}` : '';
    const newURL = `${this.providerUrl}?${query}${network}${sortBy}${page}${filters}`;
    this.callSearchProvider(newURL);
  }

  /**
   * This will set either the current active or default provider. If the user is currently in
   * Tor mode, the active or default Tor provider will be set.
   * @param md the search provider model
   * @param type should be active or default
   */
  activateProvider(md, type = 'active') {
    const types = ['active', 'default'];
    if (!md || !(md instanceof ProviderMd)) {
      throw new Error('Please provide a search provider model.');
    }
    if (!type || types.indexOf(type) === -1) {
      throw new Error('You must use a valid provider type.');
    }
    if (app.searchProviders.indexOf(md) === -1) {
      throw new Error('The provider must be in the collection.');
    }
    app.searchProviders[`${type}${this.torString}Provider`] = md;
    this.sProvider = md;
    this.queryProvider = null;
    this.processTerm(this.term);
  }

  deleteProvider(md = this.sProvider) {
    if (md.get('locked')) {
      openSimpleMessage(app.polyglot.t('search.errors.locked'));
    } else {
      md.destroy();
      if (app.searchProviders.length) this.activateProvider(app.searchProviders.at(0));
    }
  }

  clickDeleteProvider() {
    this.deleteProvider();
  }

  makeDefaultProvider() {
    app.searchProviders.defaultProvider = this.sProvider;
    this.getCachedEl('.js-makeDefaultProvider').addClass('hide');
  }

  clickMakeDefaultProvider() {
    this.makeDefaultProvider();
  }

  addQueryProvider() {
    if (this.queryProvider) app.searchProviders.add(this.queryProvider);
    this.activateProvider(this.queryProvider);
  }

  clickAddQueryProvider() {
    this.addQueryProvider();
  }

  callSearchProvider(searchUrl) {
    // remove a pending search if it exists
    if (this.callSearch) this.callSearch.abort();

    this.setState({
      fetching: true,
    });

    // initial render to show the loading spinner
    this.render();

    // query the search provider
    this.callSearch = $.get({
      url: searchUrl,
      dataType: 'json',
    })
        .always(() => {
          this.setState({
            fetching: false,
          });
        })
        .done((data, status, xhr) => {
        // make sure minimal data is present
          if (data.name && data.links) {
            // if data about the provider is recieved, update the model
            const update = { name: data.name };
            if (data.logo && is.url(data.logo)) update.logo = data.logo;
            if (data.links) {
              if (data.links.search && is.url(data.links.search)) {
                update.search = data.links.search;
              }
              if (data.links.listings && is.url(data.links.listings)) {
                update.listings = data.links.listings;
              }
              if (data.links.tor) {
                if (data.links.tor.search && is.url(data.links.tor.search)) {
                  update.torsearch = data.links.tor.search;
                }
                if (data.links.tor.listings && is.url(data.links.tor.listings)) {
                  update.torlistings = data.links.tor.listings;
                }
              }
            }
            this.sProvider.set(update);
            this.sProvider.save();
            this.render(data, searchUrl);
          } else {
            this.render({}, searchUrl, xhr);
          }
        })
        .fail((xhr) => {
          if (xhr.statusText !== 'abort') {
            this.render({}, searchUrl, xhr);
          }
        });
  }

  showSearchError(xhr = {}) {
    const title = app.polyglot.t('search.errors.searchFailTitle', { provider: this.sProvider });
    const failReason = xhr.responseJSON ? xhr.responseJSON.reason : '';
    const msg = failReason ?
                app.polyglot.t('search.errors.searchFailReason', { error: failReason }) : '';
    const buttons = [];
    if (this.usingOriginal) {
      buttons.push({
        text: app.polyglot.t('search.changeProvider'),
        fragment: 'changeProvider',
      });
    } else {
      buttons.push({
        text: app.polyglot.t('search.useDefault',
          {
            term: this.term,
            defaultProvider: app.searchProviders[`default${this.torString}Provider`],
          }),
        fragment: 'useDefault',
      });
    }

    const errorDialog = new Dialog({
      title,
      msg,
      buttons,
      showCloseButton: false,
      removeOnClose: true,
    }).render().open();
    this.listenTo(errorDialog, 'click-changeProvider', () => {
      errorDialog.close();
    });
    this.listenTo(errorDialog, 'click-useDefault', () => {
      this.activateProvider(app.searchProviders.at(0));
      errorDialog.close();
    });
  }

  createResults(data, searchUrl) {
    this.resultsCol = new ResultsCol();
    this.resultsCol.add(this.resultsCol.parse(data));

    const resultsView = this.createChild(Results, {
      searchUrl,
      total: data.results ? data.results.total : 0,
      morePages: data.results ? data.results.morePages : false,
      serverPage: this.serverPage,
      pageSize: this.pageSize,
      initCol: this.resultsCol,
    });

    this.$resultsWrapper.html(resultsView.render().el);

    this.listenTo(resultsView, 'searchError', (xhr) => this.showSearchError(xhr));
    this.listenTo(resultsView, 'loadingPage', () => this.scrollToTop());
  }

  clickSearchBtn() {
    this.processTerm(this.$searchInput.val());
  }

  onKeyupSearchInput(e) {
    if (e.which === 13) {
      this.processTerm(this.$searchInput.val());
    }
  }

  changeSortBy(e) {
    this.sortBySelected = $(e.target).val();
    this.processTerm(this.term);
  }

  changeFilter(e) {
    const targ = $(e.target);
    this.filters[targ.prop('name')] = targ.val();
    this.processTerm(this.term);
  }

  scrollToTop() {
    this.$el[0].scrollIntoView();
  }

  remove() {
    if (this.callSearch) this.callSearch.abort();
    super.remove();
  }

  render(data, searchUrl, xhr) {
    if (data && !searchUrl) {
      throw new Error('Please provide the search URL along with the data.');
    }

    let errTitle;
    let errMsg;
    const state = this.getState();
    // check to see if the call to the provider failed, or returned an empty result
    const emptyData = $.isEmptyObject(data);

    if (xhr) {
      errTitle = app.polyglot.t('search.errors.searchFailTitle', { provider: searchUrl });
      const failReason = xhr.responseJSON ? xhr.responseJSON.reason : '';
      errMsg = failReason ?
        app.polyglot.t('search.errors.searchFailReason', { error: failReason }) : '';
    }

    loadTemplate('search/Search.html', (t) => {
      this.$el.html(t({
        term: this.term === '*' ? '' : this.term,
        sortBySelected: this.sortBySelected,
        filterVals: this.filters,
        errTitle,
        errMsg,
        providerLocked: this.sProvider.get('locked'),
        isQueryProvider: !!this.queryProvider,
        isDefaultProvider: this.sProvider === app.searchProviders.defaultProvider,
        emptyData,
        ...state,
        ...this.sProvider,
        ...data,
      }));
    });
    this.$sortBy = this.$('#sortBy');
    this.$sortBy.select2({
      // disables the search box
      minimumResultsForSearch: Infinity,
      templateResult: selectEmojis,
      templateSelection: selectEmojis,
    });
    const filterWrapper = this.$('.js-filterWrapper');
    filterWrapper.find('select').select2({
      // disables the search box
      minimumResultsForSearch: Infinity,
      templateResult: selectEmojis,
      templateSelection: selectEmojis,
    });
    this.$filters = filterWrapper.find('select, input');
    this.$resultsWrapper = this.$('.js-resultsWrapper');
    this.$searchInput = this.$('.js-searchInput');
    this.$searchLogo = this.$('.js-searchLogo');

    this.$searchLogo.find('img').on('error', () => {
      this.$searchLogo.addClass('loadError');
    });

    this.searchProviders.delegateEvents();
    this.searchProviders.currentProviderId = this.queryProvider ? '' : this.sProvider.id;
    this.$('.js-searchProviders').append(this.searchProviders.render().el);

    // use the initial set of results data to create the results view
    if (data) this.createResults(data, searchUrl);

    return this;
  }
}
<|endoftext|>


<commit_before>var _ = require('../util').lodash,
    PropertyBase = require('./property-base').PropertyBase,
    Property = require('./property').Property,
    Url = require('./url').Url,
    ProxyConfig = require('./proxy-config').ProxyConfig,
    Certificate = require('./certificate').Certificate,
    HeaderList = require('./header-list').HeaderList,
    RequestBody = require('./request-body').RequestBody,
    RequestAuth = require('./request-auth').RequestAuth,

    Request,
    DEFAULT_REQ_METHOD = 'GET';

/**
 * @typedef Request~definition
 * @property {String|Url} url The URL of the request. This can be a {@link Url~definition} or a string.
 * @property {String} method The request method, e.g: "GET" or "POST".
 * @property {Array<Header~definition>} header The headers that should be sent as a part of this request.
 * @property {RequestBody~definition} body The request body definition.
 * @property {RequestAuth~definition} auth The authentication/signing information for this request.
 * @property {ProxyConfig~definition} proxy The proxy information for this request.
 * @property {Certificate~definition} certificate The certificate information for this request.
 */
_.inherit((

    /**
     * A Postman HTTP request object.
     *
     * @constructor
     * @extends {Property}
     * @param {Request~definition} options
     */
    Request = function PostmanRequest (options) {
        // this constructor is intended to inherit and as such the super constructor is required to be executed
        Request.super_.apply(this, arguments);

        // if the definition is a string, it implies that this is a get of URL
        (typeof options === 'string') && (options = {
            url: options
        });

        // Create the default properties
        _.assign(this, /** @lends Request.prototype */ {
            /**
             * @type {Url}
             */
            url: new Url(),

            /**
             * @type {HeaderList}
             */
            headers: new HeaderList(this, options && options.header),

            // Although a similar check is being done in the .update call below, this handles falsy options as well.
            /**
             * @type {String}
             * @todo: Clean this up
             */
            // the negated condition is required to keep DEFAULT_REQ_METHOD as a fallback
            method: _.has(options, 'method') && !_.isNil(options.method) ?
                String(options.method).toUpperCase() : DEFAULT_REQ_METHOD
        });

        this.update(options);
    }), Property);

_.assign(Request.prototype, /** @lends Request.prototype */ {

    /**
     * Updates the different properties of the request.
     *
     * @param {Request~definition} options
     */
    update: function (options) {
        // Nothing to do
        if (!options) { return; }

        // The existing url is updated.
        _.has(options, 'url') && this.url.update(options.url);

        // The existing list of headers must be cleared before adding the given headers to it.
        options.header && this.headers.repopulate(options.header);

        // Only update the method if one is provided.
        _.has(options, 'method') && (this.method = _.isNil(options.method) ?
            DEFAULT_REQ_METHOD : String(options.method).toUpperCase());

        // The rest of the properties are not assumed to exist so we merge in the defined ones.
        _.mergeDefined(this, /** @lends Request.prototype */ {
            /**
             * @type {RequestBody|undefined}
             */
            body: _.createDefined(options, 'body', RequestBody),

            // auth is a special case, empty RequestAuth should not be created for falsy values
            // to allow inheritance from parent
            /**
             * @type {RequestAuth}
             */
            auth: options.auth ? new RequestAuth(options.auth) : undefined,

            /**
             * @type {ProxyConfig}
             */
            proxy: options.proxy && new ProxyConfig(options.proxy),

            /**
             * @type {Certificate|undefined}
             */
            certificate: options.certificate && new Certificate(options.certificate)
        });
    },

    /**
     * Sets authentication method for the request
     *
     * @param {?String|RequestAuth~definition} type
     * @param {VariableList~definition=} [options]
     *
     * @note This function was previously (in v2 of SDK) used to clone request and populate headers. Now it is used to
     * only set auth information to request
     *
     * @note that ItemGroup#authorizeUsing depends on this function
     */
    authorizeUsing: function (type, options) {
        if (_.isObject(type) && _.isNil(options)) {
            type = options.type;
            options = _.omit(options, 'type');
        }

        // null = delete request
        if (type === null) {
            _.has(this, 'auth') && (delete this.auth);
            return;
        }

        if (!RequestAuth.isValidType(type)) {
            return;
        }

        // create a new authentication data
        if (!this.auth) {
            this.auth = new RequestAuth(null, this);
        }
        else {
            this.auth.clear(type);
        }

        this.auth.use(type, options);
    },

    /**
     * Returns an object where the key is a header name and value is the header value.
     *
     * @param {Object=} options
     * @param {Boolean} options.ignoreCase When set to "true", will ensure that all the header keys are lower case.
     * @param {Boolean} options.enabled Only get the enabled headers
     * @param {Boolean} options.multiValue When set to "true", duplicate header values will be stored in an array
     * @param {Boolean} options.sanitizeKeys When set to "true", headers with falsy keys are removed
     * @returns {Object}
     * @note If multiple headers are present in the same collection with same name, but different case
     * (E.g "x-forward-port" and "X-Forward-Port", and `options.ignoreCase` is set to true,
     * the values will be stored in an array.
     */
    getHeaders: function getHeaders (options) {
        !options && (options = {});

        // @note: options.multiValue will not be respected since, Header._postman_propertyAllowsMultipleValues
        // gets higher precedence in PropertyLists~toObject.
        // @todo: sanitizeKeys for headers by default.
        return this.headers.toObject(options.enabled, !options.ignoreCase, options.multiValue, options.sanitizeKeys);
    },

    /**
     * Calls the given callback on each Header object contained within the request.
     *
     * @param {Function} callback
     */
    forEachHeader: function forEachHeader (callback) {
        this.headers.all().forEach(function (header) {
            return callback(header, this);
        }, this);
    },

    /**
     * Adds a header to the PropertyList of headers.
     *
     * @param {Header| {key: String, value: String}} header Can be a {Header} object, or a raw header object.
     */
    addHeader: function (header) {
        this.headers.add(header);
    },

    /**
     * Removes a header from the request.
     *
     * @param {String|Header} toRemove A header object to remove, or a string containing the header key.
     * @param {Object} options
     * @param {Boolean} options.ignoreCase If set to true, ignores case while removing the header.
     */
    removeHeader: function (toRemove, options) {
        toRemove = _.isString(toRemove) ? toRemove : toRemove.key;

        options = options || {};

        if (!toRemove) { // Nothing to remove :(
            return;
        }

        options.ignoreCase && (toRemove = toRemove.toLowerCase());

        this.headers.remove(function (header) {
            var key = options.ignoreCase ? header.key.toLowerCase() : header.key;
            return key === toRemove;
        });
    },

    /**
     * Updates or inserts the given header.
     *
     * @param {Object} header
     */
    upsertHeader: function (header) {
        if (!(header && header.key)) { return; } // if no valid header is provided, do nothing

        var existing = this.headers.find({ key: header.key });

        if (!existing) {
            return this.headers.add(header);
        }

        existing.value = header.value;
    },

    /**
     * Add query parameters to the request.
     *
     * @todo: Rename this?
     * @param {Array<QueryParam>|String} params
     */
    addQueryParams: function (params) {
        this.url.addQueryParams(params);
    },

    /**
     * Removes parameters passed in params.
     *
     * @param {String|Array} params
     */
    removeQueryParams: function (params) {
        this.url.removeQueryParams(params);
    },

    /**
     * Converts the Request to a plain JavaScript object, which is also how the request is
     * represented in a collection file.
     *
     * @returns {{url: (*|string), method: *, header: (undefined|*), body: *, auth: *, certificate: *}}
     */
    toJSON: function () {
        var obj = PropertyBase.toJSON(this);

        // remove header array if blank
        if (_.isArray(obj.header) && !obj.header.length) {
            delete obj.header;
        }

        return obj;
    },

    /**
     * Creates a clone of this request
     *
     * @returns {Request}
     */
    clone: function () {
        return new Request(this.toJSON());
    },

    /**
     * Creates a copy of this request, with the appropriate auth headers or parameters added.
     *
     * @deprecated discontinued in v3.x
     * @note This function does not take care of resolving variables.
     * @returns {Request}
     */
    authorize: function () {
        throw new Error('collection request.authorize() has been discontinued');
    }
});

_.assign(Request, /** @lends Request */ {
    /**
     * Defines the name of this property for internal use.
     * @private
     * @readOnly
     * @type {String}
     */
    _postman_propertyName: 'Request',

    /**
     * Check whether an object is an instance of {@link ItemGroup}.
     *
     * @param {*} obj
     * @returns {Boolean}
     */
    isRequest: function (obj) {
        return Boolean(obj) && ((obj instanceof Request) ||
            _.inSuperChain(obj.constructor, '_postman_propertyName', Request._postman_propertyName));
    }
});

module.exports = {
    Request: Request
};
<commit_msg>Add request size<commit_after>var _ = require('../util').lodash,
    PropertyBase = require('./property-base').PropertyBase,
    Property = require('./property').Property,
    Url = require('./url').Url,
    ProxyConfig = require('./proxy-config').ProxyConfig,
    Certificate = require('./certificate').Certificate,
    HeaderList = require('./header-list').HeaderList,
    RequestBody = require('./request-body').RequestBody,
    RequestAuth = require('./request-auth').RequestAuth,

    Request,
    DEFAULT_REQ_METHOD = 'GET';

/**
 * @typedef Request~definition
 * @property {String|Url} url The URL of the request. This can be a {@link Url~definition} or a string.
 * @property {String} method The request method, e.g: "GET" or "POST".
 * @property {Array<Header~definition>} header The headers that should be sent as a part of this request.
 * @property {RequestBody~definition} body The request body definition.
 * @property {RequestAuth~definition} auth The authentication/signing information for this request.
 * @property {ProxyConfig~definition} proxy The proxy information for this request.
 * @property {Certificate~definition} certificate The certificate information for this request.
 */
_.inherit((

    /**
     * A Postman HTTP request object.
     *
     * @constructor
     * @extends {Property}
     * @param {Request~definition} options
     */
    Request = function PostmanRequest (options) {
        // this constructor is intended to inherit and as such the super constructor is required to be executed
        Request.super_.apply(this, arguments);

        // if the definition is a string, it implies that this is a get of URL
        (typeof options === 'string') && (options = {
            url: options
        });

        // Create the default properties
        _.assign(this, /** @lends Request.prototype */ {
            /**
             * @type {Url}
             */
            url: new Url(),

            /**
             * @type {HeaderList}
             */
            headers: new HeaderList(this, options && options.header),

            // Although a similar check is being done in the .update call below, this handles falsy options as well.
            /**
             * @type {String}
             * @todo: Clean this up
             */
            // the negated condition is required to keep DEFAULT_REQ_METHOD as a fallback
            method: _.has(options, 'method') && !_.isNil(options.method) ?
                String(options.method).toUpperCase() : DEFAULT_REQ_METHOD
        });

        this.update(options);
    }), Property);

_.assign(Request.prototype, /** @lends Request.prototype */ {

    /**
     * Updates the different properties of the request.
     *
     * @param {Request~definition} options
     */
    update: function (options) {
        // Nothing to do
        if (!options) { return; }

        // The existing url is updated.
        _.has(options, 'url') && this.url.update(options.url);

        // The existing list of headers must be cleared before adding the given headers to it.
        options.header && this.headers.repopulate(options.header);

        // Only update the method if one is provided.
        _.has(options, 'method') && (this.method = _.isNil(options.method) ?
            DEFAULT_REQ_METHOD : String(options.method).toUpperCase());

        // The rest of the properties are not assumed to exist so we merge in the defined ones.
        _.mergeDefined(this, /** @lends Request.prototype */ {
            /**
             * @type {RequestBody|undefined}
             */
            body: _.createDefined(options, 'body', RequestBody),

            // auth is a special case, empty RequestAuth should not be created for falsy values
            // to allow inheritance from parent
            /**
             * @type {RequestAuth}
             */
            auth: options.auth ? new RequestAuth(options.auth) : undefined,

            /**
             * @type {ProxyConfig}
             */
            proxy: options.proxy && new ProxyConfig(options.proxy),

            /**
             * @type {Certificate|undefined}
             */
            certificate: options.certificate && new Certificate(options.certificate),

            /**
             * @private
             * @type {Object}
             */
            size: options && options.size
        });
    },

    /**
     * Sets authentication method for the request
     *
     * @param {?String|RequestAuth~definition} type
     * @param {VariableList~definition=} [options]
     *
     * @note This function was previously (in v2 of SDK) used to clone request and populate headers. Now it is used to
     * only set auth information to request
     *
     * @note that ItemGroup#authorizeUsing depends on this function
     */
    authorizeUsing: function (type, options) {
        if (_.isObject(type) && _.isNil(options)) {
            type = options.type;
            options = _.omit(options, 'type');
        }

        // null = delete request
        if (type === null) {
            _.has(this, 'auth') && (delete this.auth);
            return;
        }

        if (!RequestAuth.isValidType(type)) {
            return;
        }

        // create a new authentication data
        if (!this.auth) {
            this.auth = new RequestAuth(null, this);
        }
        else {
            this.auth.clear(type);
        }

        this.auth.use(type, options);
    },

    /**
     * Returns an object where the key is a header name and value is the header value.
     *
     * @param {Object=} options
     * @param {Boolean} options.ignoreCase When set to "true", will ensure that all the header keys are lower case.
     * @param {Boolean} options.enabled Only get the enabled headers
     * @param {Boolean} options.multiValue When set to "true", duplicate header values will be stored in an array
     * @param {Boolean} options.sanitizeKeys When set to "true", headers with falsy keys are removed
     * @returns {Object}
     * @note If multiple headers are present in the same collection with same name, but different case
     * (E.g "x-forward-port" and "X-Forward-Port", and `options.ignoreCase` is set to true,
     * the values will be stored in an array.
     */
    getHeaders: function getHeaders (options) {
        !options && (options = {});

        // @note: options.multiValue will not be respected since, Header._postman_propertyAllowsMultipleValues
        // gets higher precedence in PropertyLists~toObject.
        // @todo: sanitizeKeys for headers by default.
        return this.headers.toObject(options.enabled, !options.ignoreCase, options.multiValue, options.sanitizeKeys);
    },

    /**
     * Calls the given callback on each Header object contained within the request.
     *
     * @param {Function} callback
     */
    forEachHeader: function forEachHeader (callback) {
        this.headers.all().forEach(function (header) {
            return callback(header, this);
        }, this);
    },

    /**
     * Adds a header to the PropertyList of headers.
     *
     * @param {Header| {key: String, value: String}} header Can be a {Header} object, or a raw header object.
     */
    addHeader: function (header) {
        this.headers.add(header);
    },

    /**
     * Removes a header from the request.
     *
     * @param {String|Header} toRemove A header object to remove, or a string containing the header key.
     * @param {Object} options
     * @param {Boolean} options.ignoreCase If set to true, ignores case while removing the header.
     */
    removeHeader: function (toRemove, options) {
        toRemove = _.isString(toRemove) ? toRemove : toRemove.key;

        options = options || {};

        if (!toRemove) { // Nothing to remove :(
            return;
        }

        options.ignoreCase && (toRemove = toRemove.toLowerCase());

        this.headers.remove(function (header) {
            var key = options.ignoreCase ? header.key.toLowerCase() : header.key;
            return key === toRemove;
        });
    },

    /**
     * Updates or inserts the given header.
     *
     * @param {Object} header
     */
    upsertHeader: function (header) {
        if (!(header && header.key)) { return; } // if no valid header is provided, do nothing

        var existing = this.headers.find({ key: header.key });

        if (!existing) {
            return this.headers.add(header);
        }

        existing.value = header.value;
    },

    /**
     * Add query parameters to the request.
     *
     * @todo: Rename this?
     * @param {Array<QueryParam>|String} params
     */
    addQueryParams: function (params) {
        this.url.addQueryParams(params);
    },

    /**
     * Removes parameters passed in params.
     *
     * @param {String|Array} params
     */
    removeQueryParams: function (params) {
        this.url.removeQueryParams(params);
    },

    /**
     * Converts the Request to a plain JavaScript object, which is also how the request is
     * represented in a collection file.
     *
     * @returns {{url: (*|string), method: *, header: (undefined|*), body: *, auth: *, certificate: *}}
     */
    toJSON: function () {
        var obj = PropertyBase.toJSON(this);

        // remove header array if blank
        if (_.isArray(obj.header) && !obj.header.length) {
            delete obj.header;
        }

        return obj;
    },

    /**
     * Creates a clone of this request
     *
     * @returns {Request}
     */
    clone: function () {
        return new Request(this.toJSON());
    },

    /**
     * Creates a copy of this request, with the appropriate auth headers or parameters added.
     *
     * @deprecated discontinued in v3.x
     * @note This function does not take care of resolving variables.
     * @returns {Request}
     */
    authorize: function () {
        throw new Error('collection request.authorize() has been discontinued');
    }
});

_.assign(Request, /** @lends Request */ {
    /**
     * Defines the name of this property for internal use.
     * @private
     * @readOnly
     * @type {String}
     */
    _postman_propertyName: 'Request',

    /**
     * Check whether an object is an instance of {@link ItemGroup}.
     *
     * @param {*} obj
     * @returns {Boolean}
     */
    isRequest: function (obj) {
        return Boolean(obj) && ((obj instanceof Request) ||
            _.inSuperChain(obj.constructor, '_postman_propertyName', Request._postman_propertyName));
    }
});

module.exports = {
    Request: Request
};
<|endoftext|>


<commit_before>/**********************************************************************
 Freeciv - Copyright (C) 2009-2010 - Andreas Røsdal   andrearo@pvv.ntnu.no
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
***********************************************************************/

/**************************************************************************
  Returns true unless a situation were a regular move always would be
  impossible is recognized.
**************************************************************************/
function can_actor_unit_move(pdiplomat, target_tile)
{
  var tgt_owner_id;

  if (index_to_tile(pdiplomat['tile']) == target_tile) {
    /* The unit is already on this tile. */
    return false;
  }

  for (var i = 0; i < tile_units(target_tile).length; i++) {
    tgt_owner_id = unit_owner(tile_units(target_tile)[i])['playerno'];

    if (tgt_owner_id != unit_owner(pdiplomat)['playerno']
        && diplstates[tgt_owner_id] != DS_ALLIANCE
        && diplstates[tgt_owner_id] != DS_TEAM) {
      /* In current Freeciv acting units can't attack foreign units. */
      return false;
    }
  };

  if (tile_city(target_tile) != null) {
    tgt_owner_id = city_owner(tile_city(target_tile))['playerno'];

    if (tgt_owner_id == unit_owner(pdiplomat)['playerno']) {
      /* This city isn't foreign. */
      return true;
    }

    if (diplstates[tgt_owner_id] == DS_ALLIANCE
        || diplstates[tgt_owner_id] == DS_TEAM) {
      /* This city belongs to an ally. */
      return true;
    }

    /* TODO: Support rulesets were actors can invade cities. */
    return false;
  }

  /* It is better to show the "Keep moving" option one time to much than
   * one time to little. */
  return true;
}

/****************************************************************************
 ...
****************************************************************************/
function popup_caravan_dialog(punit, traderoute, wonder)
{
  var id = "#caravan_dialog_" + punit['id'];
  $(id).remove();
  $("

").appendTo("div#game_page");

  var homecity = cities[punit['homecity']];
  var ptile = index_to_tile(punit['tile']);
  var pcity = tile_city(ptile);

  var dhtml = "Your caravan from " + decodeURIComponent(homecity['name']) + " reaches the city of "
        + decodeURIComponent(pcity['name']) + ". What now?
"
        + "<input id='car_trade" + punit['id']
        + "' class='car_button' type='button' value='Establish Traderoute'>"
        + "<input id='car_wonder" + punit['id']
        + "' class='car_button' type='button' value='Help build Wonder'>"
        + "<input id='car_cancel" + punit['id']
        + "' class='car_button' type='button' value='Cancel'>"
        + ""
  $(id).html(dhtml);

  $(id).attr("title", "Your Caravan Has Arrived");
  $(id).dialog({
            bgiframe: true,
            modal: true,
            width: "350"});

  $(id).dialog('open');
  $(".car_button").button();
  $(".car_button").css("width", "250px");

  if (!traderoute) $("#car_trade" + punit['id']).button( "option", "disabled", true);
  if (!wonder) $("#car_wonder" + punit['id']).button( "option", "disabled", true);

  $("#car_trade" + punit['id']).click(function() {
    var packet = {"type" : packet_unit_establish_trade,
                   "unit_id": punit['id'],
                   "city_id" : pcity['id']};
    send_request (JSON.stringify(packet));

    $(id).remove();
  });

  $("#car_wonder" + punit['id']).click(function() {
    var packet = {"type" : packet_unit_help_build_wonder,
                   "unit_id": punit['id'],
                   "city_id" : pcity['id']};
    send_request (JSON.stringify(packet));

    $(id).remove();
  });

  $("#car_cancel" + punit['id']).click(function() {
    $(id).remove();
  });

}

function popup_diplomat_dialog(pdiplomat, action_probabilities,
                               target_tile, punit, pcity)
{
 // reset dialog page.
  var id = "#diplo_dialog_" + pdiplomat['id'];
  $(id).remove();
  $("

").appendTo("div#game_page");

  var actor_homecity = cities[pdiplomat['homecity']];

  var dhtml = "";

  if (pcity != null) {
    dhtml += "Your " + unit_types[pdiplomat['type']]['name'];

    /* Some units don't have a home city. */
    if (actor_homecity != null) {
      dhtml += " from " + decodeURIComponent(actor_homecity['name']);
    }

    dhtml += " has arrived at " + decodeURIComponent(pcity['name'])
             + ". What is your command?";
  } else {
    dhtml += "The diplomat is waiting for your command";
  }

  dhtml += "
";

  if (action_probabilities[ACTION_ESTABLISH_EMBASSY] != 0) {
    dhtml += "<input id='diplo_emb' class='diplo_button' type='button' value='Establish Embassy'>";
  }
  if (action_probabilities[ACTION_SPY_INVESTIGATE_CITY] != 0) {
    dhtml += "<input id='diplo_inv' class='diplo_button' type='button' value='Investigate City'>"
  }
  if (action_probabilities[ACTION_SPY_SABOTAGE_CITY] != 0) {
    dhtml += "<input id='diplo_sab' class='diplo_button' type='button' value='Sabotage City'>"
  }
  if (action_probabilities[ACTION_SPY_STEAL_TECH] != 0) {
    dhtml += "<input id='diplo_tech' class='diplo_button' type='button' value='Steal Technology'>"
  }
  if (action_probabilities[ACTION_SPY_INCITE_CITY] != 0) {
    dhtml += "<input id='diplo_revo' class='diplo_button' type='button' value='Incite a revolt'>"
  }
  if (action_probabilities[ACTION_SPY_POISON] != 0) {
    dhtml += "<input id='diplo_poi' class='diplo_button' type='button' value='Poison city'>"
  }
  if (action_probabilities[ACTION_SPY_BRIBE_UNIT] != 0) {
    dhtml += "<input id='diplo_bribe' class='diplo_button' type='button' value='Bribe enemy unit'>"
  }
  if (action_probabilities[ACTION_SPY_SABOTAGE_UNIT] != 0) {
    dhtml += "<input id='diplo_spy_sabo' class='diplo_button' type='button' value='Sabotage enemy unit'>"
  }
  if (can_actor_unit_move(pdiplomat, target_tile)) {
    dhtml += "<input id='diplo_move' class='diplo_button' type='button' value='Keep moving'>"
  }

  dhtml += "<input id='diplo_cancel' class='diplo_button' type='button' value='Cancel'>"
         + "";
  $(id).html(dhtml);

  $(id).attr("title", "Choose Your Diplomat's Strategy");
  $(id).dialog({
			bgiframe: true,
			modal: true,
			width: "350"});

  $(id).dialog('open');
  $(".diplo_button").button();
  $(".diplo_button").css("width", "250px");

  $("#diplo_cancel").click(function() {
    $(id).remove();
  });

  if (action_probabilities[ACTION_ESTABLISH_EMBASSY] != 0) {
    $("#diplo_emb").click(function() {
      var packet = {"type" : packet_unit_do_action,
                     "actor_id" : pdiplomat['id'],
                     "target_id": pcity['id'],
                     "value" : 0,
                     "action_type": ACTION_ESTABLISH_EMBASSY};
      send_request (JSON.stringify(packet));

      $(id).remove();
    });
  }

  if (action_probabilities[ACTION_SPY_INVESTIGATE_CITY] != 0) {
    $("#diplo_inv").click(function() {
      var packet = {"type" : packet_unit_do_action,
        "actor_id" : pdiplomat['id'],
        "target_id": pcity['id'],
        "value" : 0,
        "action_type": ACTION_SPY_INVESTIGATE_CITY};
        send_request (JSON.stringify(packet));

        $(id).remove();
    });
  }

  if (action_probabilities[ACTION_SPY_SABOTAGE_CITY] != 0) {
    $("#diplo_sab").click(function() {
      var packet = {"type" : packet_unit_do_action,
        "actor_id" : pdiplomat['id'],
        "target_id": pcity['id'],
        "value" : 0,
        "action_type": ACTION_SPY_SABOTAGE_CITY};
        send_request (JSON.stringify(packet));

        $(id).remove();
    });
  }

  var last_tech = 0;

  if (action_probabilities[ACTION_SPY_STEAL_TECH] != 0) {
    $("#diplo_tech").click(function() {
      var packet = {"type" : packet_unit_do_action,
                     "actor_id" : pdiplomat['id'],
                     "target_id": pcity['id'],
                     "value" : last_tech,
                     "action_type": ACTION_SPY_STEAL_TECH};
      send_request (JSON.stringify(packet));

      $(id).remove();
    });
  }

  if (action_probabilities[ACTION_SPY_INCITE_CITY] != 0) {
    $("#diplo_revo").click(function() {
      var packet = {"type" : packet_unit_do_action,
        "actor_id" : pdiplomat['id'],
        "target_id": pcity['id'],
        "value" : 0,
        "action_type": ACTION_SPY_INCITE_CITY};
        send_request (JSON.stringify(packet));

        $(id).remove();
    });
  }

  if (action_probabilities[ACTION_SPY_POISON] != 0) {
    $("#diplo_poi").click(function() {
      var packet = {"type" : packet_unit_do_action,
        "actor_id" : pdiplomat['id'],
        "target_id": pcity['id'],
        "value" : 0,
        "action_type": ACTION_SPY_POISON};
        send_request (JSON.stringify(packet));

        $(id).remove();
    });
  }

  if (action_probabilities[ACTION_SPY_BRIBE_UNIT] != 0) {
    $("#diplo_bribe").click(function() {
      var packet = {"type" : packet_unit_do_action,
        "actor_id" : pdiplomat['id'],
        "target_id": punit['id'],
        "value" : 0,
        "action_type": ACTION_SPY_BRIBE_UNIT};
        send_request (JSON.stringify(packet));

        $(id).remove();
    });
  }

  if (action_probabilities[ACTION_SPY_SABOTAGE_UNIT] != 0) {
    $("#diplo_spy_sabo").click(function() {
      var packet = {"type" : packet_unit_do_action,
        "actor_id" : pdiplomat['id'],
        "target_id": punit['id'],
        "value" : 0,
        "action_type": ACTION_SPY_SABOTAGE_UNIT};
        send_request (JSON.stringify(packet));

        $(id).remove();
    });
  }

  if (can_actor_unit_move(pdiplomat, target_tile)) {
    $("#diplo_move").click(function() {
      var packet = {"type" : packet_unit_do_action,
        "actor_id" : pdiplomat['id'],
        "target_id": target_tile['index'],
        "value" : 0,
        "action_type": ACTION_MOVE};
        send_request (JSON.stringify(packet));

        $(id).remove();
    });
  }
}

<commit_msg>Diplomat dialog: Use the unit type name in the description when a unit is the target.<commit_after>/**********************************************************************
 Freeciv - Copyright (C) 2009-2010 - Andreas Røsdal   andrearo@pvv.ntnu.no
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
***********************************************************************/

/**************************************************************************
  Returns true unless a situation were a regular move always would be
  impossible is recognized.
**************************************************************************/
function can_actor_unit_move(pdiplomat, target_tile)
{
  var tgt_owner_id;

  if (index_to_tile(pdiplomat['tile']) == target_tile) {
    /* The unit is already on this tile. */
    return false;
  }

  for (var i = 0; i < tile_units(target_tile).length; i++) {
    tgt_owner_id = unit_owner(tile_units(target_tile)[i])['playerno'];

    if (tgt_owner_id != unit_owner(pdiplomat)['playerno']
        && diplstates[tgt_owner_id] != DS_ALLIANCE
        && diplstates[tgt_owner_id] != DS_TEAM) {
      /* In current Freeciv acting units can't attack foreign units. */
      return false;
    }
  };

  if (tile_city(target_tile) != null) {
    tgt_owner_id = city_owner(tile_city(target_tile))['playerno'];

    if (tgt_owner_id == unit_owner(pdiplomat)['playerno']) {
      /* This city isn't foreign. */
      return true;
    }

    if (diplstates[tgt_owner_id] == DS_ALLIANCE
        || diplstates[tgt_owner_id] == DS_TEAM) {
      /* This city belongs to an ally. */
      return true;
    }

    /* TODO: Support rulesets were actors can invade cities. */
    return false;
  }

  /* It is better to show the "Keep moving" option one time to much than
   * one time to little. */
  return true;
}

/****************************************************************************
 ...
****************************************************************************/
function popup_caravan_dialog(punit, traderoute, wonder)
{
  var id = "#caravan_dialog_" + punit['id'];
  $(id).remove();
  $("

").appendTo("div#game_page");

  var homecity = cities[punit['homecity']];
  var ptile = index_to_tile(punit['tile']);
  var pcity = tile_city(ptile);

  var dhtml = "Your caravan from " + decodeURIComponent(homecity['name']) + " reaches the city of "
        + decodeURIComponent(pcity['name']) + ". What now?
"
        + "<input id='car_trade" + punit['id']
        + "' class='car_button' type='button' value='Establish Traderoute'>"
        + "<input id='car_wonder" + punit['id']
        + "' class='car_button' type='button' value='Help build Wonder'>"
        + "<input id='car_cancel" + punit['id']
        + "' class='car_button' type='button' value='Cancel'>"
        + ""
  $(id).html(dhtml);

  $(id).attr("title", "Your Caravan Has Arrived");
  $(id).dialog({
            bgiframe: true,
            modal: true,
            width: "350"});

  $(id).dialog('open');
  $(".car_button").button();
  $(".car_button").css("width", "250px");

  if (!traderoute) $("#car_trade" + punit['id']).button( "option", "disabled", true);
  if (!wonder) $("#car_wonder" + punit['id']).button( "option", "disabled", true);

  $("#car_trade" + punit['id']).click(function() {
    var packet = {"type" : packet_unit_establish_trade,
                   "unit_id": punit['id'],
                   "city_id" : pcity['id']};
    send_request (JSON.stringify(packet));

    $(id).remove();
  });

  $("#car_wonder" + punit['id']).click(function() {
    var packet = {"type" : packet_unit_help_build_wonder,
                   "unit_id": punit['id'],
                   "city_id" : pcity['id']};
    send_request (JSON.stringify(packet));

    $(id).remove();
  });

  $("#car_cancel" + punit['id']).click(function() {
    $(id).remove();
  });

}

function popup_diplomat_dialog(pdiplomat, action_probabilities,
                               target_tile, punit, pcity)
{
 // reset dialog page.
  var id = "#diplo_dialog_" + pdiplomat['id'];
  $(id).remove();
  $("

").appendTo("div#game_page");

  var actor_homecity = cities[pdiplomat['homecity']];

  var dhtml = "";

  if (pcity != null) {
    dhtml += "Your " + unit_types[pdiplomat['type']]['name'];

    /* Some units don't have a home city. */
    if (actor_homecity != null) {
      dhtml += " from " + decodeURIComponent(actor_homecity['name']);
    }

    dhtml += " has arrived at " + decodeURIComponent(pcity['name'])
             + ". What is your command?";
  } else {
    dhtml += "The " + unit_types[pdiplomat['type']]['name']
             + " is waiting for your command";
  }

  dhtml += "
";

  if (action_probabilities[ACTION_ESTABLISH_EMBASSY] != 0) {
    dhtml += "<input id='diplo_emb' class='diplo_button' type='button' value='Establish Embassy'>";
  }
  if (action_probabilities[ACTION_SPY_INVESTIGATE_CITY] != 0) {
    dhtml += "<input id='diplo_inv' class='diplo_button' type='button' value='Investigate City'>"
  }
  if (action_probabilities[ACTION_SPY_SABOTAGE_CITY] != 0) {
    dhtml += "<input id='diplo_sab' class='diplo_button' type='button' value='Sabotage City'>"
  }
  if (action_probabilities[ACTION_SPY_STEAL_TECH] != 0) {
    dhtml += "<input id='diplo_tech' class='diplo_button' type='button' value='Steal Technology'>"
  }
  if (action_probabilities[ACTION_SPY_INCITE_CITY] != 0) {
    dhtml += "<input id='diplo_revo' class='diplo_button' type='button' value='Incite a revolt'>"
  }
  if (action_probabilities[ACTION_SPY_POISON] != 0) {
    dhtml += "<input id='diplo_poi' class='diplo_button' type='button' value='Poison city'>"
  }
  if (action_probabilities[ACTION_SPY_BRIBE_UNIT] != 0) {
    dhtml += "<input id='diplo_bribe' class='diplo_button' type='button' value='Bribe enemy unit'>"
  }
  if (action_probabilities[ACTION_SPY_SABOTAGE_UNIT] != 0) {
    dhtml += "<input id='diplo_spy_sabo' class='diplo_button' type='button' value='Sabotage enemy unit'>"
  }
  if (can_actor_unit_move(pdiplomat, target_tile)) {
    dhtml += "<input id='diplo_move' class='diplo_button' type='button' value='Keep moving'>"
  }

  dhtml += "<input id='diplo_cancel' class='diplo_button' type='button' value='Cancel'>"
         + "";
  $(id).html(dhtml);

  $(id).attr("title", "Choose Your Diplomat's Strategy");
  $(id).dialog({
			bgiframe: true,
			modal: true,
			width: "350"});

  $(id).dialog('open');
  $(".diplo_button").button();
  $(".diplo_button").css("width", "250px");

  $("#diplo_cancel").click(function() {
    $(id).remove();
  });

  if (action_probabilities[ACTION_ESTABLISH_EMBASSY] != 0) {
    $("#diplo_emb").click(function() {
      var packet = {"type" : packet_unit_do_action,
                     "actor_id" : pdiplomat['id'],
                     "target_id": pcity['id'],
                     "value" : 0,
                     "action_type": ACTION_ESTABLISH_EMBASSY};
      send_request (JSON.stringify(packet));

      $(id).remove();
    });
  }

  if (action_probabilities[ACTION_SPY_INVESTIGATE_CITY] != 0) {
    $("#diplo_inv").click(function() {
      var packet = {"type" : packet_unit_do_action,
        "actor_id" : pdiplomat['id'],
        "target_id": pcity['id'],
        "value" : 0,
        "action_type": ACTION_SPY_INVESTIGATE_CITY};
        send_request (JSON.stringify(packet));

        $(id).remove();
    });
  }

  if (action_probabilities[ACTION_SPY_SABOTAGE_CITY] != 0) {
    $("#diplo_sab").click(function() {
      var packet = {"type" : packet_unit_do_action,
        "actor_id" : pdiplomat['id'],
        "target_id": pcity['id'],
        "value" : 0,
        "action_type": ACTION_SPY_SABOTAGE_CITY};
        send_request (JSON.stringify(packet));

        $(id).remove();
    });
  }

  var last_tech = 0;

  if (action_probabilities[ACTION_SPY_STEAL_TECH] != 0) {
    $("#diplo_tech").click(function() {
      var packet = {"type" : packet_unit_do_action,
                     "actor_id" : pdiplomat['id'],
                     "target_id": pcity['id'],
                     "value" : last_tech,
                     "action_type": ACTION_SPY_STEAL_TECH};
      send_request (JSON.stringify(packet));

      $(id).remove();
    });
  }

  if (action_probabilities[ACTION_SPY_INCITE_CITY] != 0) {
    $("#diplo_revo").click(function() {
      var packet = {"type" : packet_unit_do_action,
        "actor_id" : pdiplomat['id'],
        "target_id": pcity['id'],
        "value" : 0,
        "action_type": ACTION_SPY_INCITE_CITY};
        send_request (JSON.stringify(packet));

        $(id).remove();
    });
  }

  if (action_probabilities[ACTION_SPY_POISON] != 0) {
    $("#diplo_poi").click(function() {
      var packet = {"type" : packet_unit_do_action,
        "actor_id" : pdiplomat['id'],
        "target_id": pcity['id'],
        "value" : 0,
        "action_type": ACTION_SPY_POISON};
        send_request (JSON.stringify(packet));

        $(id).remove();
    });
  }

  if (action_probabilities[ACTION_SPY_BRIBE_UNIT] != 0) {
    $("#diplo_bribe").click(function() {
      var packet = {"type" : packet_unit_do_action,
        "actor_id" : pdiplomat['id'],
        "target_id": punit['id'],
        "value" : 0,
        "action_type": ACTION_SPY_BRIBE_UNIT};
        send_request (JSON.stringify(packet));

        $(id).remove();
    });
  }

  if (action_probabilities[ACTION_SPY_SABOTAGE_UNIT] != 0) {
    $("#diplo_spy_sabo").click(function() {
      var packet = {"type" : packet_unit_do_action,
        "actor_id" : pdiplomat['id'],
        "target_id": punit['id'],
        "value" : 0,
        "action_type": ACTION_SPY_SABOTAGE_UNIT};
        send_request (JSON.stringify(packet));

        $(id).remove();
    });
  }

  if (can_actor_unit_move(pdiplomat, target_tile)) {
    $("#diplo_move").click(function() {
      var packet = {"type" : packet_unit_do_action,
        "actor_id" : pdiplomat['id'],
        "target_id": target_tile['index'],
        "value" : 0,
        "action_type": ACTION_MOVE};
        send_request (JSON.stringify(packet));

        $(id).remove();
    });
  }
}

<|endoftext|>


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

angular.module('mm.addons.mod_assign')

/**
 * Assign submission controller.
 *
 * @module mm.addons.mod_assign
 * @ngdoc controller
 * @name mmaModAssignSubmissionCtrl
 */

.controller('mmaAssignSubmissionList', function($scope, $mmSite, $mmWS, $mmFilepool, mmaGradingInfo, $stateParams, $ionicPlatform, $mmApp, $mmaModAssign) {
    $scope.courseid = $stateParams.courseid;
    $scope.assignid = $stateParams.assignid;
    $scope.isTablet = $ionicPlatform.isTablet();
    $scope.submissions = $stateParams.submissions;
    var i = 0;
    $mmApp.getDB().getAll('grading_info').then(function(data){
        $scope.syncDisable = data.length;
    });
    var sortSub = [];
    if($stateParams.submissions !== null) {
      $stateParams.submissions.forEach(function(submission) {
         i += submission.attachments.length;
        $mmApp.getDB().getAll(mmaGradingInfo).then(function(grade) {
            submission.graded = false;
            grade.forEach(function(data) {
               if(data.userid === submission.userid && $stateParams.assignid === data.assignid) {
                 submission.graded = true;
               }
            });
        });
        if(submission.attachments.length > 0) {
          sortSub.unshift(submission);
        }else {
          sortSub.push(submission);
        }
      });
      $scope.submissions = sortSub;
    }else {
      $scope.noSubmission = true;
    }
    $scope.submissionsLoaded = true;

    $mmSite.getDb().getAll('filepool').then(function(data){
        if(data.length === i){
            $scope.dlDisable = true;
        }else{
            $scope.dlDisable = false;
        }
    });

    $scope.addGrade = function() {
      var grades = [];
      var assignid;
      return $mmApp.getDB().getAll(mmaGradingInfo).then(function(grade) {
          grade.forEach(function(data) {
              grades[grades.length] = {
                  userid: data.userid,
                  grade: data.grade,
                  attemptnumber: -1,
                  addattempt: 0,
                  workflowstate: "",
                  plugindata: {
                    assignfeedbackcomments_editor: {
                      text:  data.comment,
                      format: 4
                    },
                    files_filemanager: data.files_filemanager // itemId
                  }
              };
              assignid = data.assignid;
              data.file.forEach(function(file) {
                //console.log($mmFS.readFile(file.localpath));
                //console.log($mmFS.readFileData($mmFS.readFile(file.localpath)));
                $mmaModAssign.uploadFiles(file, data.files_filemanager);
              });
          });
          $mmaModAssign.addGrade(assignid, grades);
      });
    };

    $scope.downloadAll = function() {
      var file;
      sortSub.forEach(function(sub) {
        file = $mmaModAssign.getLocalSubmissionFile(sub);
        file.forEach(function(attachment) {
          $mmFilepool.addToQueueByUrl($mmSite.getId(), attachment.fileurl, {}, sub.id , 0);
          $mmWS.downloadFile(attachment.fileurl, attachment.localpath, attachment.filename);
        });
      });
    };

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

angular.module('mm.addons.mod_assign')

/**
 * Assign submission controller.
 *
 * @module mm.addons.mod_assign
 * @ngdoc controller
 * @name mmaModAssignSubmissionCtrl
 */

.controller('mmaAssignSubmissionList', function($scope, $mmSite, $mmWS, $mmFilepool, mmaGradingInfo, $stateParams, $ionicPlatform, $mmApp, $mmaModAssign) {
    $scope.courseid = $stateParams.courseid;
    $scope.assignid = $stateParams.assignid;
    $scope.isTablet = $ionicPlatform.isTablet();
    $scope.submissions = $stateParams.submissions;
    var i = 0;
    $mmApp.getDB().getAll('grading_info').then(function(data){
        $scope.syncDisable = data.length;
    });
    var sortSub = [];
    if($stateParams.submissions !== null) {
      $stateParams.submissions.forEach(function(submission) {
         i += submission.attachments.length;
        $mmApp.getDB().getAll(mmaGradingInfo).then(function(grade) {
            submission.graded = false;
            grade.forEach(function(data) {
               if(data.userid === submission.userid && $stateParams.assignid === data.assignid) {
                 submission.graded = true;
               }
            });
        });
        if(submission.attachments.length > 0) {
          sortSub.unshift(submission);
        }else {
          sortSub.push(submission);
        }
      });
      $scope.submissions = sortSub;
    }else {
      $scope.noSubmission = true;
    }
    $scope.submissionsLoaded = true;

    $mmSite.getDb().getAll('filepool').then(function(data){
        if(data.length === i || i === 0){
            $scope.dlDisable = true;
        }else{
            $scope.dlDisable = false;
        }
    });

    $scope.addGrade = function() {
      var grades = [];
      var assignid;
      return $mmApp.getDB().getAll(mmaGradingInfo).then(function(grade) {
          grade.forEach(function(data) {
              grades[grades.length] = {
                  userid: data.userid,
                  grade: data.grade,
                  attemptnumber: -1,
                  addattempt: 0,
                  workflowstate: "",
                  plugindata: {
                    assignfeedbackcomments_editor: {
                      text:  data.comment,
                      format: 4
                    },
                    files_filemanager: data.files_filemanager // itemId
                  }
              };
              assignid = data.assignid;
              data.file.forEach(function(file) {
                //console.log($mmFS.readFile(file.localpath));
                //console.log($mmFS.readFileData($mmFS.readFile(file.localpath)));
                $mmaModAssign.uploadFiles(file, data.files_filemanager);
              });
          });
          $mmaModAssign.addGrade(assignid, grades);
      });
    };

    $scope.downloadAll = function() {
      var file;
      sortSub.forEach(function(sub) {
        file = $mmaModAssign.getLocalSubmissionFile(sub);
        file.forEach(function(attachment) {
          $mmFilepool.addToQueueByUrl($mmSite.getId(), attachment.fileurl, {}, sub.id , 0);
          $mmWS.downloadFile(attachment.fileurl, attachment.localpath, attachment.filename);
        });
      });
    };

});
<|endoftext|>


<commit_before>/*
 * Licensed to the Sakai Foundation (SF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The SF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */

/*global $, sdata, Config */

var sakai = sakai || {};

sakai.createsite = function(tuid,placement,showSettings){

    /////////////////////////////
    // Configuration variables //
    /////////////////////////////

    // - ID
    var createSite = "#createsite";

    // Class
    var createSiteNoncourseTemplateClass = "createsite_noncourse_template";

    // Container
    var createSiteContainer = createSite + "_container";

    // Course
    var createSiteCourse = createSite + "_course";
    var createSiteCourseContainer = createSiteCourse + "_container";
    //var createSiteCourseDetails = createSiteCourse + "_details"; TODO
    var createSiteCourseRequest = createSiteCourse + "_request";

    // Course requested
    var createSiteCourseRequested = createSiteCourse + "_requested";
    var createSiteCourseRequestedContainer = createSiteCourseRequested + "_container";

    // Coursesite
    var createSiteCoursesiteContainer = createSite + "_coursesite_container";

    // Non course
    var createSiteNoncourse = createSite + "_noncourse";
    var createSiteNoncourseCancel = createSiteNoncourse + "_cancel";
    var createSiteNoncourseContainer = createSiteNoncourse + "_container";
    var createSiteNoncourseDescription = createSiteNoncourse + "_description";
    var createSiteNoncourseId = createSiteNoncourse + "_id";
    var createSiteNoncourseName = createSiteNoncourse + "_name";
    var createSiteNoncourseProcess = createSiteNoncourse + "_process";
    var createSiteNoncourseSave = createSiteNoncourse + "_save";
    var createSiteNoncourseUrl = createSiteNoncourse + "_url";

    // Option
    var createSiteOption = createSite + "_option";
    var createSiteOptionCourse = createSiteOption + "_course";
    var createSiteOptionNoncourse = createSiteOption + "_noncourse";

    ///////////////////////
    // Utility functions //
    ///////////////////////

    var withMembers  = false;

    /**
     * Public function that can be called from elsewhere
     * (e.g. chat and sites widget)
     * It initializes the createsite widget and shows the jqmodal (ligthbox)
     */
    sakai.createsite.initialise = function(members){
        if (members){

            // Filter out myself
            var todelete = -1;
            for (var i = 0; i < members.items.length; i++){
                if (members.items[i].userid == sakai.data.me.user.userid){
                    todelete = i;
                }
            }
            if (todelete != -1) {
                members.items.splice(todelete, 1);
            }

            // Put me in as first element
            var item = {};
            item.name = sakai.data.me.profile.firstName + " " + sakai.data.me.profile.lastName;
            item.userid = sakai.data.me.user.userid;
            item.picture = sakai.config.URL.USER_DEFAULT_ICON_URL;
            if (sakai.data.me.profile.picture && $.evalJSON(sakai.data.me.profile.picture).name){
                item.picture = "/_user/public/" + sakai.data.me.user.userid + "/" + $.evalJSON(sakai.data.me.profile.picture).name;
            }
            members.items.unshift(item);

            withMembers = members;

            $(".description_fields").hide();
            $(".member_fields").show();
            $("#members_to_add").html($.TemplateRenderer("members_to_add_template", members));

        } else {
            $(".description_fields").show();
            $(".member_fields").hide();
            withMembers = false;
        }
        $("#createsite_course_requested_container").hide();
        $("#createsite_course_container").hide();
        $("#createsite_noncourse_container").show();
        $("#createsite_coursesite_container").show();
        $(createSiteContainer).jqmShow();
    };

    /**
     * Show or hide the process div and hide/shows the buttons
     * @param {Boolean} show
     *     true: show the process div and hide the buttons
     *     false: hide the process div and show the buttons
     */
    var showProcess = function(show){
        if(show){
            $(createSiteNoncourseCancel).hide();
            $(createSiteNoncourseSave).hide();
            $(createSiteNoncourseProcess).show();
        }else{
            $(createSiteNoncourseProcess).hide();
            $(createSiteNoncourseCancel).show();
            $(createSiteNoncourseSave).show();
        }
    };

    /**
     * Show or hide the course/noncourse containers
     * @param {Boolean} show
     *     true: show the course container and hide the noncourse container
     *     false: hide the course container and show the noncourse container
     */
    var showCourse = function(show){
        if(show){
            $(createSiteNoncourseContainer).hide();
            $(createSiteCourseContainer).show();
        }else{
            $(createSiteCourseContainer).hide();
            $(createSiteNoncourseContainer).show();
        }
    };

    /**
     * Replace or remove malicious characters from the string
     * We use this function to modify the siteid
     * String to test against: test :?=&;\/?@+$<>#%'"''{}|\\^[]'
     * @param {Object} input The string where the characters need to be replaced
     */
    var replaceCharacters = function(input){
        input = input.toLowerCase().replace(/ /g,"-");
        input = input.toLowerCase().replace(/'/g,"");
        input = input.toLowerCase().replace(/"/g,"");

        var regexp = new RegExp("[^a-z0-9_-]", "gi");
        input = input.replace(regexp,"_");

        return input;
    };

    ////////////////////
    // Request a site //
    ////////////////////

    /**
     * TODO (for now it just hides/shows divs)
     */
    var requestSite = function(){
        $(createSiteCourseContainer).hide();
        $(createSiteCoursesiteContainer).hide();
        $(createSiteCourseRequestedContainer).show();
    };

    ///////////////////
    // Create a site //
    ///////////////////

    /**
     * Create the actual site.
     * Sends information to the server about the site you are making.
     */
    var doSaveSite = function(siteid, sitetitle, sitedescription, sitetemplate){
    // Create a site node based on the template.
        $.ajax({
            url: "/sites.createsite.json",
            data: {
                "_charset_":"utf-8",
                ":sitepath": "/" + siteid,
                "name" : sitetitle,
                "description" : sitedescription,
                "id" : siteid,
                "sakai:site-template" : "/templates/" + sitetemplate
            },
            type: "POST",
            success: function(data, textStatus){
                document.location = "/sites/" + siteid;
            },
            // error: error,
            error: function(xhr, textStatus, thrownError){
                alert("An error has occurred: " + xhr.status + " " + xhr.statusText);
            }
        });
    };

    var saveSite = function(){

        // Get the values from the input text and radio fields
        var sitetitle = $(createSiteNoncourseName).val() || "";
        var sitedescription = $(createSiteNoncourseDescription).val() || "";
        var siteid = replaceCharacters($(createSiteNoncourseId).val());

        // Check if there is a site id or site title defined
        if (!siteid || sitetitle === "")
        {
            alert("Please specify a id and title.");
            return;
        }

        // Add the correct params send to the create site request
        // Site type is course/project or default

        var sitetemplate = $('input[name=' + createSiteNoncourseTemplateClass + ']:checked').val();

        // Hide the buttons and show the process status
        showProcess(true);
        doSaveSite(siteid, sitetitle, sitedescription, sitetemplate);
    };

    ////////////////////
    // Event Handlers //
    ////////////////////

    /*
     * Add jqModal functionality to the container.
     * This makes use of the jqModal (jQuery Modal) plugin that provides support
     * for lightboxes
     */
    $(createSiteContainer).jqm({
        modal: true,
        overlay: 20,
        toTop: true
    });

    /*
     * Add binding to the save button (create the site when you click on it)
     */
    $(createSiteNoncourseSave).click(function(){
        saveSite();
    });

    /*
     * Add binding to the request button
     * Sends an email to the server with details about the request;
     */
    $(createSiteCourseRequest).click(function(){
        requestSite();
    });

    /*
     * When you change something in the name of the site, it first removes the bad characters
     * and then it shows the edited url in the span
     */
    $(createSiteNoncourseName).bind("change", function(ev){
        var entered = replaceCharacters($(this).val());
        $(createSiteNoncourseId).val(entered);
    });

    /*
     * Show the course window
     */
    $(createSiteOptionCourse).bind("click", function(ev){
        showCourse(true);
    });

    /*
     * Show the noncourse window
     */
    $(createSiteOptionNoncourse).bind("click", function(ev){
        showCourse(false);
    });

    /////////////////////////////
    // Initialisation function //
    /////////////////////////////

    var doInit = function(){

        // Set the text of the span containing the url of the current site
        // e.g. http://celestine.caret.local:8080/site/
        $(createSiteNoncourseUrl).text(document.location.protocol + "//" + document.location.host + "/sites/");
    };

    doInit();
};

sdata.widgets.WidgetLoader.informOnLoad("createsite");<commit_msg>SAKIII-301 changes to createsite.js to alert if siteid taken<commit_after>/*
 * Licensed to the Sakai Foundation (SF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The SF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */

/*global $, sdata, Config */

var sakai = sakai || {};

sakai.createsite = function(tuid,placement,showSettings){

    /////////////////////////////
    // Configuration variables //
    /////////////////////////////

    // - ID
    var createSite = "#createsite";

    // Class
    var createSiteNoncourseTemplateClass = "createsite_noncourse_template";

    // Container
    var createSiteContainer = createSite + "_container";

    // Course
    var createSiteCourse = createSite + "_course";
    var createSiteCourseContainer = createSiteCourse + "_container";
    //var createSiteCourseDetails = createSiteCourse + "_details"; TODO
    var createSiteCourseRequest = createSiteCourse + "_request";

    // Course requested
    var createSiteCourseRequested = createSiteCourse + "_requested";
    var createSiteCourseRequestedContainer = createSiteCourseRequested + "_container";

    // Coursesite
    var createSiteCoursesiteContainer = createSite + "_coursesite_container";

    // Non course
    var createSiteNoncourse = createSite + "_noncourse";
    var createSiteNoncourseCancel = createSiteNoncourse + "_cancel";
    var createSiteNoncourseContainer = createSiteNoncourse + "_container";
    var createSiteNoncourseDescription = createSiteNoncourse + "_description";
    var createSiteNoncourseId = createSiteNoncourse + "_id";
    var createSiteNoncourseName = createSiteNoncourse + "_name";
    var createSiteNoncourseProcess = createSiteNoncourse + "_process";
    var createSiteNoncourseSave = createSiteNoncourse + "_save";
    var createSiteNoncourseUrl = createSiteNoncourse + "_url";

    // Option
    var createSiteOption = createSite + "_option";
    var createSiteOptionCourse = createSiteOption + "_course";
    var createSiteOptionNoncourse = createSiteOption + "_noncourse";

    ///////////////////////
    // Utility functions //
    ///////////////////////

    var withMembers  = false;

    /**
     * Public function that can be called from elsewhere
     * (e.g. chat and sites widget)
     * It initializes the createsite widget and shows the jqmodal (ligthbox)
     */
    sakai.createsite.initialise = function(members){
        if (members){

            // Filter out myself
            var todelete = -1;
            for (var i = 0; i < members.items.length; i++){
                if (members.items[i].userid == sakai.data.me.user.userid){
                    todelete = i;
                }
            }
            if (todelete != -1) {
                members.items.splice(todelete, 1);
            }

            // Put me in as first element
            var item = {};
            item.name = sakai.data.me.profile.firstName + " " + sakai.data.me.profile.lastName;
            item.userid = sakai.data.me.user.userid;
            item.picture = sakai.config.URL.USER_DEFAULT_ICON_URL;
            if (sakai.data.me.profile.picture && $.evalJSON(sakai.data.me.profile.picture).name){
                item.picture = "/_user/public/" + sakai.data.me.user.userid + "/" + $.evalJSON(sakai.data.me.profile.picture).name;
            }
            members.items.unshift(item);

            withMembers = members;

            $(".description_fields").hide();
            $(".member_fields").show();
            $("#members_to_add").html($.TemplateRenderer("members_to_add_template", members));

        } else {
            $(".description_fields").show();
            $(".member_fields").hide();
            withMembers = false;
        }
        $("#createsite_course_requested_container").hide();
        $("#createsite_course_container").hide();
        $("#createsite_noncourse_container").show();
        $("#createsite_coursesite_container").show();
        $(createSiteContainer).jqmShow();
    };

    /**
     * Show or hide the process div and hide/shows the buttons
     * @param {Boolean} show
     *     true: show the process div and hide the buttons
     *     false: hide the process div and show the buttons
     */
    var showProcess = function(show){
        if(show){
            $(createSiteNoncourseCancel).hide();
            $(createSiteNoncourseSave).hide();
            $(createSiteNoncourseProcess).show();
        }else{
            $(createSiteNoncourseProcess).hide();
            $(createSiteNoncourseCancel).show();
            $(createSiteNoncourseSave).show();
        }
    };

    /**
     * Show or hide the course/noncourse containers
     * @param {Boolean} show
     *     true: show the course container and hide the noncourse container
     *     false: hide the course container and show the noncourse container
     */
    var showCourse = function(show){
        if(show){
            $(createSiteNoncourseContainer).hide();
            $(createSiteCourseContainer).show();
        }else{
            $(createSiteCourseContainer).hide();
            $(createSiteNoncourseContainer).show();
        }
    };

    /**
     * Replace or remove malicious characters from the string
     * We use this function to modify the siteid
     * String to test against: test :?=&;\/?@+$<>#%'"''{}|\\^[]'
     * @param {Object} input The string where the characters need to be replaced
     */
    var replaceCharacters = function(input){
        input = input.toLowerCase().replace(/ /g,"-");
        input = input.toLowerCase().replace(/'/g,"");
        input = input.toLowerCase().replace(/"/g,"");

        var regexp = new RegExp("[^a-z0-9_-]", "gi");
        input = input.replace(regexp,"_");

        return input;
    };

    ////////////////////
    // Request a site //
    ////////////////////

    /**
     * TODO (for now it just hides/shows divs)
     */
    var requestSite = function(){
        $(createSiteCourseContainer).hide();
        $(createSiteCoursesiteContainer).hide();
        $(createSiteCourseRequestedContainer).show();
    };

    ///////////////////
    // Create a site //
    ///////////////////

    /**
     * Create the actual site.
     * Sends information to the server about the site you are making.
     */

    var doCheckSite = function(siteid){
    // Check if the site exists.
        var siteExists = false;
        $.ajax({
            url: "/sites/" + siteid + ".json",
            type: "GET",
            async: false,
            success: function(data, textStatus){
                siteExists = true;
            }
        });
        return siteExists;
    };

    var doSaveSite = function(siteid, sitetitle, sitedescription, sitetemplate){
    // Create a site node based on the template.
        $.ajax({
            url: "/sites.createsite.json",
            data: {
                "_charset_":"utf-8",
                ":sitepath": "/" + siteid,
                "name" : sitetitle,
                "description" : sitedescription,
                "id" : siteid,
                "sakai:site-template" : "/templates/" + sitetemplate
            },
            type: "POST",
            success: function(data, textStatus){
                document.location = "/sites/" + siteid;
            },
            // error: error,
            error: function(xhr, textStatus, thrownError){
                var siteCheck = doCheckSite(siteid);
                if (siteCheck){
                    alert("The site Url you specified is not available, please choose another.");
                } else {
                    alert("An error has occurred: " + xhr.status + " " + xhr.statusText);
                }
                showProcess(false);
            }
        });
    };

    var saveSite = function(){

        // Get the values from the input text and radio fields
        var sitetitle = $(createSiteNoncourseName).val() || "";
        var sitedescription = $(createSiteNoncourseDescription).val() || "";
        var siteid = replaceCharacters($(createSiteNoncourseId).val());

        // Check if there is a site id or site title defined
        if (!siteid || sitetitle === "")
        {
            alert("Please specify a id and title.");
            return;
        }

        // Add the correct params send to the create site request
        // Site type is course/project or default

        var sitetemplate = $('input[name=' + createSiteNoncourseTemplateClass + ']:checked').val();

        // Hide the buttons and show the process status
        showProcess(true);
        doSaveSite(siteid, sitetitle, sitedescription, sitetemplate);
    };

    ////////////////////
    // Event Handlers //
    ////////////////////

    /*
     * Add jqModal functionality to the container.
     * This makes use of the jqModal (jQuery Modal) plugin that provides support
     * for lightboxes
     */
    $(createSiteContainer).jqm({
        modal: true,
        overlay: 20,
        toTop: true
    });

    /*
     * Add binding to the save button (create the site when you click on it)
     */
    $(createSiteNoncourseSave).click(function(){
        saveSite();
    });

    /*
     * Add binding to the request button
     * Sends an email to the server with details about the request;
     */
    $(createSiteCourseRequest).click(function(){
        requestSite();
    });

    /*
     * When you change something in the name of the site, it first removes the bad characters
     * and then it shows the edited url in the span
     */
    $(createSiteNoncourseName).bind("change", function(ev){
        var entered = replaceCharacters($(this).val());
        $(createSiteNoncourseId).val(entered);
    });

    /*
     * Show the course window
     */
    $(createSiteOptionCourse).bind("click", function(ev){
        showCourse(true);
    });

    /*
     * Show the noncourse window
     */
    $(createSiteOptionNoncourse).bind("click", function(ev){
        showCourse(false);
    });

    /////////////////////////////
    // Initialisation function //
    /////////////////////////////

    var doInit = function(){

        // Set the text of the span containing the url of the current site
        // e.g. http://celestine.caret.local:8080/site/
        $(createSiteNoncourseUrl).text(document.location.protocol + "//" + document.location.host + "/sites/");
    };

    doInit();
};

sdata.widgets.WidgetLoader.informOnLoad("createsite");<|endoftext|>