<commit_before>const utils = require('../utils');
const ui = require('./_ui');

/**
 * Fetch UI elements settings configured as nodes attributes and properties.
 *
 * @private
 * @param  {external:jQuery} $el - Element on instance.
 * @param  {external:jQuery} $fields - Fields filtered.
 * @return {settings}
 */
const fetchUISettings = function ($el, $fields) {
  'use strict';

  const fetched = {};
  const elTag = $el[0].tagName;

  // Fetch form settings.
  if (elTag === 'FORM') {

    const disabled = ui.getAttr($el, 'disabled');
    const intern = ui.getAttr($el, 'intern') !== void 0;
    const autostart = ui.getAttr($el, 'autostart') !== void 0;
    const novalidate = ui.getAttr($el, 'novalidate') !== void 0;

    if (disabled) fetched.disabled = true;
    if (intern) fetched.intern = true;
    if (autostart) fetched.autostart = true;
    if (novalidate) fetched.disableHTML5Validation = true;

    const locale = ui.getAttr($el, 'locale');
    if (locale) fetched.locale = locale;
  }

  // Fetch fields settings.
  const fields = [];

  fetched.fields = fields;

  $fields.each(function (i, f) {

    const $f = $(f);
    const name = ui.getAttr($f, 'name');
    const type = ui.getAttr($f, 'type');

    const field = { name, $el: $f };
    const validators = {};

    const disabled = ui.getAttr($f, 'disabled') !== void 0;
    const required = ui.getAttr($f, 'required') !== void 0;
    const autostart = ui.getAttr($f, 'autostart') !== void 0;
    const intern = ui.getAttr($f, 'intern') !== void 0;

    if (disabled) field.disabled = true;
    if (required) field.required = true;
    if (autostart) field.autostart = true;
    if (intern) field.intern = true;

    const display = ui.getAttr($f, 'display');
    if (display) field.display = display;

    const minlength = ui.getAttr($f, 'minlength');
    const maxlength = ui.getAttr($f, 'maxlength');
    if (minlength) {
      if (!validators.isLength) validators.isLength = {};
      validators.isLength.min = +minlength;
    }
    if (maxlength) {
      if (!validators.isLength) validators.isLength = {};
      validators.isLength.max = +maxlength;
    }

    const min = ui.getAttr($f, 'min');
    const max = ui.getAttr($f, 'max');
    if (type === 'number') {
      validators.isFloat = true;
      if (min) {
        if (validators.isFloat === true) validators.isFloat = {};
        validators.isFloat.min = +min;
      }
      if (max) {
        if (validators.isFloat === true) validators.isFloat = {};
        validators.isFloat.max = +max;
      }
    }

    if (type === 'email') validators.isEmail = true;
    if (type === 'url') validators.isURL = true;
    if (type === 'datetime') validators.isDate = true;

    const pattern = ui.getAttr($f, 'pattern');
    const patternMsgs = ui.getAttr($f, 'pattern-msgs');
    if (pattern) {
      validators.matches = pattern;
      if (patternMsgs) validators.matches = { pattern, msgs: patternMsgs };
    }

    if (Object.keys(validators).length) {
      field.validators = validators;
    }
    if (Object.keys(field).length > 1 || Object.keys(validators).length) {
      fields.push(field);
    }
  });

  return fetched;
};

module.exports = fetchUISettings;
<commit_msg>fix: fetchUISettings pattern<commit_after>const utils = require('../utils');
const ui = require('./_ui');

/**
 * Fetch UI elements settings configured as nodes attributes and properties.
 *
 * @private
 * @param  {external:jQuery} $el - Element on instance.
 * @param  {external:jQuery} $fields - Fields filtered.
 * @return {settings}
 */
const fetchUISettings = function ($el, $fields) {
  'use strict';

  const fetched = {};
  const elTag = $el[0].tagName;

  // Fetch form settings.
  if (elTag === 'FORM') {

    const disabled = ui.getAttr($el, 'disabled');
    const intern = ui.getAttr($el, 'intern') !== void 0;
    const autostart = ui.getAttr($el, 'autostart') !== void 0;
    const novalidate = ui.getAttr($el, 'novalidate') !== void 0;

    if (disabled) fetched.disabled = true;
    if (intern) fetched.intern = true;
    if (autostart) fetched.autostart = true;
    if (novalidate) fetched.disableHTML5Validation = true;

    const locale = ui.getAttr($el, 'locale');
    if (locale) fetched.locale = locale;
  }

  // Fetch fields settings.
  const fields = [];

  fetched.fields = fields;

  $fields.each(function (i, f) {

    const $f = $(f);
    const name = ui.getAttr($f, 'name');
    const type = ui.getAttr($f, 'type');

    const field = { name, $el: $f };
    const validators = {};

    const disabled = ui.getAttr($f, 'disabled') !== void 0;
    const required = ui.getAttr($f, 'required') !== void 0;
    const autostart = ui.getAttr($f, 'autostart') !== void 0;
    const intern = ui.getAttr($f, 'intern') !== void 0;

    if (disabled) field.disabled = true;
    if (required) field.required = true;
    if (autostart) field.autostart = true;
    if (intern) field.intern = true;

    const display = ui.getAttr($f, 'display');
    if (display) field.display = display;

    const minlength = ui.getAttr($f, 'minlength');
    const maxlength = ui.getAttr($f, 'maxlength');
    if (minlength) {
      if (!validators.isLength) validators.isLength = {};
      validators.isLength.min = +minlength;
    }
    if (maxlength) {
      if (!validators.isLength) validators.isLength = {};
      validators.isLength.max = +maxlength;
    }

    const min = ui.getAttr($f, 'min');
    const max = ui.getAttr($f, 'max');
    if (type === 'number') {
      validators.isFloat = true;
      if (min) {
        if (validators.isFloat === true) validators.isFloat = {};
        validators.isFloat.min = +min;
      }
      if (max) {
        if (validators.isFloat === true) validators.isFloat = {};
        validators.isFloat.max = +max;
      }
    }

    if (type === 'email') validators.isEmail = true;
    if (type === 'url') validators.isURL = true;
    if (type === 'datetime') validators.isDate = true;

    let pattern = ui.getAttr($f, 'pattern');
    const patternMsgs = ui.getAttr($f, 'pattern-msgs');
    if (pattern) {
      pattern = new RegExp(pattern);
      validators.matches = pattern;
      if (patternMsgs) validators.matches = { pattern, msgs: patternMsgs };
    }

    if (Object.keys(validators).length) {
      field.validators = validators;
    }
    if (Object.keys(field).length > 1 || Object.keys(validators).length) {
      fields.push(field);
    }
  });

  return fetched;
};

module.exports = fetchUISettings;
<|endoftext|>


<commit_before>// vim: set sw=2:

function __load_and_transform_xml(el, url, cb)
{
  $.get(url, function(xml){
    if (xml.firstChild.nodeName != "xml-stylesheet")
      throw new Error("No stylesheet given")

    var xsl_proc = new XSLTProcessor ()
    var xsl_url = xml.firstChild.data.match(/href='([^']+)/)[1]
    $.get(xsl_url, function(xsl) {
      xsl_proc.importStylesheet (xsl)
      var fragment = xsl_proc.transformToFragment (xml, document)
      $(el).slideUp(function() {
        $(el).empty().append(fragment).slideDown("slow")
        if (cb != undefined)
        {
          cb(el)
        }
      })
    }, "xml")
  })
}

(function( $ ){

  $.fn.load_xml = function(url) {
      this.each(function(idx, el) {
        $(el).addClass("loading")
        $(el).html("Loading from url".replace(/url/g, url))
        __load_and_transform_xml(el, url, function(ele) {
          $(ele).removeClass("loading")
//          $(ele).add_table_footer("Source: " + url)
        })
      })
    };

  $.fn.add_table_footer = function(text) {
    var footer = $("

abc

")
    footer.find("td").html(text)
    this.find("table").append(footer)
  };

})( jQuery );

$(document).ready(function(){
  $("div[load]").each(function(index,el){
    var url = $(el).attr("load")

    if ($(el).attr("on-request"))
    {
      $(el).html("Click to load from url (source).".replace(/url/g, url))
      $(el).click(function() {
        $(el).removeAttr("on-request")
        $(el).load_xml(url)
      })
    }
    else
    {
      $(el).load_xml(url)
    }
  })

  $("h2").each(function(index, el) {
    var e = $(el)
    var anchor = e.text()
    e.append($("").attr("id", anchor))
    var a = $("").text(e.text())
    a.attr("href", "#" + anchor)
    var li = $("
").append(a)
    $("#toc").append(li)
  })

  setTimeout(function() {
    window.location.reload()
  }, 60*1000)

});
<commit_msg>ui: Fix click on load-on-reqeust items<commit_after>// vim: set sw=2:

function __load_and_transform_xml(el, url, cb)
{
  $.get(url, function(xml){
    if (xml.firstChild.nodeName != "xml-stylesheet")
      throw new Error("No stylesheet given")

    var xsl_proc = new XSLTProcessor ()
    var xsl_url = xml.firstChild.data.match(/href='([^']+)/)[1]
    $.get(xsl_url, function(xsl) {
      xsl_proc.importStylesheet (xsl)
      var fragment = xsl_proc.transformToFragment (xml, document)
      $(el).slideUp(function() {
        $(el).empty().append(fragment).slideDown("slow")
        if (cb != undefined)
        {
          cb(el)
        }
      })
    }, "xml")
  })
}

(function( $ ){

  $.fn.load_xml = function(url) {
      this.each(function(idx, el) {
        $(el).addClass("loading")
        $(el).html("Loading from url".replace(/url/g, url))
        __load_and_transform_xml(el, url, function(ele) {
          $(ele).removeClass("loading")
//          $(ele).add_table_footer("Source: " + url)
        })
      })
    };

  $.fn.add_table_footer = function(text) {
    var footer = $("

abc

")
    footer.find("td").html(text)
    this.find("table").append(footer)
  };

})( jQuery );

$(document).ready(function(){
  $("div[load]").each(function(index,el){
    var url = $(el).attr("load")

    if ($(el).attr("on-request"))
    {
      $(el).html("Click to load from url (source).".replace(/url/g, url))
      $(el).click(function() {
        $(el).removeAttr("on-request")
        $(el).load_xml(url)
        $(el).unbind("click")
      })
    }
    else
    {
      $(el).load_xml(url)
    }
  })

  $("h2").each(function(index, el) {
    var e = $(el)
    var anchor = e.text()
    e.append($("").attr("id", anchor))
    var a = $("").text(e.text())
    a.attr("href", "#" + anchor)
    var li = $("
").append(a)
    $("#toc").append(li)
  })

  setTimeout(function() {
    window.location.reload()
  }, 60*1000)

});
<|endoftext|>


<commit_before>import { createRange } from '../../util/arrays';
import { generateGuid } from '../../util/helpers';

export function set(data) {
  return {
    type: 'MOPIDY_SET',
    data,
  };
}

export function updateServer(server) {
  return {
    type: 'MOPIDY_UPDATE_SERVER',
    server,
  };
}

export function updateServers(servers) {
  return {
    type: 'MOPIDY_UPDATE_SERVERS',
    servers,
  };
}

export function addServer(data) {
  const {
    hostname: host,
    port,
    protocol,
  } = window.location;
  const server = {
    host,
    ssl: protocol === 'https:',
    port: port || (protocol === 'https:' ? '443' : '80'),
    ...data,
  };
  return {
    type: 'MOPIDY_UPDATE_SERVER',
    server: {
      ...server,
      id: generateGuid(),
      name: `${server.host}${server.ssl ? ' 🔒' : ''}`,
    },
  };
}

export function setCurrentServer(server) {
  return {
    type: 'MOPIDY_SET_CURRENT_SERVER',
    server,
  };
}

export function getServerState(id) {
  return {
    type: 'MOPIDY_GET_SERVER_STATE',
    id,
  };
}

export function removeServer(id) {
  return {
    type: 'MOPIDY_REMOVE_SERVER',
    id,
  };
}

export function setConnection(data) {
  return {
    type: 'MOPIDY_SET_CONNECTION',
    data,
  };
}

export function request(method, params = {}, response_callback = null, error_callback = null) {
  return {
    type: 'MOPIDY_REQUEST',
    method,
    params,
    response_callback,
    error_callback,
  };
}

export function connect() {
  return {
    type: 'MOPIDY_CONNECT',
  };
}

export function connecting() {
  return {
    type: 'MOPIDY_CONNECTING',
  };
}

export function disconnect() {
  return {
    type: 'MOPIDY_DISCONNECT',
  };
}

export function debug(call, value) {
  return {
    type: 'MOPIDY_DEBUG',
    call,
    value,
  };
}

export function restartStarted() {
  return {
    type: 'MOPIDY_RESTART_STARTED',
  };
}

export function restartFinished() {
  return {
    type: 'MOPIDY_RESTART_FINISHED',
  };
}

export function upgradeStarted() {
  return {
    type: 'MOPIDY_UPGRADE_STARTED',
  };
}

export function upgradeFinished() {
  return {
    type: 'MOPIDY_UPGRADE_FINISHED',
  };
}

export function localScanStarted() {
  return {
    type: 'MOPIDY_LOCAL_SCAN_STARTED',
  };
}

export function localScanFinished() {
  return {
    type: 'MOPIDY_LOCAL_SCAN_FINISHED',
  };
}

/**
 * Core play actions
 * */

export function getPlayState() {
  return {
    type: 'MOPIDY_GET_PLAY_STATE',
  };
}

export function play() {
  return {
    type: 'MOPIDY_PLAY',
  };
}

export function pause() {
  return {
    type: 'MOPIDY_PAUSE',
  };
}

export function stop() {
  return {
    type: 'MOPIDY_STOP',
  };
}

export function next() {
  return {
    type: 'MOPIDY_NEXT',
  };
}

export function previous() {
  return {
    type: 'MOPIDY_PREVIOUS',
  };
}

export function getMute() {
  return {
    type: 'MOPIDY_GET_MUTE',
  };
}

export function setMute(mute) {
  return {
    type: 'MOPIDY_SET_MUTE',
    mute,
  };
}

export function getVolume() {
  return {
    type: 'MOPIDY_GET_VOLUME',
  };
}

export function setVolume(volume) {
  return {
    type: 'MOPIDY_SET_VOLUME',
    volume,
  };
}

export function getConsume() {
  return {
    type: 'MOPIDY_GET_CONSUME',
  };
}

export function setConsume(consume) {
  return {
    type: 'MOPIDY_SET_CONSUME',
    consume,
  };
}

export function getRepeat() {
  return {
    type: 'MOPIDY_GET_REPEAT',
  };
}

export function setRepeat(repeat) {
  return {
    type: 'MOPIDY_SET_REPEAT',
    repeat,
  };
}

export function getRandom() {
  return {
    type: 'MOPIDY_GET_RANDOM',
  };
}

export function setRandom(random) {
  return {
    type: 'MOPIDY_SET_RANDOM',
    random,
  };
}

export function getTimePosition() {
  return {
    type: 'MOPIDY_GET_TIME_POSITION',
  };
}

export function setTimePosition(time_position) {
  return {
    type: 'MOPIDY_SET_TIME_POSITION',
    time_position: parseInt(time_position),
  };
}

export function timePosition(time_position) {
  return {
    type: 'MOPIDY_TIME_POSITION',
    time_position: parseInt(time_position),
  };
}

export function getUriSchemes() {
  return {
    type: 'MOPIDY_GET_URI_SCHEMES',
  };
}

/**
 * Advanced playback actions
 * */

export function getCurrentTrack() {
  return {
    type: 'MOPIDY_GET_CURRENT_TRACK',
  };
}

export function getStreamTitle() {
  return {
    type: 'MOPIDY_GET_STREAM_TITLE',
  };
}

export function currentTrackLoaded(tl_track) {
  return {
    type: 'MOPIDY_CURRENT_TRACK_LOADED',
    tl_track,
  };
}

export function getNextTrack() {
  return {
    type: 'MOPIDY_GET_NEXT_TRACK',
  };
}

export function clearCurrentTrack() {
  return {
    type: 'CLEAR_CURRENT_TRACK',
  };
}

export function getQueue() {
  return {
    type: 'MOPIDY_GET_QUEUE',
  };
}

export function changeTrack(tlid) {
  return {
    type: 'MOPIDY_CHANGE_TRACK',
    tlid,
  };
}

/**
 * Playing assets
 * */

export function playURIs({
  uris = [],
  from = null,
  shuffle = false,
}) {
  return {
    type: 'MOPIDY_PLAY_URIS',
    uris,
    from,
    shuffle,
  };
}

export function playAlbum(uri, from) {
  return {
    type: 'MOPIDY_PLAY_ALBUM',
    uri,
    from,
  };
}

export function playPlaylist({ uri, shuffle = false }) {
  return {
    type: 'MOPIDY_PLAY_PLAYLIST',
    uri,
    shuffle,
  };
}

export function enqueueURIs({
  uris = [],
  from = null,
  shuffle = false,
  at_position = null,
  play_next = false,
  offset = 0,
}) {
  return {
    type: 'MOPIDY_ENQUEUE_URIS',
    uris,
    from,
    shuffle,
    at_position,
    play_next,
    offset,
  };
}

export function enqueueAlbum({
  uri,
  from,
  play_next = false,
  at_position = null,
}) {
  return {
    type: 'MOPIDY_ENQUEUE_ALBUM',
    uri,
    from,
    play_next,
    at_position,
  };
}

export function enqueuePlaylist({
  uri,
  from,
  play_next = false,
  at_position = null,
}) {
  return {
    type: 'MOPIDY_ENQUEUE_PLAYLIST',
    from,
    uri,
    play_next,
    at_position,
  };
}

export function enqueueURIsBatchDone() {
  return {
    type: 'MOPIDY_ENQUEUE_URIS_BATCH_DONE',
  };
}

/**
 * Playlist maniopulation
 * */

export function removeTracks(tlids) {
  return {
    type: 'MOPIDY_REMOVE_TRACKS',
    tlids,
  };
}

export function reorderTracklist(indexes, insert_before) {
  const range = createRange(indexes);
  if (insert_before > range.start) insert_before -= range.length;
  return {
    type: 'MOPIDY_REORDER_TRACKLIST',
    range_start: range.start,
    range_length: range.length,
    insert_before,
  };
}

export function clearTracklist() {
  return {
    type: 'MOPIDY_CLEAR_TRACKLIST',
  };
}

export function shuffleTracklist() {
  return {
    type: 'MOPIDY_SHUFFLE_TRACKLIST',
  };
}

/**
 * Asset-oriented actions
 * */

export function getUris(uris) {
  return {
    type: 'MOPIDY_GET_URIS',
    uris,
  };
}

export function getImages(uris) {
  return {
    type: 'MOPIDY_GET_IMAGES',
    uris,
  };
}

export function createPlaylist(playlist) {
  return {
    type: 'MOPIDY_CREATE_PLAYLIST',
    playlist,
  };
}

export function deletePlaylist(uri) {
  return {
    type: 'MOPIDY_DELETE_PLAYLIST',
    uri,
  };
}

export function getLibraryMoods(uri) {
  return {
    type: 'MOPIDY_GET_LIBRARY_MOODS',
    uri,
  };
}

export function getLibraryFeaturedPlaylists(uri) {
  return {
    type: 'MOPIDY_GET_LIBRARY_FEATURED_PLAYLISTS',
    uri,
  };
}

export function getLibraryPlaylists(uri) {
  return {
    type: 'MOPIDY_GET_LIBRARY_PLAYLISTS',
    uri,
  };
}

export function getPlaylistGroup(uri, options) {
  return {
    type: 'MOPIDY_GET_PLAYLIST_GROUP',
    uri,
    options,
  };
}

export function getPlaylist(uri, options) {
  return {
    type: 'MOPIDY_GET_PLAYLIST',
    uri,
    options,
  };
}

export function getPlaylists(uris, processor = null) {
  return {
    type: 'MOPIDY_GET_PLAYLISTS',
    uris,
    processor,
  };
}

export function getDirectory(uri) {
  return {
    type: 'MOPIDY_GET_DIRECTORY',
    uri,
  };
}

export function getTracks(uris, options) {
  return {
    type: 'MOPIDY_GET_TRACKS',
    uris,
    options,
  };
}

export function getTrack(uri, options) {
  return getTracks([uri], options);
}

export function getLibraryArtists(uri = null) {
  return {
    type: 'MOPIDY_GET_LIBRARY_ARTISTS',
    uri,
  };
}

export function getLibraryAlbums(uri = null) {
  return {
    type: 'MOPIDY_GET_LIBRARY_ALBUMS',
    uri,
  };
}

export function getLibraryTracks(uri = null) {
  return {
    type: 'MOPIDY_GET_LIBRARY_TRACKS',
    uri,
  };
}

export function getArtist(uri, options) {
  return {
    type: 'MOPIDY_GET_ARTIST',
    uri,
    options,
  };
}

export function getAlbum(uri, options) {
  return {
    type: 'MOPIDY_GET_ALBUM',
    uri,
    options,
  };
}

export function view_getRandomTracks(limit = 100) {
  return {
    type: 'VIEW__GET_RANDOM_TRACKS',
    limit,
  };
}

export function clearSearchResults() {
  return {
    type: 'MOPIDY_CLEAR_SEARCH_RESULTS',
  };
}

export function getSearchResults(query, limit = 100, uri_schemes) {
  return {
    type: 'MOPIDY_GET_SEARCH_RESULTS',
    query,
    limit,
    uri_schemes,
  };
}

export function getQueueHistory() {
  return {
    type: 'MOPIDY_GET_QUEUE_HISTORY',
  };
}
<commit_msg>Object arguments for playAlbum, fixes #819<commit_after>import { createRange } from '../../util/arrays';
import { generateGuid } from '../../util/helpers';

export function set(data) {
  return {
    type: 'MOPIDY_SET',
    data,
  };
}

export function updateServer(server) {
  return {
    type: 'MOPIDY_UPDATE_SERVER',
    server,
  };
}

export function updateServers(servers) {
  return {
    type: 'MOPIDY_UPDATE_SERVERS',
    servers,
  };
}

export function addServer(data) {
  const {
    hostname: host,
    port,
    protocol,
  } = window.location;
  const server = {
    host,
    ssl: protocol === 'https:',
    port: port || (protocol === 'https:' ? '443' : '80'),
    ...data,
  };
  return {
    type: 'MOPIDY_UPDATE_SERVER',
    server: {
      ...server,
      id: generateGuid(),
      name: `${server.host}${server.ssl ? ' 🔒' : ''}`,
    },
  };
}

export function setCurrentServer(server) {
  return {
    type: 'MOPIDY_SET_CURRENT_SERVER',
    server,
  };
}

export function getServerState(id) {
  return {
    type: 'MOPIDY_GET_SERVER_STATE',
    id,
  };
}

export function removeServer(id) {
  return {
    type: 'MOPIDY_REMOVE_SERVER',
    id,
  };
}

export function setConnection(data) {
  return {
    type: 'MOPIDY_SET_CONNECTION',
    data,
  };
}

export function request(method, params = {}, response_callback = null, error_callback = null) {
  return {
    type: 'MOPIDY_REQUEST',
    method,
    params,
    response_callback,
    error_callback,
  };
}

export function connect() {
  return {
    type: 'MOPIDY_CONNECT',
  };
}

export function connecting() {
  return {
    type: 'MOPIDY_CONNECTING',
  };
}

export function disconnect() {
  return {
    type: 'MOPIDY_DISCONNECT',
  };
}

export function debug(call, value) {
  return {
    type: 'MOPIDY_DEBUG',
    call,
    value,
  };
}

export function restartStarted() {
  return {
    type: 'MOPIDY_RESTART_STARTED',
  };
}

export function restartFinished() {
  return {
    type: 'MOPIDY_RESTART_FINISHED',
  };
}

export function upgradeStarted() {
  return {
    type: 'MOPIDY_UPGRADE_STARTED',
  };
}

export function upgradeFinished() {
  return {
    type: 'MOPIDY_UPGRADE_FINISHED',
  };
}

export function localScanStarted() {
  return {
    type: 'MOPIDY_LOCAL_SCAN_STARTED',
  };
}

export function localScanFinished() {
  return {
    type: 'MOPIDY_LOCAL_SCAN_FINISHED',
  };
}

/**
 * Core play actions
 * */

export function getPlayState() {
  return {
    type: 'MOPIDY_GET_PLAY_STATE',
  };
}

export function play() {
  return {
    type: 'MOPIDY_PLAY',
  };
}

export function pause() {
  return {
    type: 'MOPIDY_PAUSE',
  };
}

export function stop() {
  return {
    type: 'MOPIDY_STOP',
  };
}

export function next() {
  return {
    type: 'MOPIDY_NEXT',
  };
}

export function previous() {
  return {
    type: 'MOPIDY_PREVIOUS',
  };
}

export function getMute() {
  return {
    type: 'MOPIDY_GET_MUTE',
  };
}

export function setMute(mute) {
  return {
    type: 'MOPIDY_SET_MUTE',
    mute,
  };
}

export function getVolume() {
  return {
    type: 'MOPIDY_GET_VOLUME',
  };
}

export function setVolume(volume) {
  return {
    type: 'MOPIDY_SET_VOLUME',
    volume,
  };
}

export function getConsume() {
  return {
    type: 'MOPIDY_GET_CONSUME',
  };
}

export function setConsume(consume) {
  return {
    type: 'MOPIDY_SET_CONSUME',
    consume,
  };
}

export function getRepeat() {
  return {
    type: 'MOPIDY_GET_REPEAT',
  };
}

export function setRepeat(repeat) {
  return {
    type: 'MOPIDY_SET_REPEAT',
    repeat,
  };
}

export function getRandom() {
  return {
    type: 'MOPIDY_GET_RANDOM',
  };
}

export function setRandom(random) {
  return {
    type: 'MOPIDY_SET_RANDOM',
    random,
  };
}

export function getTimePosition() {
  return {
    type: 'MOPIDY_GET_TIME_POSITION',
  };
}

export function setTimePosition(time_position) {
  return {
    type: 'MOPIDY_SET_TIME_POSITION',
    time_position: parseInt(time_position),
  };
}

export function timePosition(time_position) {
  return {
    type: 'MOPIDY_TIME_POSITION',
    time_position: parseInt(time_position),
  };
}

export function getUriSchemes() {
  return {
    type: 'MOPIDY_GET_URI_SCHEMES',
  };
}

/**
 * Advanced playback actions
 * */

export function getCurrentTrack() {
  return {
    type: 'MOPIDY_GET_CURRENT_TRACK',
  };
}

export function getStreamTitle() {
  return {
    type: 'MOPIDY_GET_STREAM_TITLE',
  };
}

export function currentTrackLoaded(tl_track) {
  return {
    type: 'MOPIDY_CURRENT_TRACK_LOADED',
    tl_track,
  };
}

export function getNextTrack() {
  return {
    type: 'MOPIDY_GET_NEXT_TRACK',
  };
}

export function clearCurrentTrack() {
  return {
    type: 'CLEAR_CURRENT_TRACK',
  };
}

export function getQueue() {
  return {
    type: 'MOPIDY_GET_QUEUE',
  };
}

export function changeTrack(tlid) {
  return {
    type: 'MOPIDY_CHANGE_TRACK',
    tlid,
  };
}

/**
 * Playing assets
 * */

export function playURIs({
  uris = [],
  from = null,
  shuffle = false,
}) {
  return {
    type: 'MOPIDY_PLAY_URIS',
    uris,
    from,
    shuffle,
  };
}

export function playAlbum({ uri, from }) {
  return {
    type: 'MOPIDY_PLAY_ALBUM',
    uri,
    from,
  };
}

export function playPlaylist({ uri, shuffle = false }) {
  return {
    type: 'MOPIDY_PLAY_PLAYLIST',
    uri,
    shuffle,
  };
}

export function enqueueURIs({
  uris = [],
  from = null,
  shuffle = false,
  at_position = null,
  play_next = false,
  offset = 0,
}) {
  return {
    type: 'MOPIDY_ENQUEUE_URIS',
    uris,
    from,
    shuffle,
    at_position,
    play_next,
    offset,
  };
}

export function enqueueAlbum({
  uri,
  from,
  play_next = false,
  at_position = null,
}) {
  return {
    type: 'MOPIDY_ENQUEUE_ALBUM',
    uri,
    from,
    play_next,
    at_position,
  };
}

export function enqueuePlaylist({
  uri,
  from,
  play_next = false,
  at_position = null,
}) {
  return {
    type: 'MOPIDY_ENQUEUE_PLAYLIST',
    from,
    uri,
    play_next,
    at_position,
  };
}

export function enqueueURIsBatchDone() {
  return {
    type: 'MOPIDY_ENQUEUE_URIS_BATCH_DONE',
  };
}

/**
 * Playlist maniopulation
 * */

export function removeTracks(tlids) {
  return {
    type: 'MOPIDY_REMOVE_TRACKS',
    tlids,
  };
}

export function reorderTracklist(indexes, insert_before) {
  const range = createRange(indexes);
  if (insert_before > range.start) insert_before -= range.length;
  return {
    type: 'MOPIDY_REORDER_TRACKLIST',
    range_start: range.start,
    range_length: range.length,
    insert_before,
  };
}

export function clearTracklist() {
  return {
    type: 'MOPIDY_CLEAR_TRACKLIST',
  };
}

export function shuffleTracklist() {
  return {
    type: 'MOPIDY_SHUFFLE_TRACKLIST',
  };
}

/**
 * Asset-oriented actions
 * */

export function getUris(uris) {
  return {
    type: 'MOPIDY_GET_URIS',
    uris,
  };
}

export function getImages(uris) {
  return {
    type: 'MOPIDY_GET_IMAGES',
    uris,
  };
}

export function createPlaylist(playlist) {
  return {
    type: 'MOPIDY_CREATE_PLAYLIST',
    playlist,
  };
}

export function deletePlaylist(uri) {
  return {
    type: 'MOPIDY_DELETE_PLAYLIST',
    uri,
  };
}

export function getLibraryMoods(uri) {
  return {
    type: 'MOPIDY_GET_LIBRARY_MOODS',
    uri,
  };
}

export function getLibraryFeaturedPlaylists(uri) {
  return {
    type: 'MOPIDY_GET_LIBRARY_FEATURED_PLAYLISTS',
    uri,
  };
}

export function getLibraryPlaylists(uri) {
  return {
    type: 'MOPIDY_GET_LIBRARY_PLAYLISTS',
    uri,
  };
}

export function getPlaylistGroup(uri, options) {
  return {
    type: 'MOPIDY_GET_PLAYLIST_GROUP',
    uri,
    options,
  };
}

export function getPlaylist(uri, options) {
  return {
    type: 'MOPIDY_GET_PLAYLIST',
    uri,
    options,
  };
}

export function getPlaylists(uris, processor = null) {
  return {
    type: 'MOPIDY_GET_PLAYLISTS',
    uris,
    processor,
  };
}

export function getDirectory(uri) {
  return {
    type: 'MOPIDY_GET_DIRECTORY',
    uri,
  };
}

export function getTracks(uris, options) {
  return {
    type: 'MOPIDY_GET_TRACKS',
    uris,
    options,
  };
}

export function getTrack(uri, options) {
  return getTracks([uri], options);
}

export function getLibraryArtists(uri = null) {
  return {
    type: 'MOPIDY_GET_LIBRARY_ARTISTS',
    uri,
  };
}

export function getLibraryAlbums(uri = null) {
  return {
    type: 'MOPIDY_GET_LIBRARY_ALBUMS',
    uri,
  };
}

export function getLibraryTracks(uri = null) {
  return {
    type: 'MOPIDY_GET_LIBRARY_TRACKS',
    uri,
  };
}

export function getArtist(uri, options) {
  return {
    type: 'MOPIDY_GET_ARTIST',
    uri,
    options,
  };
}

export function getAlbum(uri, options) {
  return {
    type: 'MOPIDY_GET_ALBUM',
    uri,
    options,
  };
}

export function view_getRandomTracks(limit = 100) {
  return {
    type: 'VIEW__GET_RANDOM_TRACKS',
    limit,
  };
}

export function clearSearchResults() {
  return {
    type: 'MOPIDY_CLEAR_SEARCH_RESULTS',
  };
}

export function getSearchResults(query, limit = 100, uri_schemes) {
  return {
    type: 'MOPIDY_GET_SEARCH_RESULTS',
    query,
    limit,
    uri_schemes,
  };
}

export function getQueueHistory() {
  return {
    type: 'MOPIDY_GET_QUEUE_HISTORY',
  };
}
<|endoftext|>


<commit_before>/**
 * Created by dreamarts on 2014/03/30.
 */

var _ = require('underscore')
  , log = require('log')
  , should = require("should")
  , extend = require('../../lib/extend')
  ;

describe('extend', function () {

  describe('オブジェクト操作', function () {

    it('getValue', function () {

      var target = {c: 'xxx'};

      should.equal(extend.getValue(target, 'c'), 'xxx');

    });

    it('getValue', function () {

      var target = {a: {b: {c: 'xxx'}}};

      should.equal(extend.getValue(target, 'a.b.c'), 'xxx');

      should.equal(extend.getValue(target, 'a.b.d'), undefined);

    });

    it('setValue', function () {

      var target = {c: 'xxx'};

      extend.setValue(target, 'd', 'yyy');

      should.equal(extend.getValue(target, 'c'), 'xxx');

      should.equal(extend.getValue(target, 'd'), 'yyy');

    });

    it('setValue', function () {

      var target = {a: {b: {c: 'xxx'}}};

      extend.setValue(target, 'a.b.d', 'yyy');

      should.equal(extend.getValue(target, 'a.b.c'), 'xxx');

      should.equal(extend.getValue(target, 'a.b.d'), 'yyy');

    });

    it('setValue (readonly)', function () {

      var target = {};

      var val = extend.getValue(target, 'a.b.d', 'yyy');

      extend.setValue(target, 'a.b.d', 'yyy');

      should.equal(extend.getValue(target, 'a.b.c'), undefined);

      should.equal(extend.getValue(target, 'a.b.d'), 'yyy');

    });

    it('hasValue', function () {

      var target = {a: {b: {c: 'xxx'}}};

      should.equal(extend.hasValue(target, 'a.b.c'), true);

      should.equal(extend.hasValue(target, 'a.b.d'), false);

      should.equal(extend.hasValue(target, 'a.x.y'), false);

      should.equal(extend.hasValue(target, 'a.x.z'), false);
    });

    it('delValue', function () {

      var target = {a: {b: {c: 'xxx'}}};

      extend.delValue(target, 'a.b.c')

      should.equal(extend.hasValue(target, 'a.b.c'), false);

      should.equal(extend.hasValue(target, 'a.b.d'), false);

    });

  });

});
<commit_msg>util強化<commit_after>/**
 * Created by dreamarts on 2014/03/30.
 */

var _ = require('underscore')
  , log = require('log')
  , should = require("should")
  , extend = require('../../lib/extend')
  ;

describe('extend', function () {

  describe('オブジェクト操作', function () {

    it('getValue', function () {

      var target = {c: 'xxx'};

      should.equal(extend.getValue(target, 'c'), 'xxx');

    });

    it('getValue', function () {

      var target = {a: {b: {c: 'xxx'}}};

      should.equal(extend.getValue(target, 'a.b.c'), 'xxx');

      should.equal(extend.getValue(target, 'a.b.d'), undefined);

    });

    it('setValue', function () {

      var target = {c: 'xxx'};

      extend.setValue(target, 'd', 'yyy');

      should.equal(extend.getValue(target, 'c'), 'xxx');

      should.equal(extend.getValue(target, 'd'), 'yyy');

    });

    it('setValue', function () {

      var target = {a: {b: {c: 'xxx'}}};

      extend.setValue(target, 'a.b.d', 'yyy');

      should.equal(extend.getValue(target, 'a.b.c'), 'xxx');

      should.equal(extend.getValue(target, 'a.b.d'), 'yyy');

    });

    it('setValue (readonly)', function () {

      var target = {};

      var val = extend.getValue(target, 'a.b.d', 'yyy');

      extend.setValue(target, 'a.b.d', 'yyy');

      should.equal(extend.getValue(target, 'a.b.c'), undefined);

      should.equal(extend.getValue(target, 'a.b.d'), 'yyy');

    });

    it('hasValue', function () {

      var target = {a: {b: {c: 'xxx'}}};

      should.equal(extend.hasValue(target, 'a'), true);

      should.equal(extend.hasValue(target, 'A'), false);

      should.equal(extend.hasValue(target, 'a.b.c'), true);

      should.equal(extend.hasValue(target, 'a.b.d'), false);

      should.equal(extend.hasValue(target, 'a.x.y'), false);

      should.equal(extend.hasValue(target, 'a.x.z'), false);
    });

    it('delValue', function () {

      var target = {a: {b: {c: 'xxx'}}};

      extend.delValue(target, 'a.b.c')

      should.equal(extend.hasValue(target, 'a.b.c'), false);

      should.equal(extend.hasValue(target, 'a.b.d'), false);

    });

  });

});
<|endoftext|>


<commit_before>import * as apiActions from './apiActions';
import { displaySuccessAlert, displayErrorAlert } from './alertsActions';

export const ASSIGNED_BOOKS_FETCHED = 'ASSIGNED_BOOKS_FETCHED';
export const ASSIGNMENT_CREATED = 'ASSIGNMENT_CREATED';
export const ASSIGNMENT_DELETED = 'ASSIGNMENT_DELETED';
export const ASSIGNMENT_PROGRESS_UPDATED = 'ASSIGNMENT_PROGRESS_UPDATED';
export const BOOKS_FETCHED = 'BOOKS_FETCHED';
export const BOOK_CREATED = 'BOOK_CREATED';
export const CREATE_BOOK = 'CREATE_BOOK';
export const DELETE_BOOK = 'DELETE_BOOK';
export const ERROR_ASSIGNED_BOOK_FETCHED = 'ERROR_ASSIGNED_BOOK_FETCHED';
export const ERROR_MY_UPDATES_FETCHED = 'ERROR_MY_UPDATES_FETCHED';
export const ERROR_UPDATES_FETCHED = 'ERROR_MY_UPDATES_FETCHED';
export const ERROR_ASSIGNMENT_CREATED = 'ERROR_ASSIGNMENT_CREATED';
export const ERROR_ASSIGNMENT_DELETED = 'ERROR_ASSIGNMENT_DELETED';
export const ERROR_ASSIGNMENT_PROGRESS_UPDATED = 'ERROR_ASSIGNMENT_PROGRESS_UPDATED';
export const ERROR_BOOK_CREATED = 'ERROR_BOOK_CREATED';
export const ERROR_BOOKS_FETCHED = 'ERROR_BOOKS_FETCHED';
export const ERROR_MARKED_BOOK_AS_READ = 'ERROR_MARKED_BOOK_AS_READ';
export const ERROR_MY_STATS_FETCHED = 'ERROR_MY_STATS_FETCHED';
export const ERROR_STATS_FETCHED = 'ERROR_STATS_FETCHED';
export const MARK_BOOK_AS_READ = 'MARK_BOOK_AS_READ';
export const MARKED_BOOK_AS_READ = 'MARKED_BOOK_AS_READ';
export const SAVE_RESPONSE = 'SAVE_RESPONSE';
export const SUCCESS_SAVE_RESPONSE = 'SUCCESS_SAVE_RESPONSE';
export const SUCCESS_MY_STATS_FETCHED = 'SUCCESS_MY_STATS_FETCHED';
export const SUCCESS_MY_UPDATES_FETCHED = 'SUCCESS_MY_UPDATES_FETCHED';
export const SUCCESS_STATS_FETCHED = 'SUCCESS_STATS_FETCHED';
export const SUCCESS_UPDATES_FETCHED = 'SUCCESS_UPDATES_FETCHED';
export const ERROR_SAVE_RESPONSE = 'ERROR_SAVE_RESPONSE';
export const UPDATE_ASSIGNMENT_PROGRESS = 'UPDATE_ASSIGNMENT_PROGRESS';
export const UPDATE_BOOK = 'UPDATE_BOOK';

export const API_ASSIGNED_BOOKS_RESOURCE_URL = '/api/books/me';
export const API_BOOKS_RESOURCE_URL = '/api/books';
export const API_BOOKS_ASSIGNMENT_RESOURCE_URL = '/api/assignments';
export const API_BOOKS_ASSIGNMENT_PROGRESS_RESOURCE_URL = '/api/assignment-progress';
export const API_RESPONSES_RESOURCE_URL = '/api/responses';
export const API_MY_STATS_RESOURCE_URL = '/api/stats/me';
export const API_STATS_RESOURCE_URL = '/api/stats';
export const API_MY_UPDATES_RESOURCE_URL = '/api/updates/me';
export const API_UPDATES_RESOURCE_URL = '/api/updates';

const csrfToken = [].slice.call(document.getElementsByTagName('meta'))
    .filter((meta) => meta.name === 'csrf-token')[0].content;

const _headers = {
  'X-CSRF-TOKEN': csrfToken
};

function booksFetched(data) {
  return {
    type: BOOKS_FETCHED,
    payload: data
  };
}

function errorBooksFetched() {
  return dispatch => {
    dispatch(displayErrorAlert('Error while fetching existing books!'));
    return {
      type: ERROR_BOOKS_FETCHED
    };
  };
}

export function fetchBooks() {
  return dispatch => {
    return apiActions.getRequest(API_BOOKS_RESOURCE_URL).then(
      (res) => { dispatch(booksFetched(res)); },
      (err) => { dispatch(errorBooksFetched(err)); });
  };
}

function statsFetched(data, studentId) {
  return {
    type: SUCCESS_STATS_FETCHED,
    payload: {
      stats: data.stats,
      studentId
    }
  };
}

function errorStatsFetched(err) {
  return {
    type: ERROR_STATS_FETCHED,
    payload: err
  };
}

export function fetchStats(studentId) {
  return dispatch => {
    return apiActions.getRequest(`${API_STATS_RESOURCE_URL}/${studentId}`).then(
      (res) => { dispatch(statsFetched(res, studentId)); },
      (err) => { dispatch(errorStatsFetched(err)); });
  };
}

function myStatsFetched(data) {
  return {
    type: SUCCESS_MY_STATS_FETCHED,
    payload: data
  };
}

function errorMyStatsFetched() {
  return {
    type: ERROR_MY_STATS_FETCHED
  };
}

export function fetchMyStats() {
  return dispatch => {
    return apiActions.getRequest(API_MY_STATS_RESOURCE_URL).then(
      (res) => { dispatch(myStatsFetched(res)); },
      (err) => { dispatch(errorMyStatsFetched(err)); });
  };
}

function myUpdatesFetched(data) {
  return {
    type: SUCCESS_MY_UPDATES_FETCHED,
    payload: data.updates
  };
}

function errorMyUpdatesFetched() {
  return {
    type: ERROR_MY_UPDATES_FETCHED
  };
}

export function fetchMyUpdates() {
  return dispatch => {
    return apiActions.getRequest(API_MY_UPDATES_RESOURCE_URL).then(
      res => { dispatch(myUpdatesFetched(res)); },
      err => { dispatch(errorMyUpdatesFetched(err)); }
    );
  };
}

function updatesFetched(data, studentId) {
  return {
    type: SUCCESS_UPDATES_FETCHED,
    payload: {
      updates: data.updates,
      studentId
    }
  };
}

function errorUpdatesFetched() {
  return {
    type: ERROR_UPDATES_FETCHED
  };
}

export function fetchUpdates(studentId) {
  return dispatch => {
    return apiActions.getRequest(`${API_UPDATES_RESOURCE_URL}/${studentId}`).then(
      res => { dispatch(updatesFetched(res, studentId)); },
      err => { dispatch(errorUpdatesFetched(err)); }
    );
  };
}

export function assignedBooksFetched(data) {
  return {
    type: ASSIGNED_BOOKS_FETCHED,
    payload: data
  };
}

export function errorAssignedBooksFetched() {
  return dispatch => {
    dispatch(displayErrorAlert('Error while fetching your books!'));
    return {
      type: ERROR_ASSIGNED_BOOK_FETCHED
    };
  };
}

export function fetchAssignedBooks() {
  return dispatch => {
    return apiActions.getRequest(API_ASSIGNED_BOOKS_RESOURCE_URL).then(
      res => { dispatch(assignedBooksFetched(res)); },
      err => { dispatch(errorAssignedBooksFetched(err)); }
    );
  };
}

export function assignmentCreated(data) {
  return dispatch => {
    dispatch(displaySuccessAlert('Assignment successfully created!'))
    return {
      type: ASSIGNMENT_CREATED,
      payload: data
    };
  }
}

export function errorAssignmentCreated(data) {
  return dispatch => {
    dispatch(displayErrorAlert('Error when creating assignment!'));
    return {
      type: ERROR_ASSIGNMENT_CREATED,
      payload: data
    };
  };
}

export function createAssignment(bookId, userId) {
  return dispatch => {
    return apiActions.postRequest(API_BOOKS_ASSIGNMENT_RESOURCE_URL,
      { book_id: bookId, user_id: userId }, _headers).then(
        res => dispatch(assignmentCreated(res)),
        err => dispatch(errorAssignmentCreated(err))
    );
  };
}

export function bookCreated(data) {
  return (dispatch, getState) => {
    const userId = getState().userProfileReducer.user.id;
    return dispatch(createAssignment(data.book.id, userId));
  };
}

export function errorBookCreated() {
  return {
    type: ERROR_BOOK_CREATED
  };
}

export function createBook(dataBook) {
  return dispatch => {
    return apiActions.postRequest(API_BOOKS_RESOURCE_URL, dataBook, _headers).then(
      res => dispatch(bookCreated(res)),
      err => dispatch(errorBookCreated(err))
    );
  };
}

export function assignmentDeleted(_id) {
  return {
    type: ASSIGNMENT_DELETED,
    payload: { id: _id }
  };
}

export function errorAssignmentDeleted() {
  return {
    type: ERROR_ASSIGNMENT_DELETED
  };
}

export function deleteAssignment(id) {
  return dispatch => {
    const successAssignmentDeleted = () => {
      dispatch(displaySuccessAlert('Book successfully deleted!'));
      dispatch(assignmentDeleted(id));
    };

    dispatch(apiActions.deleteRequest(`${API_BOOKS_ASSIGNMENT_RESOURCE_URL}/${id}`,
      successAssignmentDeleted, errorAssignmentDeleted, _headers));
  };
}

export function assignmentProgressUpdated(data) {
  return {
    type: ASSIGNMENT_PROGRESS_UPDATED,
    payload: data
  };
}

export function errorAssignmentProgressUpdated() {
  return {
    type: ERROR_ASSIGNMENT_PROGRESS_UPDATED
  };
}

export function updateAssignmentProgress(_id, _numPages) {
  return dispatch => {
    const dataProgress = {
      id: _id,
      num_pages_read: _numPages
    };
    const url = `${API_BOOKS_ASSIGNMENT_PROGRESS_RESOURCE_URL}/${_id}`;
    return apiActions.putRequest(url, dataProgress, _headers).then(
      res => dispatch(assignmentProgressUpdated(res)),
      err => dispatch(errorAssignmentProgressUpdated(err))
    );
  };
}

export function markedBookAsReadSuccess(data) {
  return {
    type: MARKED_BOOK_AS_READ,
    payload: data
  };
}

export function errorMarkBookAsRead() {
  return dispatch => {
    dispatch(displayErrorAlert('Error when marking book as read!'));

    return {
      type: ERROR_MARKED_BOOK_AS_READ
    };
  };
}

export function markBookAsRead(_id) {
  const url = `${API_BOOKS_ASSIGNMENT_PROGRESS_RESOURCE_URL}/${_id}/read`;
  return dispatch => {
    return apiActions.putRequest(url, {}, _headers).then(
        res => {
          dispatch(displaySuccessAlert('Book marked as read!'));
          return dispatch(markedBookAsReadSuccess(res))
        },
        err => dispatch(errorMarkBookAsRead(err))
      );
  };
}

function errorSaveResponse() {
  return dispatch => {
    dispatch(displayErrorAlert('Error when saving response!'));

    return {
      type: ERROR_SAVE_RESPONSE
    };
  };
}

function successSaveResponse(data) {
  return dispatch => {
    dispatch(displaySuccessAlert('Response successfully saved!'));
    return {
      type: SUCCESS_SAVE_RESPONSE,
      payload: data
    };
  };
}

function successCreateResponse(assignmendId, res) {
  return (dispatch, getState) => {
    const userId = getState().userProfileReducer.user.id;
    const assignments = getState().bookReducers.assignedBooks;
    const currentAssignment = assignments.find(
      assignment => parseInt(assignmendId, 10) === assignment.id
    );

    const url = `${API_BOOKS_ASSIGNMENT_RESOURCE_URL}/${assignmendId}`;
    const data = {
      response_id: res.response.id,
      user_id: userId,
      book_id: currentAssignment.book.id
    };

    return apiActions.putRequest(url, data, _headers).then(
        _res => dispatch(successSaveResponse(_res)),
        err => dispatch(errorSaveResponse(err))
      );
  };
}

export function saveResponse(props) {
  const assignmentId = props.assignmentId;
  const data = { type: props.type };
  const attachments = [];

  switch (data.type) {
    case 'text':
      data.content = props.content;
      break;

    case 'image':
      attachments.push({ file: props.file, fieldName: 'file' });
      break;

    case 'video':
    case 'link':
      data.url = props.url;
      break;

    default:
      break;
  }

  if (attachments.length > 0) {
    return dispatch => {
      return apiActions.postRequestWithAttachments(API_RESPONSES_RESOURCE_URL, data,
        attachments, _headers).then(
        res => dispatch(successCreateResponse(assignmentId, res)),
        err => dispatch(errorSaveResponse(err))
      );
    };
  }

  return dispatch => {
    return apiActions.postRequest(API_RESPONSES_RESOURCE_URL, data, _headers).then(
        res => dispatch(successCreateResponse(assignmentId, res)),
        err => dispatch(errorSaveResponse(err))
      );
  };
}
<commit_msg>use new delete request<commit_after>import * as apiActions from './apiActions';
import { displaySuccessAlert, displayErrorAlert } from './alertsActions';

export const ASSIGNED_BOOKS_FETCHED = 'ASSIGNED_BOOKS_FETCHED';
export const ASSIGNMENT_CREATED = 'ASSIGNMENT_CREATED';
export const ASSIGNMENT_DELETED = 'ASSIGNMENT_DELETED';
export const ASSIGNMENT_PROGRESS_UPDATED = 'ASSIGNMENT_PROGRESS_UPDATED';
export const BOOKS_FETCHED = 'BOOKS_FETCHED';
export const BOOK_CREATED = 'BOOK_CREATED';
export const CREATE_BOOK = 'CREATE_BOOK';
export const DELETE_BOOK = 'DELETE_BOOK';
export const ERROR_ASSIGNED_BOOK_FETCHED = 'ERROR_ASSIGNED_BOOK_FETCHED';
export const ERROR_MY_UPDATES_FETCHED = 'ERROR_MY_UPDATES_FETCHED';
export const ERROR_UPDATES_FETCHED = 'ERROR_MY_UPDATES_FETCHED';
export const ERROR_ASSIGNMENT_CREATED = 'ERROR_ASSIGNMENT_CREATED';
export const ERROR_ASSIGNMENT_DELETED = 'ERROR_ASSIGNMENT_DELETED';
export const ERROR_ASSIGNMENT_PROGRESS_UPDATED = 'ERROR_ASSIGNMENT_PROGRESS_UPDATED';
export const ERROR_BOOK_CREATED = 'ERROR_BOOK_CREATED';
export const ERROR_BOOKS_FETCHED = 'ERROR_BOOKS_FETCHED';
export const ERROR_MARKED_BOOK_AS_READ = 'ERROR_MARKED_BOOK_AS_READ';
export const ERROR_MY_STATS_FETCHED = 'ERROR_MY_STATS_FETCHED';
export const ERROR_STATS_FETCHED = 'ERROR_STATS_FETCHED';
export const MARK_BOOK_AS_READ = 'MARK_BOOK_AS_READ';
export const MARKED_BOOK_AS_READ = 'MARKED_BOOK_AS_READ';
export const SAVE_RESPONSE = 'SAVE_RESPONSE';
export const SUCCESS_SAVE_RESPONSE = 'SUCCESS_SAVE_RESPONSE';
export const SUCCESS_MY_STATS_FETCHED = 'SUCCESS_MY_STATS_FETCHED';
export const SUCCESS_MY_UPDATES_FETCHED = 'SUCCESS_MY_UPDATES_FETCHED';
export const SUCCESS_STATS_FETCHED = 'SUCCESS_STATS_FETCHED';
export const SUCCESS_UPDATES_FETCHED = 'SUCCESS_UPDATES_FETCHED';
export const ERROR_SAVE_RESPONSE = 'ERROR_SAVE_RESPONSE';
export const UPDATE_ASSIGNMENT_PROGRESS = 'UPDATE_ASSIGNMENT_PROGRESS';
export const UPDATE_BOOK = 'UPDATE_BOOK';

export const API_ASSIGNED_BOOKS_RESOURCE_URL = '/api/books/me';
export const API_BOOKS_RESOURCE_URL = '/api/books';
export const API_BOOKS_ASSIGNMENT_RESOURCE_URL = '/api/assignments';
export const API_BOOKS_ASSIGNMENT_PROGRESS_RESOURCE_URL = '/api/assignment-progress';
export const API_RESPONSES_RESOURCE_URL = '/api/responses';
export const API_MY_STATS_RESOURCE_URL = '/api/stats/me';
export const API_STATS_RESOURCE_URL = '/api/stats';
export const API_MY_UPDATES_RESOURCE_URL = '/api/updates/me';
export const API_UPDATES_RESOURCE_URL = '/api/updates';

const csrfToken = [].slice.call(document.getElementsByTagName('meta'))
    .filter((meta) => meta.name === 'csrf-token')[0].content;

const _headers = {
  'X-CSRF-TOKEN': csrfToken
};

function booksFetched(data) {
  return {
    type: BOOKS_FETCHED,
    payload: data
  };
}

function errorBooksFetched() {
  return dispatch => {
    dispatch(displayErrorAlert('Error while fetching existing books!'));
    return {
      type: ERROR_BOOKS_FETCHED
    };
  };
}

export function fetchBooks() {
  return dispatch => {
    return apiActions.getRequest(API_BOOKS_RESOURCE_URL).then(
      (res) => { dispatch(booksFetched(res)); },
      (err) => { dispatch(errorBooksFetched(err)); });
  };
}

function statsFetched(data, studentId) {
  return {
    type: SUCCESS_STATS_FETCHED,
    payload: {
      stats: data.stats,
      studentId
    }
  };
}

function errorStatsFetched(err) {
  return {
    type: ERROR_STATS_FETCHED,
    payload: err
  };
}

export function fetchStats(studentId) {
  return dispatch => {
    return apiActions.getRequest(`${API_STATS_RESOURCE_URL}/${studentId}`).then(
      (res) => { dispatch(statsFetched(res, studentId)); },
      (err) => { dispatch(errorStatsFetched(err)); });
  };
}

function myStatsFetched(data) {
  return {
    type: SUCCESS_MY_STATS_FETCHED,
    payload: data
  };
}

function errorMyStatsFetched() {
  return {
    type: ERROR_MY_STATS_FETCHED
  };
}

export function fetchMyStats() {
  return dispatch => {
    return apiActions.getRequest(API_MY_STATS_RESOURCE_URL).then(
      (res) => { dispatch(myStatsFetched(res)); },
      (err) => { dispatch(errorMyStatsFetched(err)); });
  };
}

function myUpdatesFetched(data) {
  return {
    type: SUCCESS_MY_UPDATES_FETCHED,
    payload: data.updates
  };
}

function errorMyUpdatesFetched() {
  return {
    type: ERROR_MY_UPDATES_FETCHED
  };
}

export function fetchMyUpdates() {
  return dispatch => {
    return apiActions.getRequest(API_MY_UPDATES_RESOURCE_URL).then(
      res => { dispatch(myUpdatesFetched(res)); },
      err => { dispatch(errorMyUpdatesFetched(err)); }
    );
  };
}

function updatesFetched(data, studentId) {
  return {
    type: SUCCESS_UPDATES_FETCHED,
    payload: {
      updates: data.updates,
      studentId
    }
  };
}

function errorUpdatesFetched() {
  return {
    type: ERROR_UPDATES_FETCHED
  };
}

export function fetchUpdates(studentId) {
  return dispatch => {
    return apiActions.getRequest(`${API_UPDATES_RESOURCE_URL}/${studentId}`).then(
      res => { dispatch(updatesFetched(res, studentId)); },
      err => { dispatch(errorUpdatesFetched(err)); }
    );
  };
}

export function assignedBooksFetched(data) {
  return {
    type: ASSIGNED_BOOKS_FETCHED,
    payload: data
  };
}

export function errorAssignedBooksFetched() {
  return dispatch => {
    dispatch(displayErrorAlert('Error while fetching your books!'));
    return {
      type: ERROR_ASSIGNED_BOOK_FETCHED
    };
  };
}

export function fetchAssignedBooks() {
  return dispatch => {
    return apiActions.getRequest(API_ASSIGNED_BOOKS_RESOURCE_URL).then(
      res => { dispatch(assignedBooksFetched(res)); },
      err => { dispatch(errorAssignedBooksFetched(err)); }
    );
  };
}

export function assignmentCreated(data) {
  return dispatch => {
    dispatch(displaySuccessAlert('Assignment successfully created!'))
    return {
      type: ASSIGNMENT_CREATED,
      payload: data
    };
  }
}

export function errorAssignmentCreated(data) {
  return dispatch => {
    dispatch(displayErrorAlert('Error when creating assignment!'));
    return {
      type: ERROR_ASSIGNMENT_CREATED,
      payload: data
    };
  };
}

export function createAssignment(bookId, userId) {
  return dispatch => {
    return apiActions.postRequest(API_BOOKS_ASSIGNMENT_RESOURCE_URL,
      { book_id: bookId, user_id: userId }, _headers).then(
        res => dispatch(assignmentCreated(res)),
        err => dispatch(errorAssignmentCreated(err))
    );
  };
}

export function bookCreated(data) {
  return (dispatch, getState) => {
    const userId = getState().userProfileReducer.user.id;
    return dispatch(createAssignment(data.book.id, userId));
  };
}

export function errorBookCreated() {
  return {
    type: ERROR_BOOK_CREATED
  };
}

export function createBook(dataBook) {
  return dispatch => {
    return apiActions.postRequest(API_BOOKS_RESOURCE_URL, dataBook, _headers).then(
      res => dispatch(bookCreated(res)),
      err => dispatch(errorBookCreated(err))
    );
  };
}

export function assignmentDeleted(_id) {
  return {
    type: ASSIGNMENT_DELETED,
    payload: { id: _id }
  };
}

export function errorAssignmentDeleted() {
  return {
    type: ERROR_ASSIGNMENT_DELETED
  };
}

export function deleteAssignment(id) {
  return dispatch => {
    const successAssignmentDeleted = () => {
      dispatch(displaySuccessAlert('Book successfully deleted!'));
      return dispatch(assignmentDeleted(id));
    };

    return apiActions.deleteRequest(`${API_BOOKS_ASSIGNMENT_RESOURCE_URL}/${id}`, _headers).then(
      () => dispatch(successAssignmentDeleted()),
      () => dispatch(errorAssignmentDeleted())
    );
  };
}

export function assignmentProgressUpdated(data) {
  return {
    type: ASSIGNMENT_PROGRESS_UPDATED,
    payload: data
  };
}

export function errorAssignmentProgressUpdated() {
  return {
    type: ERROR_ASSIGNMENT_PROGRESS_UPDATED
  };
}

export function updateAssignmentProgress(_id, _numPages) {
  return dispatch => {
    const dataProgress = {
      id: _id,
      num_pages_read: _numPages
    };
    const url = `${API_BOOKS_ASSIGNMENT_PROGRESS_RESOURCE_URL}/${_id}`;
    return apiActions.putRequest(url, dataProgress, _headers).then(
      res => dispatch(assignmentProgressUpdated(res)),
      err => dispatch(errorAssignmentProgressUpdated(err))
    );
  };
}

export function markedBookAsReadSuccess(data) {
  return {
    type: MARKED_BOOK_AS_READ,
    payload: data
  };
}

export function errorMarkBookAsRead() {
  return dispatch => {
    dispatch(displayErrorAlert('Error when marking book as read!'));

    return {
      type: ERROR_MARKED_BOOK_AS_READ
    };
  };
}

export function markBookAsRead(_id) {
  const url = `${API_BOOKS_ASSIGNMENT_PROGRESS_RESOURCE_URL}/${_id}/read`;
  return dispatch => {
    return apiActions.putRequest(url, {}, _headers).then(
        res => {
          dispatch(displaySuccessAlert('Book marked as read!'));
          return dispatch(markedBookAsReadSuccess(res))
        },
        err => dispatch(errorMarkBookAsRead(err))
      );
  };
}

function errorSaveResponse() {
  return dispatch => {
    dispatch(displayErrorAlert('Error when saving response!'));

    return {
      type: ERROR_SAVE_RESPONSE
    };
  };
}

function successSaveResponse(data) {
  return dispatch => {
    dispatch(displaySuccessAlert('Response successfully saved!'));
    return {
      type: SUCCESS_SAVE_RESPONSE,
      payload: data
    };
  };
}

function successCreateResponse(assignmendId, res) {
  return (dispatch, getState) => {
    const userId = getState().userProfileReducer.user.id;
    const assignments = getState().bookReducers.assignedBooks;
    const currentAssignment = assignments.find(
      assignment => parseInt(assignmendId, 10) === assignment.id
    );

    const url = `${API_BOOKS_ASSIGNMENT_RESOURCE_URL}/${assignmendId}`;
    const data = {
      response_id: res.response.id,
      user_id: userId,
      book_id: currentAssignment.book.id
    };

    return apiActions.putRequest(url, data, _headers).then(
        _res => dispatch(successSaveResponse(_res)),
        err => dispatch(errorSaveResponse(err))
      );
  };
}

export function saveResponse(props) {
  const assignmentId = props.assignmentId;
  const data = { type: props.type };
  const attachments = [];

  switch (data.type) {
    case 'text':
      data.content = props.content;
      break;

    case 'image':
      attachments.push({ file: props.file, fieldName: 'file' });
      break;

    case 'video':
    case 'link':
      data.url = props.url;
      break;

    default:
      break;
  }

  if (attachments.length > 0) {
    return dispatch => {
      return apiActions.postRequestWithAttachments(API_RESPONSES_RESOURCE_URL, data,
        attachments, _headers).then(
        res => dispatch(successCreateResponse(assignmentId, res)),
        err => dispatch(errorSaveResponse(err))
      );
    };
  }

  return dispatch => {
    return apiActions.postRequest(API_RESPONSES_RESOURCE_URL, data, _headers).then(
        res => dispatch(successCreateResponse(assignmentId, res)),
        err => dispatch(errorSaveResponse(err))
      );
  };
}
<|endoftext|>


<commit_before>var PORT = 9529;
var http = require('http');
var qs = require('qs');

var TOKEN = 'rinesnow';

function checkSignature(params,token){
	//1.将token、timestamp、nonce三个参数进行字典序排序
	//2.将三个参数字符串拼接成一个字符串进行sha1加密
	//3.开发者获得加密后的字符串可与signature对比，标识该请求来源于微信  return true/false

	var key = [token, params.timestamp,params.nonce].sort().join('');//拼接
	var sha1 = require('crypto').createHash('sha1');
	sha1.update(key);
	return sha1.digest('hex')==params.signature;

}

var server = http.createServer(function(request,response){
	//解析URL中的Query部分，用qs模块（npm install qs）将Query解析成json
	var url=require('url');
	var query = url.parse(request.url).query;
	var params = qs.parse(query);

	console.log(params);
	console.log("token-->",TOKEN);

	if(checkSignature(params,TOKEN)){
		console.log("chenggong");
		response.end(params.echostr);

	}else{
		response.end('signature fail');
		return;
	}
		console.log(request.method+'/////');

	//若请求时GET，返回echostr用于通过服务器有效检验
	if(request.method=="GET"){
		response.end(params.echostr);
	}else{
	//否则是微信给开发者服务器的POST请求
		var postdata = "";
		console.log('else'+'/////');

		request.addListener("data",function(postchunk){
			postdata+= postchunk;
			console.log(postdata+'/////data');

		});
		request.addListener("end",function(){
			console.log(postdata);
			response.end('success');
		});
	}

});
server.listen(PORT);
console.log("Server running at port:"+PORT+".");<commit_msg>add message.js debug<commit_after>var PORT = 9529;
var http = require('http');
var qs = require('qs');

var TOKEN = 'rinesnow';

function checkSignature(params,token){
	//1.将token、timestamp、nonce三个参数进行字典序排序
	//2.将三个参数字符串拼接成一个字符串进行sha1加密
	//3.开发者获得加密后的字符串可与signature对比，标识该请求来源于微信  return true/false

	var key = [token, params.timestamp,params.nonce].sort().join('');//拼接
	var sha1 = require('crypto').createHash('sha1');
	sha1.update(key);
	return sha1.digest('hex')==params.signature;

}

var server = http.createServer(function(request,response){
	//解析URL中的Query部分，用qs模块（npm install qs）将Query解析成json
	var url=require('url');
	var query = url.parse(request.url).query;
	var params = qs.parse(query);

	console.log(params);
	console.log("token-->",TOKEN);

	if(checkSignature(params,TOKEN)){
		console.log("chenggong");
		response.end(params.echostr);

	}else{
		response.end('signature fail');
		return;
	}
		console.log(request.method+'/////');

	//若请求时GET，返回echostr用于通过服务器有效检验
	if(request.method=="GET"){
		response.end(params.echostr);
	}else{
	//否则是微信给开发者服务器的POST请求
		var postdata = "";
		console.log('else'+'/////');

		request.addListener("data",function(postchunk){
			postdata += postchunk;
			console.log(postchunk+'/////data');

		});
		console.log(postdata);

		request.addListener("end",function(){
			console.log(postdata);
			response.end('success');
		});
	}

});
server.listen(PORT);
console.log("Server running at port:"+PORT+".");<|endoftext|>


<commit_before>// NOTE: Rewriting former EditorSession.
// Now the EditorSession acts only as an interface to an EditorState
// part of the overall Application state
import {
  isPlainObject, Selection, operationHelpers, isString
} from 'substance'

import EditorState from './EditorState'
import SurfaceManager from './SurfaceManager'
import MarkersManager from './MarkersManager'
import GlobalEventHandler from './GlobalEventHandler'
import KeyboardManager from './KeyboardManager'
import CommandManager from './CommandManager'

export default function (DocumentSession) {
  class EditorSession extends DocumentSession {
    constructor (doc, config, contextProvider, initialState = {}) {
      super(doc, config)

      if (!contextProvider) contextProvider = { context: { editorSession: this } }

      this.config = config
      this.contextProvider = contextProvider

      let editorState = new EditorState(Object.assign({
        document: doc,
        selection: Selection.nullSelection,
        selectionState: {},
        focusedSurface: null,
        commandStates: {},
        hasUnsavedChanges: false,
        isBlurred: false,
        overlayId: null
      }, initialState))
      let surfaceManager = new SurfaceManager(editorState)
      let markersManager = new MarkersManager(editorState)
      let globalEventHandler = new GlobalEventHandler(editorState)
      let keyboardManager = new KeyboardManager(config.getKeyboardShortcuts(), (commandName) => {
        return this.executeCommand(commandName)
      }, contextProvider)
      let commandManager = new CommandManager(editorState,
        // update commands when document or selection have changed
        ['document', 'selection'],
        config.getCommands(),
        contextProvider
      )

      this.editorState = editorState
      this.surfaceManager = surfaceManager
      this.markersManager = markersManager
      this.globalEventHandler = globalEventHandler
      this.keyboardManager = keyboardManager
      this.commandManager = commandManager

      doc.on('document:changed', this._onDocumentChange, this)
    }

    dispose () {
      this.getDocument().off(this)
    }

    initialize () {
      // TODO: is this the right place?
      // initial reduce step
      this.commandManager.reduce()
    }

    getConfigurator () {
      return this.config
    }

    getContext () {
      return this.contextProvider.context
    }

    getSelection () {
      return this.editorState.selection
    }

    getSelectionState () {
      return this.editorState.selectionState
    }

    getCommandStates () {
      return this.editorState.commandStates
    }

    getFocusedSurface () {
      return this.editorState.focusedSurface
    }

    isBlurred () {
      return Boolean(this.editorState.isBlurred)
    }

    hasUnsavedChanges () {
      return Boolean(this.editorState.hasUnsavedChanges)
    }

    setSelection (sel) {
      // console.log('EditorSession.setSelection()', sel)
      if (!sel) sel = Selection.nullSelection
      if (sel && isPlainObject(sel)) {
        sel = this.getDocument().createSelection(sel)
      }
      if (sel && !sel.isNull()) {
        if (!sel.surfaceId) {
          let fs = this.getFocusedSurface()
          if (fs) {
            sel.surfaceId = fs.id
          }
        }
      }
      _addSurfaceId(sel, this)
      _addContainerId(sel, this)
      this.editorState.selection = sel
      this.editorState.propagateUpdates()
      return sel
    }

    transaction (fn, info) {
      const editorState = this.editorState
      let tx = this._transaction.tx
      // HACK: setting the state of 'tx' here
      // TODO: find out a way to pass a tx state for the transaction
      // then we could derive this state from the editorState
      let selBefore = editorState.selection
      tx.selection = selBefore
      let change = this._recordChange(fn, info)
      if (change) {
        let selAfter = tx.selection
        this._setSelection(selAfter)
        change.before = { selection: selBefore }
        change.after = { selection: selAfter }
        // console.log('EditorSession.transaction()', change)
        this._commit(change, info)
        editorState.propagateUpdates()
      }
      return change
    }

    undo () {
      let change = super.undo()
      if (change) this._setSelection(change.after.selection)
      this.editorState.propagateUpdates()
    }

    redo () {
      let change = super.redo()
      if (change) this._setSelection(change.after.selection)
      this.editorState.propagateUpdates()
    }

    onUpdate (...args) {
      console.error('DEPRECATED: use EditorState API')
      return this._registerObserver('update', args)
    }

    onPreRender (...args) {
      console.error('DEPRECATED: use EditorState API')
      return this._registerObserver('pre-render', args)
    }

    onRender (...args) {
      if (_shouldDisplayDeprecatedWarning()) {
        console.error('DEPRECATED: use EditorState API')
      }
      return this._registerObserver('render', args)
    }

    onPostRender (...args) {
      console.error('DEPRECATED: use EditorState API')
      return this._registerObserver('post-render', args)
    }

    onPosition (...args) {
      console.error('DEPRECATED: use EditorState API')
      return this._registerObserver('position', args)
    }

    onFinalize (...args) {
      console.error('DEPRECATED: use EditorState API')
      return this._registerObserver('finalize', args)
    }

    on (stage, ...args) {
      if (_shouldDisplayDeprecatedWarning()) {
        console.error("DEPRECATED: use 'editorState.addObserver(...)' instead.")
      }
      return this._registerObserver(stage, args)
    }

    off (observer) {
      if (_shouldDisplayDeprecatedWarning()) {
        console.error("DEPRECATED: use 'editorState.off(...)' instead.")
      }
      this.editorState.removeObserver(observer)
    }

    _onDocumentChange (change, info) {
      this.editorState._setUpdate('document', { change, info })
      this.editorState.hasUnsavedChanges = true
    }

    executeCommand (commandName) {
      this.commandManager.executeCommand(commandName)
    }

    _registerObserver (stage, args) {
      let resource, handler, observer, opts
      if (!isString(args[0])) {
        ([handler, observer, opts] = args)
        resource = '@any'
      } else {
        ([resource, handler, observer, opts] = args)
      }
      let options = { stage }
      if (opts) options[resource] = opts
      this.editorState.addObserver([resource], handler, observer, options)
    }

    _setSelection (sel) {
      const doc = this.getDocument()
      if (!sel) {
        sel = Selection.nullSelection
      } else {
        sel.attach(doc)
      }
      this.editorState.selection = sel
      return sel
    }

    // HACK: Allows to immitate a document change
    _setUpdate (name, update) {
      this.editorState._setUpdate(name, update)
    }

    _transformSelection (change) {
      var oldSelection = this.getSelection()
      var newSelection = operationHelpers.transformSelection(oldSelection, change)
      return newSelection
    }

    _applyRemoteChange (change) {
      // console.log('EditorSession: applying remote change');
      if (change.ops.length > 0) {
        super._applyRemoteChange(change)
        this._setSelection(this._transformSelection(change))
        this.editorState.propagateUpdates()
      }
    }
  }

  return EditorSession
}

function _addSurfaceId (sel, editorSession) {
  if (sel && !sel.isNull() && !sel.surfaceId) {
    // TODO: We could check if the selection is valid within the given surface
    let surface = editorSession.getFocusedSurface()
    if (surface) {
      sel.surfaceId = surface.id
    }
  }
}

function _addContainerId (sel, editorSession) {
  if (sel && !sel.isNull() && sel.surfaceId && !sel.containerId) {
    let surface = editorSession.surfaceManager.getSurface(sel.surfaceId)
    if (surface) {
      let containerId = surface.getContainerId()
      if (containerId) {
        sel.containerId = containerId
      }
    }
  }
}

const _exceptions = [
  /TextPropertyEditor.*substance\.js/,
  /IsolatedNodeComponent.*substance\.js/,
  /IsolatedInlineNodeComponent.*substance\.js/,
  /TextInput.*substance\.js/
]
function _shouldDisplayDeprecatedWarning () {
  let caller = _getCaller(2)
  for (let e of _exceptions) {
    if (e.exec(caller)) return false
  }
  return true
}

function _getCaller (level) {
  try {
    throw new Error()
  } catch (err) {
    let stack = err.stack
    let lines = stack.split(/\n/)
    let line = lines[2 + level]
    return line
  }
}
<commit_msg>Don't allow EditorSession.on() for flow events anymore.<commit_after>// NOTE: Rewriting former EditorSession.
// Now the EditorSession acts only as an interface to an EditorState
// part of the overall Application state
import {
  isPlainObject, Selection, operationHelpers, isString
} from 'substance'

import EditorState from './EditorState'
import SurfaceManager from './SurfaceManager'
import MarkersManager from './MarkersManager'
import GlobalEventHandler from './GlobalEventHandler'
import KeyboardManager from './KeyboardManager'
import CommandManager from './CommandManager'

export default function (DocumentSession) {
  class EditorSession extends DocumentSession {
    constructor (doc, config, contextProvider, initialState = {}) {
      super(doc, config)

      if (!contextProvider) contextProvider = { context: { editorSession: this } }

      this.config = config
      this.contextProvider = contextProvider

      let editorState = new EditorState(Object.assign({
        document: doc,
        selection: Selection.nullSelection,
        selectionState: {},
        focusedSurface: null,
        commandStates: {},
        hasUnsavedChanges: false,
        isBlurred: false,
        overlayId: null
      }, initialState))
      let surfaceManager = new SurfaceManager(editorState)
      let markersManager = new MarkersManager(editorState)
      let globalEventHandler = new GlobalEventHandler(editorState)
      let keyboardManager = new KeyboardManager(config.getKeyboardShortcuts(), (commandName) => {
        return this.executeCommand(commandName)
      }, contextProvider)
      let commandManager = new CommandManager(editorState,
        // update commands when document or selection have changed
        ['document', 'selection'],
        config.getCommands(),
        contextProvider
      )

      this.editorState = editorState
      this.surfaceManager = surfaceManager
      this.markersManager = markersManager
      this.globalEventHandler = globalEventHandler
      this.keyboardManager = keyboardManager
      this.commandManager = commandManager

      doc.on('document:changed', this._onDocumentChange, this)
    }

    dispose () {
      this.getDocument().off(this)
    }

    initialize () {
      // TODO: is this the right place?
      // initial reduce step
      this.commandManager.reduce()
    }

    getConfigurator () {
      return this.config
    }

    getContext () {
      return this.contextProvider.context
    }

    getSelection () {
      return this.editorState.selection
    }

    getSelectionState () {
      return this.editorState.selectionState
    }

    getCommandStates () {
      return this.editorState.commandStates
    }

    getFocusedSurface () {
      return this.editorState.focusedSurface
    }

    isBlurred () {
      return Boolean(this.editorState.isBlurred)
    }

    hasUnsavedChanges () {
      return Boolean(this.editorState.hasUnsavedChanges)
    }

    setSelection (sel) {
      // console.log('EditorSession.setSelection()', sel)
      if (!sel) sel = Selection.nullSelection
      if (sel && isPlainObject(sel)) {
        sel = this.getDocument().createSelection(sel)
      }
      if (sel && !sel.isNull()) {
        if (!sel.surfaceId) {
          let fs = this.getFocusedSurface()
          if (fs) {
            sel.surfaceId = fs.id
          }
        }
      }
      _addSurfaceId(sel, this)
      _addContainerId(sel, this)
      this.editorState.selection = sel
      this.editorState.propagateUpdates()
      return sel
    }

    transaction (fn, info) {
      const editorState = this.editorState
      let tx = this._transaction.tx
      // HACK: setting the state of 'tx' here
      // TODO: find out a way to pass a tx state for the transaction
      // then we could derive this state from the editorState
      let selBefore = editorState.selection
      tx.selection = selBefore
      let change = this._recordChange(fn, info)
      if (change) {
        let selAfter = tx.selection
        this._setSelection(selAfter)
        change.before = { selection: selBefore }
        change.after = { selection: selAfter }
        // console.log('EditorSession.transaction()', change)
        this._commit(change, info)
        editorState.propagateUpdates()
      }
      return change
    }

    undo () {
      let change = super.undo()
      if (change) this._setSelection(change.after.selection)
      this.editorState.propagateUpdates()
    }

    redo () {
      let change = super.redo()
      if (change) this._setSelection(change.after.selection)
      this.editorState.propagateUpdates()
    }

    onUpdate (...args) {
      console.error('DEPRECATED: use EditorState API')
      return this._registerObserver('update', args)
    }

    onPreRender (...args) {
      console.error('DEPRECATED: use EditorState API')
      return this._registerObserver('pre-render', args)
    }

    onRender (...args) {
      if (_shouldDisplayDeprecatedWarning()) {
        console.error('DEPRECATED: use EditorState API')
      }
      return this._registerObserver('render', args)
    }

    onPostRender (...args) {
      console.error('DEPRECATED: use EditorState API')
      return this._registerObserver('post-render', args)
    }

    onPosition (...args) {
      console.error('DEPRECATED: use EditorState API')
      return this._registerObserver('position', args)
    }

    onFinalize (...args) {
      console.error('DEPRECATED: use EditorState API')
      return this._registerObserver('finalize', args)
    }

    _onDocumentChange (change, info) {
      this.editorState._setUpdate('document', { change, info })
      this.editorState.hasUnsavedChanges = true
    }

    executeCommand (commandName) {
      this.commandManager.executeCommand(commandName)
    }

    _registerObserver (stage, args) {
      let resource, handler, observer, opts
      if (!isString(args[0])) {
        ([handler, observer, opts] = args)
        resource = '@any'
      } else {
        ([resource, handler, observer, opts] = args)
      }
      let options = { stage }
      if (opts) options[resource] = opts
      this.editorState.addObserver([resource], handler, observer, options)
    }

    _setSelection (sel) {
      const doc = this.getDocument()
      if (!sel) {
        sel = Selection.nullSelection
      } else {
        sel.attach(doc)
      }
      this.editorState.selection = sel
      return sel
    }

    // HACK: Allows to immitate a document change
    _setUpdate (name, update) {
      this.editorState._setUpdate(name, update)
    }

    _transformSelection (change) {
      var oldSelection = this.getSelection()
      var newSelection = operationHelpers.transformSelection(oldSelection, change)
      return newSelection
    }

    _applyRemoteChange (change) {
      // console.log('EditorSession: applying remote change');
      if (change.ops.length > 0) {
        super._applyRemoteChange(change)
        this._setSelection(this._transformSelection(change))
        this.editorState.propagateUpdates()
      }
    }
  }

  return EditorSession
}

function _addSurfaceId (sel, editorSession) {
  if (sel && !sel.isNull() && !sel.surfaceId) {
    // TODO: We could check if the selection is valid within the given surface
    let surface = editorSession.getFocusedSurface()
    if (surface) {
      sel.surfaceId = surface.id
    }
  }
}

function _addContainerId (sel, editorSession) {
  if (sel && !sel.isNull() && sel.surfaceId && !sel.containerId) {
    let surface = editorSession.surfaceManager.getSurface(sel.surfaceId)
    if (surface) {
      let containerId = surface.getContainerId()
      if (containerId) {
        sel.containerId = containerId
      }
    }
  }
}

const _exceptions = [
  /TextPropertyEditor.*substance\.js/,
  /IsolatedNodeComponent.*substance\.js/,
  /IsolatedInlineNodeComponent.*substance\.js/,
  /TextInput.*substance\.js/
]
function _shouldDisplayDeprecatedWarning () {
  let caller = _getCaller(2)
  for (let e of _exceptions) {
    if (e.exec(caller)) return false
  }
  return true
}

function _getCaller (level) {
  try {
    throw new Error()
  } catch (err) {
    let stack = err.stack
    let lines = stack.split(/\n/)
    let line = lines[2 + level]
    return line
  }
}
<|endoftext|>


<commit_before>import { Meteor } from 'meteor/meteor';

import { InfoItem } from './infoitem';

export class ActionItem extends InfoItem{
    constructor(parentTopic, source) {   // constructs obj from item ID or document
        super(parentTopic, source);

        this._infoItemDoc.itemType = 'actionItem';

        if (this._infoItemDoc.isOpen == undefined) {
            this._infoItemDoc.isOpen = true;
        }
        if (this._infoItemDoc.isNew == undefined) {
            this._infoItemDoc.isNew = true;
        }
        if (this._infoItemDoc.responsible == undefined) {
            this._infoItemDoc.responsible = "";
        }
        if (this._infoItemDoc.priority == undefined) {
            this._infoItemDoc.priority = "";
        }
    }

    // ################### object methods

    invalidateIsNewFlag() {
        this._infoItemDoc.isNew = false;
    }

    isSticky() {
        return this._infoItemDoc.isOpen;
    }

    /**
     * Gets the date of the detail item
     * at the given index.
     *
     * @param index position in the details array (0 if undefined)
     * @returns {boolean|string} false (if date is not given) or date as ISO8601 string.
     */
    getDateFromDetails (index) {
        if (index === undefined) index = 0;
        let details = this._infoItemDoc.details;
        if (details.length > index && details[index].hasOwnProperty("date")) {
            return details[index].date;
        }
        return false;
    }

    /**
     * Gets the text of the detail item
     * at the given index.
     *
     * @param index position in the details array (0 if undefined)
     * @returns {string}
     */
    getTextFromDetails (index) {
        if (index === undefined) index = 0;
        let details = this._infoItemDoc.details;
        if (details.length > 0 && details[index].hasOwnProperty("text")) {
            return details[index].text;
        }
        return "";
    }

    getSubject() {
        return this._infoItemDoc.subject;
    }

    hasResponsibles() {
        return (this._infoItemDoc.responsibles && this._infoItemDoc.responsibles.length);
    }

    getResponsibleRawArray() {
        if (!this.hasResponsibles()) {
            return [];
        }
        return this._infoItemDoc.responsibles;
    }

    // this should only be called from server.
    // because EMails are not propagated to the client!
    getResponsibleEMailArray() {
        if (Meteor.isServer) {
            if (!this.hasResponsibles()) {
                return [];
            }

            let responsibles = this._infoItemDoc.responsibles;
            let mailArray = [];
            for (let i in responsibles) {
                let userEMailFromDB = "";
                let userNameFromDB = "";
                if (responsibles[i].length > 15) {  // maybe DB Id or free text
                    let user = Meteor.users.findOne(responsibles[i]);
                    if (user) {
                        userNameFromDB = user.username;
                        if (user.emails && user.emails.length) {
                            userEMailFromDB = user.emails[0].address;
                        }
                    }
                }
                if (userEMailFromDB) {     // user DB match!
                    mailArray.push(userEMailFromDB);
                } else {
                    let freetextMail = responsibles[i].trim();
                    if (/\S+@\S+\.\S+/.test(freetextMail)) {    // check valid mail anystring@anystring.anystring
                        mailArray.push(freetextMail);
                    } else {
                        console.log("WARNING: Invalid mail address for responsible: >"+freetextMail+"< "+userNameFromDB);
                    }
                }
            }
            return mailArray;
        }
        return [];
    }

    getResponsibleNameString() {
        if (!this.hasResponsibles()) {
            return "";
        }

        let responsibles = this._infoItemDoc.responsibles;
        let responsiblesString = "";
        for (let i in responsibles) {
            let userNameFromDB = "";
            if (responsibles[i].length > 15) {  // maybe DB Id or free text
                let user = Meteor.users.findOne(responsibles[i]);
                if (user) {
                    userNameFromDB = user.username;
                }
            }
            if (userNameFromDB) {     // user DB match!
                responsiblesString += userNameFromDB + ", ";
            } else {
                responsiblesString += responsibles[i] + ", ";
            }
        }
        responsiblesString = responsiblesString.slice(0, -2);   // remove last ", "
        return responsiblesString;
    }

    getPriority() {
        let prio = this._infoItemDoc.priority;
        return (prio) ? prio : '';
    }

    getDuedate() {
        return this._infoItemDoc.duedate;
    }

    toggleState () {    // open/close
        this._infoItemDoc.isOpen = !this._infoItemDoc.isOpen;
    }
}
<commit_msg>Minor bugfix - check if details exist before accessing them<commit_after>import { Meteor } from 'meteor/meteor';

import { InfoItem } from './infoitem';

export class ActionItem extends InfoItem{
    constructor(parentTopic, source) {   // constructs obj from item ID or document
        super(parentTopic, source);

        this._infoItemDoc.itemType = 'actionItem';

        if (this._infoItemDoc.isOpen == undefined) {
            this._infoItemDoc.isOpen = true;
        }
        if (this._infoItemDoc.isNew == undefined) {
            this._infoItemDoc.isNew = true;
        }
        if (this._infoItemDoc.responsible == undefined) {
            this._infoItemDoc.responsible = "";
        }
        if (this._infoItemDoc.priority == undefined) {
            this._infoItemDoc.priority = "";
        }
    }

    // ################### object methods

    invalidateIsNewFlag() {
        this._infoItemDoc.isNew = false;
    }

    isSticky() {
        return this._infoItemDoc.isOpen;
    }

    /**
     * Gets the date of the detail item
     * at the given index.
     *
     * @param index position in the details array (0 if undefined)
     * @returns {boolean|string} false (if date is not given) or date as ISO8601 string.
     */
    getDateFromDetails (index) {
        if (index === undefined) index = 0;
        let details = this._infoItemDoc.details;
        if (details.length > index && details[index].hasOwnProperty("date")) {
            return details[index].date;
        }
        return false;
    }

    /**
     * Gets the text of the detail item
     * at the given index.
     *
     * @param index position in the details array (0 if undefined)
     * @returns {string}
     */
    getTextFromDetails (index) {
        if (index === undefined) index = 0;
        let details = this._infoItemDoc.details;
        if (details && details.length > 0 && details[index].hasOwnProperty("text")) {
            return details[index].text;
        }
        return "";
    }

    getSubject() {
        return this._infoItemDoc.subject;
    }

    hasResponsibles() {
        return (this._infoItemDoc.responsibles && this._infoItemDoc.responsibles.length);
    }

    getResponsibleRawArray() {
        if (!this.hasResponsibles()) {
            return [];
        }
        return this._infoItemDoc.responsibles;
    }

    // this should only be called from server.
    // because EMails are not propagated to the client!
    getResponsibleEMailArray() {
        if (Meteor.isServer) {
            if (!this.hasResponsibles()) {
                return [];
            }

            let responsibles = this._infoItemDoc.responsibles;
            let mailArray = [];
            for (let i in responsibles) {
                let userEMailFromDB = "";
                let userNameFromDB = "";
                if (responsibles[i].length > 15) {  // maybe DB Id or free text
                    let user = Meteor.users.findOne(responsibles[i]);
                    if (user) {
                        userNameFromDB = user.username;
                        if (user.emails && user.emails.length) {
                            userEMailFromDB = user.emails[0].address;
                        }
                    }
                }
                if (userEMailFromDB) {     // user DB match!
                    mailArray.push(userEMailFromDB);
                } else {
                    let freetextMail = responsibles[i].trim();
                    if (/\S+@\S+\.\S+/.test(freetextMail)) {    // check valid mail anystring@anystring.anystring
                        mailArray.push(freetextMail);
                    } else {
                        console.log("WARNING: Invalid mail address for responsible: >"+freetextMail+"< "+userNameFromDB);
                    }
                }
            }
            return mailArray;
        }
        return [];
    }

    getResponsibleNameString() {
        if (!this.hasResponsibles()) {
            return "";
        }

        let responsibles = this._infoItemDoc.responsibles;
        let responsiblesString = "";
        for (let i in responsibles) {
            let userNameFromDB = "";
            if (responsibles[i].length > 15) {  // maybe DB Id or free text
                let user = Meteor.users.findOne(responsibles[i]);
                if (user) {
                    userNameFromDB = user.username;
                }
            }
            if (userNameFromDB) {     // user DB match!
                responsiblesString += userNameFromDB + ", ";
            } else {
                responsiblesString += responsibles[i] + ", ";
            }
        }
        responsiblesString = responsiblesString.slice(0, -2);   // remove last ", "
        return responsiblesString;
    }

    getPriority() {
        let prio = this._infoItemDoc.priority;
        return (prio) ? prio : '';
    }

    getDuedate() {
        return this._infoItemDoc.duedate;
    }

    toggleState () {    // open/close
        this._infoItemDoc.isOpen = !this._infoItemDoc.isOpen;
    }
}
<|endoftext|>