<commit_before>/**
 * This code is mostly from the old Etherpad. Please help us to comment this code.
 * This helps other people to understand this code better and helps them to improve it.
 * TL;DR COMMENTS ON THIS FILE ARE HIGHLY APPRECIATED
 */

/**
 * Copyright 2009 Google Inc.
 *
 * 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.
 */

var chat = require('./chat').chat;

// Dependency fill on init. This exists for `pad.socket` only.
// TODO: bind directly to the socket.
var pad = undefined;
function getSocket() {
  return pad && pad.socket;
}

/** Call this when the document is ready, and a new Ace2Editor() has been created and inited.
    ACE's ready callback does not need to have fired yet.
    "serverVars" are from calling doc.getCollabClientVars() on the server. */
function getCollabClient(ace2editor, serverVars, initialUserInfo, options, _pad)
{
  var editor = ace2editor;
  pad = _pad; // Inject pad to avoid a circular dependency.

  var rev = serverVars.rev;
  var padId = serverVars.padId;
  var globalPadId = serverVars.globalPadId;

  var state = "IDLE";
  var stateMessage;
  var stateMessageSocketId;
  var channelState = "CONNECTING";
  var appLevelDisconnectReason = null;

  var lastCommitTime = 0;
  var initialStartConnectTime = 0;

  var userId = initialUserInfo.userId;
  var socketId;
  //var socket;
  var userSet = {}; // userId -> userInfo
  userSet[userId] = initialUserInfo;

  var reconnectTimes = [];
  var caughtErrors = [];
  var caughtErrorCatchers = [];
  var caughtErrorTimes = [];
  var debugMessages = [];

  tellAceAboutHistoricalAuthors(serverVars.historicalAuthorData);
  tellAceActiveAuthorInfo(initialUserInfo);

  var callbacks = {
    onUserJoin: function()
    {},
    onUserLeave: function()
    {},
    onUpdateUserInfo: function()
    {},
    onChannelStateChange: function()
    {},
    onClientMessage: function()
    {},
    onInternalAction: function()
    {},
    onConnectionTrouble: function()
    {},
    onServerMessage: function()
    {}
  };

  if ($.browser.mozilla)
  {
    // Prevent "escape" from taking effect and canceling a comet connection;
    // doesn't work if focus is on an iframe.
    $(window).bind("keydown", function(evt)
    {
      if (evt.which == 27)
      {
        evt.preventDefault()
      }
    });
  }

  editor.setProperty("userAuthor", userId);
  editor.setBaseAttributedText(serverVars.initialAttributedText, serverVars.apool);
  editor.setUserChangeNotificationCallback(wrapRecordingErrors("handleUserChanges", handleUserChanges));

  function dmesg(str)
  {
    if (typeof window.ajlog == "string") window.ajlog += str + '\n';
    debugMessages.push(str);
  }

  function handleUserChanges()
  {
    if ((!getSocket()) || channelState == "CONNECTING")
    {
      if (channelState == "CONNECTING" && (((+new Date()) - initialStartConnectTime) > 20000))
      {
        setChannelState("DISCONNECTED", "initsocketfail");
      }
      else
      {
        // check again in a bit
        setTimeout(wrapRecordingErrors("setTimeout(handleUserChanges)", handleUserChanges), 1000);
      }
      return;
    }

    var t = (+new Date());

    if (state != "IDLE")
    {
      if (state == "COMMITTING" && (t - lastCommitTime) > 20000)
      {
        // a commit is taking too long
        setChannelState("DISCONNECTED", "slowcommit");
      }
      else if (state == "COMMITTING" && (t - lastCommitTime) > 5000)
      {
        callbacks.onConnectionTrouble("SLOW");
      }
      else
      {
        // run again in a few seconds, to detect a disconnect
        setTimeout(wrapRecordingErrors("setTimeout(handleUserChanges)", handleUserChanges), 3000);
      }
      return;
    }

    var earliestCommit = lastCommitTime + 500;
    if (t < earliestCommit)
    {
      setTimeout(wrapRecordingErrors("setTimeout(handleUserChanges)", handleUserChanges), earliestCommit - t);
      return;
    }

    var sentMessage = false;
    var userChangesData = editor.prepareUserChangeset();
    if (userChangesData.changeset)
    {
      lastCommitTime = t;
      state = "COMMITTING";
      stateMessage = {
        type: "USER_CHANGES",
        baseRev: rev,
        changeset: userChangesData.changeset,
        apool: userChangesData.apool
      };
      stateMessageSocketId = socketId;
      sendMessage(stateMessage);
      sentMessage = true;
      callbacks.onInternalAction("commitPerformed");
    }

    if (sentMessage)
    {
      // run again in a few seconds, to detect a disconnect
      setTimeout(wrapRecordingErrors("setTimeout(handleUserChanges)", handleUserChanges), 3000);
    }
  }

  function getStats()
  {
    var stats = {};

    stats.screen = [$(window).width(), $(window).height(), window.screen.availWidth, window.screen.availHeight, window.screen.width, window.screen.height].join(',');
    stats.ip = serverVars.clientIp;
    stats.useragent = serverVars.clientAgent;

    return stats;
  }

  function setUpSocket()
  {
    //oldSocketId = String(Math.floor(Math.random()*1e12));
    //socketId = String(Math.floor(Math.random()*1e12));
/*socket = new io.Socket();
    socket.connect();*/

    //socket.on('connect', function(){
    hiccupCount = 0;
    setChannelState("CONNECTED");
/*var msg = { type:"CLIENT_READY", roomType:'padpage',
                  roomName:'padpage/'+globalPadId,
                  data: {
                    lastRev:rev,
                    userInfo:userSet[userId],
                    stats: getStats() } };
      if (oldSocketId) {
        msg.data.isReconnectOf = oldSocketId;
        msg.data.isCommitPending = (state == "COMMITTING");
      }
      sendMessage(msg);*/
    doDeferredActions();

    initialStartConnectTime = +new Date();
    // });
/*socket.on('message', function(obj){
      if(window.console)
        console.log(obj);
      handleMessageFromServer(obj);
    });*/

/*var success = false;
    callCatchingErrors("setUpSocket", function() {
      appLevelDisconnectReason = null;

      var oldSocketId = socketId;
      socketId = String(Math.floor(Math.random()*1e12));
      socket = new WebSocket(socketId);
      socket.onmessage = wrapRecordingErrors("socket.onmessage", handleMessageFromServer);
      socket.onclosed = wrapRecordingErrors("socket.onclosed", handleSocketClosed);
      socket.onopen = wrapRecordingErrors("socket.onopen", function() {
        hiccupCount = 0;
        setChannelState("CONNECTED");
        var msg = { type:"CLIENT_READY", roomType:'padpage',
                    roomName:'padpage/'+globalPadId,
                    data: {
                      lastRev:rev,
                      userInfo:userSet[userId],
                      stats: getStats() } };
        if (oldSocketId) {
          msg.data.isReconnectOf = oldSocketId;
          msg.data.isCommitPending = (state == "COMMITTING");
        }
        sendMessage(msg);
        doDeferredActions();
      });
      socket.onhiccup = wrapRecordingErrors("socket.onhiccup", handleCometHiccup);
      socket.onlogmessage = dmesg;
      socket.connect();
      success = true;
    });
    if (success) {
      initialStartConnectTime = +new Date();
    }
    else {
      abandonConnection("initsocketfail");
    }*/
  }

  var hiccupCount = 0;

  function handleCometHiccup(params)
  {
    dmesg("HICCUP (connected:" + ( !! params.connected) + ")");
    var connectedNow = params.connected;
    if (!connectedNow)
    {
      hiccupCount++;
      // skip first "cut off from server" notification
      if (hiccupCount > 1)
      {
        setChannelState("RECONNECTING");
      }
    }
    else
    {
      hiccupCount = 0;
      setChannelState("CONNECTED");
    }
  }

  function sendMessage(msg)
  {
    getSocket().json.send(
    {
      type: "COLLABROOM",
      component: "pad",
      data: msg
    });
  }

  function wrapRecordingErrors(catcher, func)
  {
    return function()
    {
      try
      {
        return func.apply(this, Array.prototype.slice.call(arguments));
      }
      catch (e)
      {
        caughtErrors.push(e);
        caughtErrorCatchers.push(catcher);
        caughtErrorTimes.push(+new Date());
        //console.dir({catcher: catcher, e: e});
        throw e;
      }
    };
  }

  function callCatchingErrors(catcher, func)
  {
    try
    {
      wrapRecordingErrors(catcher, func)();
    }
    catch (e)
    { /*absorb*/
    }
  }

  function handleMessageFromServer(evt)
  {
    if (window.console) console.log(evt);

    if (!getSocket()) return;
    if (!evt.data) return;
    var wrapper = evt;
    if (wrapper.type != "COLLABROOM") return;
    var msg = wrapper.data;
    if (msg.type == "NEW_CHANGES")
    {
      var newRev = msg.newRev;
      var changeset = msg.changeset;
      var author = (msg.author || '');
      var apool = msg.apool;
      if (newRev != (rev + 1))
      {
        dmesg("bad message revision on NEW_CHANGES: " + newRev + " not " + (rev + 1));
        setChannelState("DISCONNECTED", "badmessage_newchanges");
        return;
      }
      rev = newRev;
      editor.applyChangesToBase(changeset, author, apool);
    }
    else if (msg.type == "ACCEPT_COMMIT")
    {
      var newRev = msg.newRev;
      if (newRev != (rev + 1))
      {
        dmesg("bad message revision on ACCEPT_COMMIT: " + newRev + " not " + (rev + 1));
        setChannelState("DISCONNECTED", "badmessage_acceptcommit");
        return;
      }
      rev = newRev;
      editor.applyPreparedChangesetToBase();
      setStateIdle();
      callCatchingErrors("onInternalAction", function()
      {
        callbacks.onInternalAction("commitAcceptedByServer");
      });
      callCatchingErrors("onConnectionTrouble", function()
      {
        callbacks.onConnectionTrouble("OK");
      });
      handleUserChanges();
    }
    else if (msg.type == "NO_COMMIT_PENDING")
    {
      if (state == "COMMITTING")
      {
        // server missed our commit message; abort that commit
        setStateIdle();
        handleUserChanges();
      }
    }
    else if (msg.type == "USER_NEWINFO")
    {
      var userInfo = msg.userInfo;
      var id = userInfo.userId;

      if (userSet[id])
      {
        userSet[id] = userInfo;
        callbacks.onUpdateUserInfo(userInfo);
        dmesgUsers();
      }
      else
      {
        userSet[id] = userInfo;
        callbacks.onUserJoin(userInfo);
        dmesgUsers();
      }
      tellAceActiveAuthorInfo(userInfo);
    }
    else if (msg.type == "USER_LEAVE")
    {
      var userInfo = msg.userInfo;
      var id = userInfo.userId;
      if (userSet[id])
      {
        delete userSet[userInfo.userId];
        fadeAceAuthorInfo(userInfo);
        callbacks.onUserLeave(userInfo);
        dmesgUsers();
      }
    }
    else if (msg.type == "DISCONNECT_REASON")
    {
      appLevelDisconnectReason = msg.reason;
    }
    else if (msg.type == "CLIENT_MESSAGE")
    {
      callbacks.onClientMessage(msg.payload);
    }
    else if (msg.type == "CHAT_MESSAGE")
    {
      chat.addMessage(msg, true);
    }
    else if (msg.type == "SERVER_MESSAGE")
    {
      callbacks.onServerMessage(msg.payload);
    }
  }

  function updateUserInfo(userInfo)
  {
    userInfo.userId = userId;
    userSet[userId] = userInfo;
    tellAceActiveAuthorInfo(userInfo);
    if (!getSocket()) return;
    sendMessage(
    {
      type: "USERINFO_UPDATE",
      userInfo: userInfo
    });
  }

  function tellAceActiveAuthorInfo(userInfo)
  {
    tellAceAuthorInfo(userInfo.userId, userInfo.colorId);
  }

  function tellAceAuthorInfo(userId, colorId, inactive)
  {
    if(typeof colorId == "number")
    {
      colorId = clientVars.colorPalette[colorId];
    }

    var cssColor = colorId;
    if (inactive)
    {
      editor.setAuthorInfo(userId, {
        bgcolor: cssColor,
        fade: 0.5
      });
    }
    else
    {
      editor.setAuthorInfo(userId, {
        bgcolor: cssColor
      });
    }
  }

  function fadeAceAuthorInfo(userInfo)
  {
    tellAceAuthorInfo(userInfo.userId, userInfo.colorId, true);
  }

  function getConnectedUsers()
  {
    return valuesArray(userSet);
  }

  function tellAceAboutHistoricalAuthors(hadata)
  {
    for (var author in hadata)
    {
      var data = hadata[author];
      if (!userSet[author])
      {
        tellAceAuthorInfo(author, data.colorId, true);
      }
    }
  }

  function dmesgUsers()
  {
    //pad.dmesg($.map(getConnectedUsers(), function(u) { return u.userId.slice(-2); }).join(','));
  }

  function setChannelState(newChannelState, moreInfo)
  {
    if (newChannelState != channelState)
    {
      channelState = newChannelState;
      callbacks.onChannelStateChange(channelState, moreInfo);
    }
  }

  function keys(obj)
  {
    var array = [];
    $.each(obj, function(k, v)
    {
      array.push(k);
    });
    return array;
  }

  function valuesArray(obj)
  {
    var array = [];
    $.each(obj, function(k, v)
    {
      array.push(v);
    });
    return array;
  }

  // We need to present a working interface even before the socket
  // is connected for the first time.
  var deferredActions = [];

  function defer(func, tag)
  {
    return function()
    {
      var that = this;
      var args = arguments;

      function action()
      {
        func.apply(that, args);
      }
      action.tag = tag;
      if (channelState == "CONNECTING")
      {
        deferredActions.push(action);
      }
      else
      {
        action();
      }
    }
  }

  function doDeferredActions(tag)
  {
    var newArray = [];
    for (var i = 0; i < deferredActions.length; i++)
    {
      var a = deferredActions[i];
      if ((!tag) || (tag == a.tag))
      {
        a();
      }
      else
      {
        newArray.push(a);
      }
    }
    deferredActions = newArray;
  }

  function sendClientMessage(msg)
  {
    sendMessage(
    {
      type: "CLIENT_MESSAGE",
      payload: msg
    });
  }

  function getCurrentRevisionNumber()
  {
    return rev;
  }

  function getMissedChanges()
  {
    var obj = {};
    obj.userInfo = userSet[userId];
    obj.baseRev = rev;
    if (state == "COMMITTING" && stateMessage)
    {
      obj.committedChangeset = stateMessage.changeset;
      obj.committedChangesetAPool = stateMessage.apool;
      obj.committedChangesetSocketId = stateMessageSocketId;
      editor.applyPreparedChangesetToBase();
    }
    var userChangesData = editor.prepareUserChangeset();
    if (userChangesData.changeset)
    {
      obj.furtherChangeset = userChangesData.changeset;
      obj.furtherChangesetAPool = userChangesData.apool;
    }
    return obj;
  }

  function setStateIdle()
  {
    state = "IDLE";
    callbacks.onInternalAction("newlyIdle");
    schedulePerhapsCallIdleFuncs();
  }

  function callWhenNotCommitting(func)
  {
    idleFuncs.push(func);
    schedulePerhapsCallIdleFuncs();
  }

  var idleFuncs = [];

  function schedulePerhapsCallIdleFuncs()
  {
    setTimeout(function()
    {
      if (state == "IDLE")
      {
        while (idleFuncs.length > 0)
        {
          var f = idleFuncs.shift();
          f();
        }
      }
    }, 0);
  }

  var self = {
    setOnUserJoin: function(cb)
    {
      callbacks.onUserJoin = cb;
    },
    setOnUserLeave: function(cb)
    {
      callbacks.onUserLeave = cb;
    },
    setOnUpdateUserInfo: function(cb)
    {
      callbacks.onUpdateUserInfo = cb;
    },
    setOnChannelStateChange: function(cb)
    {
      callbacks.onChannelStateChange = cb;
    },
    setOnClientMessage: function(cb)
    {
      callbacks.onClientMessage = cb;
    },
    setOnInternalAction: function(cb)
    {
      callbacks.onInternalAction = cb;
    },
    setOnConnectionTrouble: function(cb)
    {
      callbacks.onConnectionTrouble = cb;
    },
    setOnServerMessage: function(cb)
    {
      callbacks.onServerMessage = cb;
    },
    updateUserInfo: defer(updateUserInfo),
    handleMessageFromServer: handleMessageFromServer,
    getConnectedUsers: getConnectedUsers,
    sendClientMessage: sendClientMessage,
    sendMessage: sendMessage,
    getCurrentRevisionNumber: getCurrentRevisionNumber,
    getMissedChanges: getMissedChanges,
    callWhenNotCommitting: callWhenNotCommitting,
    addHistoricalAuthors: tellAceAboutHistoricalAuthors,
    setChannelState: setChannelState
  };

  $(document).ready(setUpSocket);
  return self;
}

function selectElementContents(elem)
{
  if ($.browser.msie)
  {
    var range = document.body.createTextRange();
    range.moveToElementText(elem);
    range.select();
  }
  else
  {
    if (window.getSelection)
    {
      var browserSelection = window.getSelection();
      if (browserSelection)
      {
        var range = document.createRange();
        range.selectNodeContents(elem);
        browserSelection.removeAllRanges();
        browserSelection.addRange(range);
      }
    }
  }
}

exports.getCollabClient = getCollabClient;
exports.selectElementContents = selectElementContents;
<commit_msg>removed unused functions in collab_client<commit_after>/**
 * This code is mostly from the old Etherpad. Please help us to comment this code.
 * This helps other people to understand this code better and helps them to improve it.
 * TL;DR COMMENTS ON THIS FILE ARE HIGHLY APPRECIATED
 */

/**
 * Copyright 2009 Google Inc.
 *
 * 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.
 */

var chat = require('./chat').chat;

// Dependency fill on init. This exists for `pad.socket` only.
// TODO: bind directly to the socket.
var pad = undefined;
function getSocket() {
  return pad && pad.socket;
}

/** Call this when the document is ready, and a new Ace2Editor() has been created and inited.
    ACE's ready callback does not need to have fired yet.
    "serverVars" are from calling doc.getCollabClientVars() on the server. */
function getCollabClient(ace2editor, serverVars, initialUserInfo, options, _pad)
{
  var editor = ace2editor;
  pad = _pad; // Inject pad to avoid a circular dependency.

  var rev = serverVars.rev;
  var padId = serverVars.padId;
  var globalPadId = serverVars.globalPadId;

  var state = "IDLE";
  var stateMessage;
  var stateMessageSocketId;
  var channelState = "CONNECTING";
  var appLevelDisconnectReason = null;

  var lastCommitTime = 0;
  var initialStartConnectTime = 0;

  var userId = initialUserInfo.userId;
  var socketId;
  //var socket;
  var userSet = {}; // userId -> userInfo
  userSet[userId] = initialUserInfo;

  var reconnectTimes = [];
  var caughtErrors = [];
  var caughtErrorCatchers = [];
  var caughtErrorTimes = [];
  var debugMessages = [];

  tellAceAboutHistoricalAuthors(serverVars.historicalAuthorData);
  tellAceActiveAuthorInfo(initialUserInfo);

  var callbacks = {
    onUserJoin: function()
    {},
    onUserLeave: function()
    {},
    onUpdateUserInfo: function()
    {},
    onChannelStateChange: function()
    {},
    onClientMessage: function()
    {},
    onInternalAction: function()
    {},
    onConnectionTrouble: function()
    {},
    onServerMessage: function()
    {}
  };

  if ($.browser.mozilla)
  {
    // Prevent "escape" from taking effect and canceling a comet connection;
    // doesn't work if focus is on an iframe.
    $(window).bind("keydown", function(evt)
    {
      if (evt.which == 27)
      {
        evt.preventDefault()
      }
    });
  }

  editor.setProperty("userAuthor", userId);
  editor.setBaseAttributedText(serverVars.initialAttributedText, serverVars.apool);
  editor.setUserChangeNotificationCallback(wrapRecordingErrors("handleUserChanges", handleUserChanges));

  function dmesg(str)
  {
    if (typeof window.ajlog == "string") window.ajlog += str + '\n';
    debugMessages.push(str);
  }

  function handleUserChanges()
  {
    if ((!getSocket()) || channelState == "CONNECTING")
    {
      if (channelState == "CONNECTING" && (((+new Date()) - initialStartConnectTime) > 20000))
      {
        setChannelState("DISCONNECTED", "initsocketfail");
      }
      else
      {
        // check again in a bit
        setTimeout(wrapRecordingErrors("setTimeout(handleUserChanges)", handleUserChanges), 1000);
      }
      return;
    }

    var t = (+new Date());

    if (state != "IDLE")
    {
      if (state == "COMMITTING" && (t - lastCommitTime) > 20000)
      {
        // a commit is taking too long
        setChannelState("DISCONNECTED", "slowcommit");
      }
      else if (state == "COMMITTING" && (t - lastCommitTime) > 5000)
      {
        callbacks.onConnectionTrouble("SLOW");
      }
      else
      {
        // run again in a few seconds, to detect a disconnect
        setTimeout(wrapRecordingErrors("setTimeout(handleUserChanges)", handleUserChanges), 3000);
      }
      return;
    }

    var earliestCommit = lastCommitTime + 500;
    if (t < earliestCommit)
    {
      setTimeout(wrapRecordingErrors("setTimeout(handleUserChanges)", handleUserChanges), earliestCommit - t);
      return;
    }

    var sentMessage = false;
    var userChangesData = editor.prepareUserChangeset();
    if (userChangesData.changeset)
    {
      lastCommitTime = t;
      state = "COMMITTING";
      stateMessage = {
        type: "USER_CHANGES",
        baseRev: rev,
        changeset: userChangesData.changeset,
        apool: userChangesData.apool
      };
      stateMessageSocketId = socketId;
      sendMessage(stateMessage);
      sentMessage = true;
      callbacks.onInternalAction("commitPerformed");
    }

    if (sentMessage)
    {
      // run again in a few seconds, to detect a disconnect
      setTimeout(wrapRecordingErrors("setTimeout(handleUserChanges)", handleUserChanges), 3000);
    }
  }

  function getStats()
  {
    var stats = {};

    stats.screen = [$(window).width(), $(window).height(), window.screen.availWidth, window.screen.availHeight, window.screen.width, window.screen.height].join(',');
    stats.ip = serverVars.clientIp;
    stats.useragent = serverVars.clientAgent;

    return stats;
  }

  function setUpSocket()
  {
    hiccupCount = 0;
    setChannelState("CONNECTED");
    doDeferredActions();

    initialStartConnectTime = +new Date();
  }

  var hiccupCount = 0;

  function sendMessage(msg)
  {
    getSocket().json.send(
    {
      type: "COLLABROOM",
      component: "pad",
      data: msg
    });
  }

  function wrapRecordingErrors(catcher, func)
  {
    return function()
    {
      try
      {
        return func.apply(this, Array.prototype.slice.call(arguments));
      }
      catch (e)
      {
        caughtErrors.push(e);
        caughtErrorCatchers.push(catcher);
        caughtErrorTimes.push(+new Date());
        //console.dir({catcher: catcher, e: e});
        throw e;
      }
    };
  }

  function callCatchingErrors(catcher, func)
  {
    try
    {
      wrapRecordingErrors(catcher, func)();
    }
    catch (e)
    { /*absorb*/
    }
  }

  function handleMessageFromServer(evt)
  {
    if (window.console) console.log(evt);

    if (!getSocket()) return;
    if (!evt.data) return;
    var wrapper = evt;
    if (wrapper.type != "COLLABROOM") return;
    var msg = wrapper.data;
    if (msg.type == "NEW_CHANGES")
    {
      var newRev = msg.newRev;
      var changeset = msg.changeset;
      var author = (msg.author || '');
      var apool = msg.apool;
      if (newRev != (rev + 1))
      {
        dmesg("bad message revision on NEW_CHANGES: " + newRev + " not " + (rev + 1));
        setChannelState("DISCONNECTED", "badmessage_newchanges");
        return;
      }
      rev = newRev;
      editor.applyChangesToBase(changeset, author, apool);
    }
    else if (msg.type == "ACCEPT_COMMIT")
    {
      var newRev = msg.newRev;
      if (newRev != (rev + 1))
      {
        dmesg("bad message revision on ACCEPT_COMMIT: " + newRev + " not " + (rev + 1));
        setChannelState("DISCONNECTED", "badmessage_acceptcommit");
        return;
      }
      rev = newRev;
      editor.applyPreparedChangesetToBase();
      setStateIdle();
      callCatchingErrors("onInternalAction", function()
      {
        callbacks.onInternalAction("commitAcceptedByServer");
      });
      callCatchingErrors("onConnectionTrouble", function()
      {
        callbacks.onConnectionTrouble("OK");
      });
      handleUserChanges();
    }
    else if (msg.type == "NO_COMMIT_PENDING")
    {
      if (state == "COMMITTING")
      {
        // server missed our commit message; abort that commit
        setStateIdle();
        handleUserChanges();
      }
    }
    else if (msg.type == "USER_NEWINFO")
    {
      var userInfo = msg.userInfo;
      var id = userInfo.userId;

      if (userSet[id])
      {
        userSet[id] = userInfo;
        callbacks.onUpdateUserInfo(userInfo);
        dmesgUsers();
      }
      else
      {
        userSet[id] = userInfo;
        callbacks.onUserJoin(userInfo);
        dmesgUsers();
      }
      tellAceActiveAuthorInfo(userInfo);
    }
    else if (msg.type == "USER_LEAVE")
    {
      var userInfo = msg.userInfo;
      var id = userInfo.userId;
      if (userSet[id])
      {
        delete userSet[userInfo.userId];
        fadeAceAuthorInfo(userInfo);
        callbacks.onUserLeave(userInfo);
        dmesgUsers();
      }
    }
    else if (msg.type == "DISCONNECT_REASON")
    {
      appLevelDisconnectReason = msg.reason;
    }
    else if (msg.type == "CLIENT_MESSAGE")
    {
      callbacks.onClientMessage(msg.payload);
    }
    else if (msg.type == "CHAT_MESSAGE")
    {
      chat.addMessage(msg, true);
    }
    else if (msg.type == "SERVER_MESSAGE")
    {
      callbacks.onServerMessage(msg.payload);
    }
  }

  function updateUserInfo(userInfo)
  {
    userInfo.userId = userId;
    userSet[userId] = userInfo;
    tellAceActiveAuthorInfo(userInfo);
    if (!getSocket()) return;
    sendMessage(
    {
      type: "USERINFO_UPDATE",
      userInfo: userInfo
    });
  }

  function tellAceActiveAuthorInfo(userInfo)
  {
    tellAceAuthorInfo(userInfo.userId, userInfo.colorId);
  }

  function tellAceAuthorInfo(userId, colorId, inactive)
  {
    if(typeof colorId == "number")
    {
      colorId = clientVars.colorPalette[colorId];
    }

    var cssColor = colorId;
    if (inactive)
    {
      editor.setAuthorInfo(userId, {
        bgcolor: cssColor,
        fade: 0.5
      });
    }
    else
    {
      editor.setAuthorInfo(userId, {
        bgcolor: cssColor
      });
    }
  }

  function fadeAceAuthorInfo(userInfo)
  {
    tellAceAuthorInfo(userInfo.userId, userInfo.colorId, true);
  }

  function getConnectedUsers()
  {
    return valuesArray(userSet);
  }

  function tellAceAboutHistoricalAuthors(hadata)
  {
    for (var author in hadata)
    {
      var data = hadata[author];
      if (!userSet[author])
      {
        tellAceAuthorInfo(author, data.colorId, true);
      }
    }
  }

  function dmesgUsers()
  {
    //pad.dmesg($.map(getConnectedUsers(), function(u) { return u.userId.slice(-2); }).join(','));
  }

  function setChannelState(newChannelState, moreInfo)
  {
    if (newChannelState != channelState)
    {
      channelState = newChannelState;
      callbacks.onChannelStateChange(channelState, moreInfo);
    }
  }

  function keys(obj)
  {
    var array = [];
    $.each(obj, function(k, v)
    {
      array.push(k);
    });
    return array;
  }

  function valuesArray(obj)
  {
    var array = [];
    $.each(obj, function(k, v)
    {
      array.push(v);
    });
    return array;
  }

  // We need to present a working interface even before the socket
  // is connected for the first time.
  var deferredActions = [];

  function defer(func, tag)
  {
    return function()
    {
      var that = this;
      var args = arguments;

      function action()
      {
        func.apply(that, args);
      }
      action.tag = tag;
      if (channelState == "CONNECTING")
      {
        deferredActions.push(action);
      }
      else
      {
        action();
      }
    }
  }

  function doDeferredActions(tag)
  {
    var newArray = [];
    for (var i = 0; i < deferredActions.length; i++)
    {
      var a = deferredActions[i];
      if ((!tag) || (tag == a.tag))
      {
        a();
      }
      else
      {
        newArray.push(a);
      }
    }
    deferredActions = newArray;
  }

  function sendClientMessage(msg)
  {
    sendMessage(
    {
      type: "CLIENT_MESSAGE",
      payload: msg
    });
  }

  function getCurrentRevisionNumber()
  {
    return rev;
  }

  function getMissedChanges()
  {
    var obj = {};
    obj.userInfo = userSet[userId];
    obj.baseRev = rev;
    if (state == "COMMITTING" && stateMessage)
    {
      obj.committedChangeset = stateMessage.changeset;
      obj.committedChangesetAPool = stateMessage.apool;
      obj.committedChangesetSocketId = stateMessageSocketId;
      editor.applyPreparedChangesetToBase();
    }
    var userChangesData = editor.prepareUserChangeset();
    if (userChangesData.changeset)
    {
      obj.furtherChangeset = userChangesData.changeset;
      obj.furtherChangesetAPool = userChangesData.apool;
    }
    return obj;
  }

  function setStateIdle()
  {
    state = "IDLE";
    callbacks.onInternalAction("newlyIdle");
    schedulePerhapsCallIdleFuncs();
  }

  function callWhenNotCommitting(func)
  {
    idleFuncs.push(func);
    schedulePerhapsCallIdleFuncs();
  }

  var idleFuncs = [];

  function schedulePerhapsCallIdleFuncs()
  {
    setTimeout(function()
    {
      if (state == "IDLE")
      {
        while (idleFuncs.length > 0)
        {
          var f = idleFuncs.shift();
          f();
        }
      }
    }, 0);
  }

  var self = {
    setOnUserJoin: function(cb)
    {
      callbacks.onUserJoin = cb;
    },
    setOnUserLeave: function(cb)
    {
      callbacks.onUserLeave = cb;
    },
    setOnUpdateUserInfo: function(cb)
    {
      callbacks.onUpdateUserInfo = cb;
    },
    setOnChannelStateChange: function(cb)
    {
      callbacks.onChannelStateChange = cb;
    },
    setOnClientMessage: function(cb)
    {
      callbacks.onClientMessage = cb;
    },
    setOnInternalAction: function(cb)
    {
      callbacks.onInternalAction = cb;
    },
    setOnConnectionTrouble: function(cb)
    {
      callbacks.onConnectionTrouble = cb;
    },
    setOnServerMessage: function(cb)
    {
      callbacks.onServerMessage = cb;
    },
    updateUserInfo: defer(updateUserInfo),
    handleMessageFromServer: handleMessageFromServer,
    getConnectedUsers: getConnectedUsers,
    sendClientMessage: sendClientMessage,
    sendMessage: sendMessage,
    getCurrentRevisionNumber: getCurrentRevisionNumber,
    getMissedChanges: getMissedChanges,
    callWhenNotCommitting: callWhenNotCommitting,
    addHistoricalAuthors: tellAceAboutHistoricalAuthors,
    setChannelState: setChannelState
  };

  $(document).ready(setUpSocket);
  return self;
}

exports.getCollabClient = getCollabClient;
<|endoftext|>


<commit_before>// Specific hash to display the skin variants builder popup
if (window.location.hash.toLowerCase() == "#skinvariantsbuilder") {
  $('#skin-variants').addClass('popup-show');

  $('.skin-variant').change(function() {
    updateSkinVariantsClasses();
  });

  var containers = ['editor', 'background', 'toolbar'];
  var colors = ['super-light', 'light', 'dark', 'super-dark'];

  updateCheckboxFromSkinClasses();
  updateSkinVariantsClasses();

  // add corresponding classes when config change
  function updateSkinVariantsClasses() {
    var domsToUpdate = [
      $('html'),
      $('iframe[name=ace_outer]').contents().find('html'),
      $('iframe[name=ace_outer]').contents().find('iframe[name=ace_inner]').contents().find('html')
    ];
    colors.forEach(function(color) {
      containers.forEach(function(container) {
        domsToUpdate.forEach(function(el) { el.removeClass(color + '-' + container); });
      })
    })

    domsToUpdate.forEach(function(el) { el.removeClass('full-width-editor'); });

    var new_classes = [];
    $('.skin-variant-color').each(function() {
      new_classes.push($(this).val() + "-" + $(this).data('container'));
    })
    if ($('#skin-variant-full-width').is(':checked')) new_classes.push("full-width-editor");

    domsToUpdate.forEach(function(el) { el.addClass(new_classes.join(" ")); });

    $('#skin-variants-result').val('"skinVariants": "' + new_classes.join(" ") + '"');
  }

  // run on init
  function updateCheckboxFromSkinClasses() {
    $('html').attr('class').split(' ').forEach(function(classItem) {
      var container = classItem.split('-').slice(-1);

      var container = classItem.substring(classItem.lastIndexOf("-") + 1, classItem.length);
      if (containers.indexOf(container) > -1) {
        var color = classItem.substring(0, classItem.lastIndexOf("-"));
        $('.skin-variant-color[data-container="' + container + '"').val(color);
      }
    })

    $('#skin-variant-full-width').prop('checked', $('html').hasClass('full-width-editor'));
  }
}<commit_msg>colibris: Fix skin variant builder after introducing nice-select<commit_after>// Specific hash to display the skin variants builder popup
if (window.location.hash.toLowerCase() == "#skinvariantsbuilder") {
  $('#skin-variants').addClass('popup-show');

  $('.skin-variant').change(function() {
    updateSkinVariantsClasses();
  });

  var containers = ['editor', 'background', 'toolbar'];
  var colors = ['super-light', 'light', 'dark', 'super-dark'];

  updateCheckboxFromSkinClasses();
  updateSkinVariantsClasses();

  // add corresponding classes when config change
  function updateSkinVariantsClasses() {
    var domsToUpdate = [
      $('html'),
      $('iframe[name=ace_outer]').contents().find('html'),
      $('iframe[name=ace_outer]').contents().find('iframe[name=ace_inner]').contents().find('html')
    ];
    colors.forEach(function(color) {
      containers.forEach(function(container) {
        domsToUpdate.forEach(function(el) { el.removeClass(color + '-' + container); });
      })
    })

    domsToUpdate.forEach(function(el) { el.removeClass('full-width-editor'); });

    var new_classes = [];
    $('select.skin-variant-color').each(function() {
      new_classes.push($(this).val() + "-" + $(this).data('container'));
    })
    if ($('#skin-variant-full-width').is(':checked')) new_classes.push("full-width-editor");

    domsToUpdate.forEach(function(el) { el.addClass(new_classes.join(" ")); });

    $('#skin-variants-result').val('"skinVariants": "' + new_classes.join(" ") + '"');
  }

  // run on init
  function updateCheckboxFromSkinClasses() {
    $('html').attr('class').split(' ').forEach(function(classItem) {
      var container = classItem.split('-').slice(-1);

      var container = classItem.substring(classItem.lastIndexOf("-") + 1, classItem.length);
      if (containers.indexOf(container) > -1) {
        var color = classItem.substring(0, classItem.lastIndexOf("-"));
        $('.skin-variant-color[data-container="' + container + '"').val(color);
      }
    })

    $('#skin-variant-full-width').prop('checked', $('html').hasClass('full-width-editor'));
  }
}<|endoftext|>


<commit_before>/* eslint-disable import/first, import/no-dynamic-require */

require('../utils/binHelper')

import glob from 'glob'
import path from 'path'

import getConfig from './getConfig'
import { DefaultDocument } from './RootComponents'
import { poolAll } from '../utils/shared'
import exportRoute from './exportRoute'

process.on('message', async payload => {
  try {
    const { config: oldConfig, routes } = payload
    // Get config again
    const config = await getConfig(oldConfig.originalConfig)
    // Use the node version of the app created with webpack
    const Comp = require(glob.sync(path.resolve(config.paths.ASSETS, 'static.*.js'))[0]).default
    // Retrieve the document template
    const DocumentTemplate = config.Document || DefaultDocument

    const tasks = []
    for (let i = 0; i < routes.length; i++) {
      const route = routes[i]
      tasks.push(async () => {
        await exportRoute({
          ...payload,
          config,
          route,
          Comp,
          DocumentTemplate,
        })
        if (process.connected) {
          process.send({ type: 'tick' })
        }
      })
    }
    await poolAll(tasks, Number(config.outputFileRate))
    if (process.connected) {
      process.send({ type: 'done' })
    }
  } catch (err) {
    console.error(err)
    if (process.connected) {
      process.send({ type: 'error', payload: err })
    }
  }
})
<commit_msg>Ensure threads processes are closed regardless of success or not<commit_after>/* eslint-disable import/first, import/no-dynamic-require */

require('../utils/binHelper')

import glob from 'glob'
import path from 'path'

import getConfig from './getConfig'
import { DefaultDocument } from './RootComponents'
import { poolAll } from '../utils/shared'
import exportRoute from './exportRoute'

process.on('message', async payload => {
  try {
    const { config: oldConfig, routes } = payload
    // Get config again
    const config = await getConfig(oldConfig.originalConfig)
    // Use the node version of the app created with webpack
    const Comp = require(glob.sync(path.resolve(config.paths.ASSETS, 'static.*.js'))[0]).default
    // Retrieve the document template
    const DocumentTemplate = config.Document || DefaultDocument

    const tasks = []
    for (let i = 0; i < routes.length; i++) {
      const route = routes[i]
      tasks.push(async () => {
        await exportRoute({
          ...payload,
          config,
          route,
          Comp,
          DocumentTemplate,
        })
        if (process.connected) {
          process.send({ type: 'tick' })
        }
      })
    }
    await poolAll(tasks, Number(config.outputFileRate))
    if (process.connected) {
      process.send({ type: 'done' })
    }
    process.exit()
  } catch (err) {
    console.error(err)
    if (process.connected) {
      process.send({ type: 'error', payload: err })
    }
    process.exit(1)
  }
})
<|endoftext|>


<commit_before>import { CALL_API } from 'redux-api-middleware'

// ------------------------------------
// Constants
// ------------------------------------
export const GET_EQUATIONS = 'wc:equations:get_equations'
export const GET_EQUATIONS_SUCCESS = 'wc:equations:get_equations_success'
export const GET_EQUATIONS_FAIL = 'wc:equations:get_equations_fail'
export const CREATE_EQUATION = 'wc:equations:create_equation'
export const CREATE_EQUATION_SUCCESS = 'wc:equations:create_equation_success'
export const CREATE_EQUATION_FAIL = 'wc:equations:create_equation_fail'
export const GET_EQUATION = 'wc:equations:get_equation'
export const GET_EQUATION_SUCCESS = 'wc:equations:get_equation_success'
export const GET_EQUATION_FAIL = 'wc:equations:get_equation_fail'
export const UPDATE_EQUATION = 'wc:equations:update_equation'
export const UPDATE_EQUATION_SUCCESS = 'wc:equations:update_equation_success'
export const UPDATE_EQUATION_FAIL = 'wc:equations:update_equation_fail'
export const DELETE_EQUATION = 'wc:equation:delete_equation'
export const DELETE_EQUATION_SUCCESS = 'wc:equation:delete_equation_success'
export const DELETE_EQUATION_FAIL = 'wc:equation:delete_equation_fail'
export const UPLOAD_FILE = 'wc:equation:upload_file'
export const UPLOAD_FILE_SUCCESS = 'wc:equation:upload_file_success'
export const UPLOAD_FILE_FAIL = 'wc:equation:upload_file_fail'

// ------------------------------------
// Actions
// ------------------------------------
export function getEquations (filter = null, page = 1, count = 10) {
  return (dispatch, getState) => {
    let endpoint = `/api/equations?filter=${filter}&page=${page}&count=${count}`
    return dispatch({
      [CALL_API]: {
        endpoint,
        method: 'GET',
        headers: {
          'Accept': 'application/json'
        },
        types: [GET_EQUATIONS, GET_EQUATIONS_SUCCESS, GET_EQUATIONS_FAIL]
      }
    })
  }
}

export function createEquation (data) {
  return (dispatch, getState) => {
    return dispatch({
      [CALL_API]: {
        endpoint: '/api/equations',
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(data),
        types: [
          CREATE_EQUATION,
          {
            type: CREATE_EQUATION_SUCCESS,
            meta: {
              done: true,
              transition: {
                success: (prevState, nextStatem, res) => {
                  return { pathname: '/' }
                }
              }
            }
          },
          CREATE_EQUATION_FAIL
        ]
      }
    })
  }
}

export function getEquationsBySearch (by, keyword) {
  return (dispatch, getState) => {
    return dispatch({
      [CALL_API]: {
        endpoint: `/api/search?by=${by}&keyword=${keyword}`,
        method: 'GET',
        headers: {
          'Accept': 'application/json'
        },
        types: [GET_EQUATION, GET_EQUATION_SUCCESS, GET_EQUATION_FAIL]
      }
    })
  }
}

export function updateEquation (data, eqId) {
  return (dispatch, getState) => {
    return dispatch({
      [CALL_API]: {
        endpoint: `/api/equations/${eqId}`,
        method: 'PUT',
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(data),
        types: [UPDATE_EQUATION, UPDATE_EQUATION_SUCCESS, UPDATE_EQUATION_FAIL]
      }
    })
  }
}

export function uploadFile (eqId, data) {
  return (dispatch, getState) => {
    return dispatch({
      [CALL_API]: {
        endpoint: `/api/equation/${eqId}/upload`,
        method: 'POST',
        body: data,
        types: [UPLOAD_FILE, UPLOAD_FILE_SUCCESS, UPLOAD_FILE_FAIL]
      }
    })
  }
}

export function deleteEquation (eqId) {
  return (dispatch, getState) => {
    return dispatch({
      [CALL_API]: {
        endpoint: `/api/equation/${eqId}`,
        method: 'DELETE',
        headers: {
          'Content-Type': 'application/json'
        },
        types: [DELETE_EQUATION, DELETE_EQUATION_SUCCESS, DELETE_EQUATION_FAIL]
      }
    })
  }
}

const emptyErrors = {
  equationCreationErrors: {},
  equationUpdateErrors: {},
  deleteEquationErrors: {},
  uploadFileErrors: {}
}

// ------------------------------------
// Action Handlers
// ------------------------------------
const ACTION_HANDLERS = {
  [GET_EQUATIONS]: (state) => ({
    ...state,
    fetchingEquations: true,
    createSuccess: false,
    updateSuccess: false,
    deleteEquationSuccess: false,
    fetchingEquationSuccess: false,
    fileUploadSuccess: false,
    fetchingEquationsSuccess: false,
    ...emptyErrors
  }),
  [GET_EQUATIONS_SUCCESS]: (state, action) => {
    return {
      ...state,
      fetchingEquations: false,
      fetchingEquationsSuccess: true,
      list: action.payload.data
    }
  },
  [GET_EQUATIONS_FAIL]: (state, action) => ({
    ...state,
    fetchingEquations: false
  }),
  [CREATE_EQUATION]: (state) => ({
    ...state,
    creatingEquation: true,
    createSuccess: false,
    createdEquation: null,
    ...emptyErrors
  }),
  [CREATE_EQUATION_SUCCESS]: (state, action) => {
    return {
      ...state,
      creatingEquation: false,
      createSuccess: true,
      createdEquation: action.payload.data
    }
  },
  [CREATE_EQUATION_FAIL]: (state, action) => ({
    ...state,
    creatingEquation: false,
    createSuccess: false,
    createdEquation: null,
    equationCreationErrors: action.payload.response.errors
  }),
  [GET_EQUATION]: (state) => ({
    ...state,
    fetchingEquationBySearch: true,
    createSuccess: false,
    updateSuccess: false,
    deleteEquationSuccess: false,
    fetchingEquationSuccess: false,
    fileUploadSuccess: false
  }),
  [GET_EQUATION_SUCCESS]: (state, action) => {
    return {
      ...state,
      fetchingEquationBySearch: false,
      fetchingEquationSuccess: true,
      equationsBySearch: action.payload.data
    }
  },
  [GET_EQUATION_FAIL]: (state, action) => ({
    ...state,
    fetchingEquationBySearch: false,
    fetchingEquationSuccess: false
  }),
  [UPDATE_EQUATION]: (state) => ({
    ...state,
    updatingEquation: true,
    updateSuccess: false,
    updatedEquation: null,
    ...emptyErrors
  }),
  [UPDATE_EQUATION_SUCCESS]: (state, action) => {
    return {
      ...state,
      updatingEquation: false,
      updateSuccess: true,
      updatedEquation: action.payload.data
    }
  },
  [UPDATE_EQUATION_FAIL]: (state, action) => ({
    ...state,
    updatingEquation: false,
    updateSuccess: false,
    updatedEquation: null,
    equationUpdateErrors: action.payload.response.errors
  }),
  [DELETE_EQUATION]: (state) => ({
    ...state,
    deletingEquation: true,
    deleteEquationSuccess: false,
    deleteEquationResponse: null,
    deleteEquationErrors: []
  }),
  [DELETE_EQUATION_SUCCESS]: (state, action) => ({
    ...state,
    deletingEquation: false,
    deleteEquationSuccess: true,
    deleteEquationResponse: action.payload.data
  }),
  [DELETE_EQUATION_FAIL]: (state, action) => ({
    ...state,
    deletingEquation: false,
    deleteEquationSuccess: false,
    deleteEquationResponse: null,
    deleteEquationErrors: action.payload.response.errors
  }),
  [UPLOAD_FILE]: state => ({
    ...state,
    uploadingFile: true
  }),
  [UPLOAD_FILE_SUCCESS]: (state, action) => ({
    ...state,
    uploadingFile: false,
    fileUploadSuccess: true,
    fileUploaded: action.payload.data
  }),
  [UPLOAD_FILE_FAIL]: (state, action) => ({
    ...state,
    uploadingFile: false,
    uploadFileErrors: action.payload.response.error
  })
}

// ------------------------------------
// Reducer
// ------------------------------------
const initialState = {
  fetchingEquations: false,
  fetchingEquationsSuccess: false,
  list: {},
  equationCreationErrors: {},
  equationUpdateErrors: {},
  createdEquation: null,
  createSuccess: false,
  creatingEquation: false,
  updatedEquation: null,
  updateSuccess: false,
  updatingEquation: false,
  equationsBySearch: [],
  fetchingEquationBySearch: false,
  fetchingEquationSuccess: false,
  deletingEquation: false,
  deleteEquationSuccess: false,
  deleteEquationResponse: null,
  deleteEquationErrors: {},
  uploadingFile: false,
  fileUploadSuccess: false,
  fileUploaded: [],
  uploadFileErrors: {}
}
export default function equationsReducer (state = initialState, action) {
  const handler = ACTION_HANDLERS[action.type]

  return handler ? handler(state, action) : state
}
<commit_msg>fixed response payload<commit_after>import { CALL_API } from 'redux-api-middleware'

// ------------------------------------
// Constants
// ------------------------------------
export const GET_EQUATIONS = 'wc:equations:get_equations'
export const GET_EQUATIONS_SUCCESS = 'wc:equations:get_equations_success'
export const GET_EQUATIONS_FAIL = 'wc:equations:get_equations_fail'
export const CREATE_EQUATION = 'wc:equations:create_equation'
export const CREATE_EQUATION_SUCCESS = 'wc:equations:create_equation_success'
export const CREATE_EQUATION_FAIL = 'wc:equations:create_equation_fail'
export const GET_EQUATION = 'wc:equations:get_equation'
export const GET_EQUATION_SUCCESS = 'wc:equations:get_equation_success'
export const GET_EQUATION_FAIL = 'wc:equations:get_equation_fail'
export const UPDATE_EQUATION = 'wc:equations:update_equation'
export const UPDATE_EQUATION_SUCCESS = 'wc:equations:update_equation_success'
export const UPDATE_EQUATION_FAIL = 'wc:equations:update_equation_fail'
export const DELETE_EQUATION = 'wc:equation:delete_equation'
export const DELETE_EQUATION_SUCCESS = 'wc:equation:delete_equation_success'
export const DELETE_EQUATION_FAIL = 'wc:equation:delete_equation_fail'
export const UPLOAD_FILE = 'wc:equation:upload_file'
export const UPLOAD_FILE_SUCCESS = 'wc:equation:upload_file_success'
export const UPLOAD_FILE_FAIL = 'wc:equation:upload_file_fail'

// ------------------------------------
// Actions
// ------------------------------------
export function getEquations (filter = null, page = 1, count = 10) {
  return (dispatch, getState) => {
    let endpoint = `/api/equations?filter=${filter}&page=${page}&count=${count}`
    return dispatch({
      [CALL_API]: {
        endpoint,
        method: 'GET',
        headers: {
          'Accept': 'application/json'
        },
        types: [GET_EQUATIONS, GET_EQUATIONS_SUCCESS, GET_EQUATIONS_FAIL]
      }
    })
  }
}

export function createEquation (data) {
  return (dispatch, getState) => {
    return dispatch({
      [CALL_API]: {
        endpoint: '/api/equations',
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(data),
        types: [
          CREATE_EQUATION,
          {
            type: CREATE_EQUATION_SUCCESS,
            meta: {
              done: true,
              transition: {
                success: (prevState, nextStatem, res) => {
                  return { pathname: '/' }
                }
              }
            }
          },
          CREATE_EQUATION_FAIL
        ]
      }
    })
  }
}

export function getEquationsBySearch (by, keyword) {
  return (dispatch, getState) => {
    return dispatch({
      [CALL_API]: {
        endpoint: `/api/search?by=${by}&keyword=${keyword}`,
        method: 'GET',
        headers: {
          'Accept': 'application/json'
        },
        types: [GET_EQUATION, GET_EQUATION_SUCCESS, GET_EQUATION_FAIL]
      }
    })
  }
}

export function updateEquation (data, eqId) {
  return (dispatch, getState) => {
    return dispatch({
      [CALL_API]: {
        endpoint: `/api/equations/${eqId}`,
        method: 'PUT',
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(data),
        types: [UPDATE_EQUATION, UPDATE_EQUATION_SUCCESS, UPDATE_EQUATION_FAIL]
      }
    })
  }
}

export function uploadFile (eqId, data) {
  return (dispatch, getState) => {
    return dispatch({
      [CALL_API]: {
        endpoint: `/api/equation/${eqId}/upload`,
        method: 'POST',
        body: data,
        types: [UPLOAD_FILE, UPLOAD_FILE_SUCCESS, UPLOAD_FILE_FAIL]
      }
    })
  }
}

export function deleteEquation (eqId) {
  return (dispatch, getState) => {
    return dispatch({
      [CALL_API]: {
        endpoint: `/api/equation/${eqId}`,
        method: 'DELETE',
        headers: {
          'Content-Type': 'application/json'
        },
        types: [DELETE_EQUATION, DELETE_EQUATION_SUCCESS, DELETE_EQUATION_FAIL]
      }
    })
  }
}

const emptyErrors = {
  equationCreationErrors: {},
  equationUpdateErrors: {},
  deleteEquationErrors: {},
  uploadFileErrors: {}
}

// ------------------------------------
// Action Handlers
// ------------------------------------
const ACTION_HANDLERS = {
  [GET_EQUATIONS]: (state) => ({
    ...state,
    fetchingEquations: true,
    createSuccess: false,
    updateSuccess: false,
    deleteEquationSuccess: false,
    fetchingEquationSuccess: false,
    fileUploadSuccess: false,
    fetchingEquationsSuccess: false,
    ...emptyErrors
  }),
  [GET_EQUATIONS_SUCCESS]: (state, action) => {
    return {
      ...state,
      fetchingEquations: false,
      fetchingEquationsSuccess: true,
      list: action.payload
    }
  },
  [GET_EQUATIONS_FAIL]: (state, action) => ({
    ...state,
    fetchingEquations: false
  }),
  [CREATE_EQUATION]: (state) => ({
    ...state,
    creatingEquation: true,
    createSuccess: false,
    createdEquation: null,
    ...emptyErrors
  }),
  [CREATE_EQUATION_SUCCESS]: (state, action) => {
    return {
      ...state,
      creatingEquation: false,
      createSuccess: true,
      createdEquation: action.payload
    }
  },
  [CREATE_EQUATION_FAIL]: (state, action) => ({
    ...state,
    creatingEquation: false,
    createSuccess: false,
    createdEquation: null,
    equationCreationErrors: action.payload.response.errors
  }),
  [GET_EQUATION]: (state) => ({
    ...state,
    fetchingEquationBySearch: true,
    createSuccess: false,
    updateSuccess: false,
    deleteEquationSuccess: false,
    fetchingEquationSuccess: false,
    fileUploadSuccess: false
  }),
  [GET_EQUATION_SUCCESS]: (state, action) => {
    return {
      ...state,
      fetchingEquationBySearch: false,
      fetchingEquationSuccess: true,
      equationsBySearch: action.payload
    }
  },
  [GET_EQUATION_FAIL]: (state, action) => ({
    ...state,
    fetchingEquationBySearch: false,
    fetchingEquationSuccess: false
  }),
  [UPDATE_EQUATION]: (state) => ({
    ...state,
    updatingEquation: true,
    updateSuccess: false,
    updatedEquation: null,
    ...emptyErrors
  }),
  [UPDATE_EQUATION_SUCCESS]: (state, action) => {
    return {
      ...state,
      updatingEquation: false,
      updateSuccess: true,
      updatedEquation: action.payload
    }
  },
  [UPDATE_EQUATION_FAIL]: (state, action) => ({
    ...state,
    updatingEquation: false,
    updateSuccess: false,
    updatedEquation: null,
    equationUpdateErrors: action.payload.response.errors
  }),
  [DELETE_EQUATION]: (state) => ({
    ...state,
    deletingEquation: true,
    deleteEquationSuccess: false,
    deleteEquationResponse: null,
    deleteEquationErrors: []
  }),
  [DELETE_EQUATION_SUCCESS]: (state, action) => ({
    ...state,
    deletingEquation: false,
    deleteEquationSuccess: true,
    deleteEquationResponse: action.payload
  }),
  [DELETE_EQUATION_FAIL]: (state, action) => ({
    ...state,
    deletingEquation: false,
    deleteEquationSuccess: false,
    deleteEquationResponse: null,
    deleteEquationErrors: action.payload.response.errors
  }),
  [UPLOAD_FILE]: state => ({
    ...state,
    uploadingFile: true
  }),
  [UPLOAD_FILE_SUCCESS]: (state, action) => ({
    ...state,
    uploadingFile: false,
    fileUploadSuccess: true,
    fileUploaded: action.payload
  }),
  [UPLOAD_FILE_FAIL]: (state, action) => ({
    ...state,
    uploadingFile: false,
    uploadFileErrors: action.payload.response.error
  })
}

// ------------------------------------
// Reducer
// ------------------------------------
const initialState = {
  fetchingEquations: false,
  fetchingEquationsSuccess: false,
  list: {},
  equationCreationErrors: {},
  equationUpdateErrors: {},
  createdEquation: null,
  createSuccess: false,
  creatingEquation: false,
  updatedEquation: null,
  updateSuccess: false,
  updatingEquation: false,
  equationsBySearch: [],
  fetchingEquationBySearch: false,
  fetchingEquationSuccess: false,
  deletingEquation: false,
  deleteEquationSuccess: false,
  deleteEquationResponse: null,
  deleteEquationErrors: {},
  uploadingFile: false,
  fileUploadSuccess: false,
  fileUploaded: [],
  uploadFileErrors: {}
}
export default function equationsReducer (state = initialState, action) {
  const handler = ACTION_HANDLERS[action.type]

  return handler ? handler(state, action) : state
}
<|endoftext|>


<commit_before>///
// Dependencies
///

import React, { Component } from 'react';

import CardsListItem from '../elements/CardsListItem';
import ButtonsList from '../elements/ButtonsList';
import ButtonsListMenu from '../elements/ButtonsListMenu';
import ButtonsListMenuItem from '../elements/ButtonsListMenuItem';
import TabSetsLogo from '../elements/TabSetsLogo';

import * as actions from './actions';

///
// View
///

class TabsetsListItemView extends Component {
	processItem(item) {
		return item.set('href', '/app/tabsets/' + this.props.item.get('id'));
	}

	render() {
		const defaultLogoIcon = (
			<TabSetsLogo />
		);

		return (
			<CardsListItem
				item={this.processItem(this.props.item)}
				defaultLogoIcon={defaultLogoIcon}
				width="2x"
				horizontal
			>
				<ButtonsList>
					<ButtonsListMenu id="tabsetsItemMenu">
						<ButtonsListMenuItem
							icon="pencil"
							title="Edit"
							action={actions.editItemStart(this.props.item.toJS())}
						/>
						<ButtonsListMenuItem
							icon="times"
							title="Delete"
							action={actions.removeItemStart(this.props.item.toJS())}
						/>
					</ButtonsListMenu>
				</ButtonsList>
			</CardsListItem>
		);
	}
}

export default TabsetsListItemView;

<commit_msg>feat/cr41 - Switched edit button action to editItemPrompt<commit_after>///
// Dependencies
///

import React, { Component } from 'react';

import CardsListItem from '../elements/CardsListItem';
import ButtonsList from '../elements/ButtonsList';
import ButtonsListMenu from '../elements/ButtonsListMenu';
import ButtonsListMenuItem from '../elements/ButtonsListMenuItem';
import TabSetsLogo from '../elements/TabSetsLogo';

import * as actions from './actions';

///
// View
///

class TabsetsListItemView extends Component {
	processItem(item) {
		return item.set('href', '/app/tabsets/' + this.props.item.get('id'));
	}

	render() {
		const defaultLogoIcon = (
			<TabSetsLogo />
		);

		return (
			<CardsListItem
				item={this.processItem(this.props.item)}
				defaultLogoIcon={defaultLogoIcon}
				width="2x"
				horizontal
			>
				<ButtonsList>
					<ButtonsListMenu id="tabsetsItemMenu">
						<ButtonsListMenuItem
							icon="pencil"
							title="Edit"
							action={actions.editItemPrompt(this.props.item.toJS())}
						/>
						<ButtonsListMenuItem
							icon="times"
							title="Delete"
							action={actions.removeItemStart(this.props.item.toJS())}
						/>
					</ButtonsListMenu>
				</ButtonsList>
			</CardsListItem>
		);
	}
}

export default TabsetsListItemView;

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016, Rogassi Ent. All rights reserved.
 * Copyrights licensed under the New BSD License.
 * See the accompanying LICENSE file for terms.
 */

'use strict';

var Promise = global.Promise || require('promise');

var React = require('react');
var ReactDOM = require('react-dom');
var ReactDOMServer = require('react-dom/server');

var glob = require('glob');
//var Handlebars = require('handlebars');
var fs = require('graceful-fs');
var path = require('path');

var utils = require('./utils');

module.exports = ExpressReactServerPages;

// -----------------------------------------------------------------------------

function ExpressReactServerPages(config) {
    // Config properties with defaults.
    utils.assign(this, {
        //handlebars     : Handlebars,
        extname: '.rt',
        wrapperExt: '.html',
        layoutsDir: 'views/layouts/',
        partialsDir: 'views/partials/',
        defaultLayout: undefined,
        helpers: undefined,
        compilerOptions: undefined,
    }, config);

    // Express view engine integration point.
    this.engine = this.renderView.bind(this);

    // Normalize `extname`.
    if (this.extname.charAt(0) !== '.') {
        this.extname = '.' + this.extname;
    }

    // Internal caches of compiled and precompiled templates.
    this.compiled = Object.create(null);
    this.precompiled = Object.create(null);

    // Private internal file system cache.
    this._fsCache = Object.create(null);
}

ExpressReactServerPages.prototype.getPartials = function (options) {
    var partialsDirs = Array.isArray(this.partialsDir) ?
            this.partialsDir : [this.partialsDir];

    partialsDirs = partialsDirs.map(function (dir) {
        var dirPath;
        var dirTemplates;
        var dirNamespace;

        // Support `partialsDir` collection with object entries that contain a
        // templates promise and a namespace.
        if (typeof dir === 'string') {
            dirPath = dir;
        } else if (typeof dir === 'object') {
            dirTemplates = dir.templates;
            dirNamespace = dir.namespace;
            dirPath = dir.dir;
        }

        // We must have some path to templates, or templates themselves.
        if (!(dirPath || dirTemplates)) {
            throw new Error('A partials dir must be a string or config object');
        }

        // Make sure we're have a promise for the templates.
        var templatesPromise = dirTemplates ? Promise.resolve(dirTemplates) :
                this.getTemplates(dirPath, options);

        return templatesPromise.then(function (templates) {
            return {
                templates: templates,
                namespace: dirNamespace,
            };
        });
    }, this);

    return Promise.all(partialsDirs).then(function (dirs) {
        var getTemplateName = this._getTemplateName.bind(this);

        return dirs.reduce(function (partials, dir) {
            var templates = dir.templates;
            var namespace = dir.namespace;
            var filePaths = Object.keys(templates);

            filePaths.forEach(function (filePath) {
                var partialName = getTemplateName(filePath, namespace);
                partials[partialName] = templates[filePath];
            });

            return partials;
        }, {});
    }.bind(this));
};

ExpressReactServerPages.prototype.getTemplate = function (filePath, options) {
    filePath = path.resolve(filePath);
    options || (options = {});

    var precompiled = options.precompiled;
    var cache = precompiled ? this.precompiled : this.compiled;
    var template = options.cache && cache[filePath];

    if (template) {
        return template;
    }

    //// Optimistically cache template promise to reduce file system I/O, but
    //// remove from cache if there was a problem.
    //template = cache[filePath] = this._getFile(filePath, { cache: options.cache })
    //    .then(function (file) {
    //    /// WE DO NOT DO THIS
    //    //if (precompiled) {
    //    //    return this._precompileTemplate(file, this.compilerOptions);
    //    //}
    //    return this._compileTemplate(file, this.compilerOptions);
    //}.bind(this));

    template = cache[filePath] = require(filePath.replace(/\.rt.html/ig, '.js').replace(/\.rt/ig, '.js'));

    //return template.catch(function (err) {
    //    delete cache[filePath];
    //    throw err;
    //});
    return template;
};

ExpressReactServerPages.prototype.getTemplates = function (dirPath, options) {
    options || (options = {});
    var cache = options.cache;

    return this._getDir(dirPath, { cache: cache }).then(function (filePaths) {
        var templates = filePaths.map(function (filePath) {
            return this.getTemplate(path.join(dirPath, filePath), options);
        }, this);

        return Promise.all(templates).then(function (templates) {
            return filePaths.reduce(function (hash, filePath, i) {
                hash[filePath] = templates[i];
                return hash;
            }, {});
        });
    }.bind(this));
};

ExpressReactServerPages.prototype.render = function (filePath, context, options) {
    options || (options = {});

    return Promise.all([
        this.getTemplate(filePath, { cache: options.cache }),
        options.partials || this.getPartials({ cache: options.cache }),
    ]).then(function (templates) {
        var template = templates[0];
        var partials = templates[1];
        var helpers = options.helpers || this.helpers;

        // DOES TEMPLATE EXPOSE OVERRIDE SETTINGS ?

        // DOES CURRENT DIRECTORY OVERRIDE SETTINGS ?

        // RECURSE THE DIRECTORY UP UNTIL WE FIND A OVERRIDE SETTINGS ?

        // DO NOTHING IF WE DO NOT FIND ONE AND USE THE OPTIONS SETTING

        context.template = template;
        // Add ExpressHandlebars metadata to the data channel so that it's
        // accessible within the templates and helpers, namespaced under:
        // `@exprsp.*`
        var data = utils.assign({}, options.data, {
            exprsp: utils.assign({}, options, {
                filePath: filePath,
                helpers: helpers,
                partials: partials,
            }),
        });

        return this._renderTemplate(template, context, {
            data: data,
            helpers: helpers,
            partials: partials,
        });
    }.bind(this));
};

ExpressReactServerPages.prototype.renderView = function (viewPath, options, callback) {
    options || (options = {});

    var context = options;

    // Express provides `settings.views` which is the path to the views dir that
    // the developer set on the Express app. When this value exists, it's used
    // to compute the view's name.
    var view;
    var viewsPath = options.settings && options.settings.views;
    if (viewsPath) {
        view = this._getTemplateName(path.relative(viewsPath, viewPath));
    }

    // Merge render-level and instance-level helpers together.
    var helpers = utils.assign({}, this.helpers, options.helpers);

    // Merge render-level and instance-level partials together.
    var partials = Promise.all([
        this.getPartials({ cache: options.cache }),
        Promise.resolve(options.partials),
    ]).then(function (partials) {
        return utils.assign.apply(null, [{}].concat(partials));
    });

    // Pluck-out ExpressHandlebars-specific options and Handlebars-specific
    // rendering options.
    options = {
        cache: options.cache,
        view: view,
        layout: 'layout' in options ? options.layout : this.defaultLayout,

        data: options.data,
        helpers: helpers,
        partials: partials,
    };

    this.render(viewPath, context, options)
        .then(function (body) {
            var layoutPath = this._resolveLayoutPath(options.layout);

            if (layoutPath) {

                var _body = this._getFile(layoutPath, options).then(function (str) {
                    var _template = context.template;
                    var templateOut = [];
                    var last = 0;
                    var rex = /<REACT.*"(.*)".*\/>/gm;
                    var myArray;
                    var fileToEnd = null;
                    while ((myArray = rex.exec(str)) != null) {

                        templateOut.push(myArray.input.substr(last, myArray.index - last));
                        last = myArray.index + myArray[0].length;
                        fileToEnd = myArray.input.substr(last, myArray.input.length - last);
                        var component = null
                        if (myArray[1] == 'body') {
                            component = body;
                        } else if (_template.renderSection != null) {
                            var _comp = React.createElement(_template.renderSection(myArray[1]), reqContext, {});
                            if (_comp != null) {
                                component = ReactDOMServer.renderToStaticMarkup(_comp);
                            }
                        }
                        if (component != null) {
                            templateOut.push(component);
                        }
                    }
                    templateOut.push(fileToEnd);

                    return templateOut.join('');
                });
                //return this.render(
                //    layoutPath,
                //        utils.assign({}, context, { body: body }),
                //        utils.assign({}, options, { layout: undefined })
                //);
                return _body;

            }

            return body;
        }.bind(this))
        .then(utils.passValue(callback))
        .catch(utils.passError(callback));
};

// -- Protected Hooks ----------------------------------------------------------

//ExpressReactServerPages.prototype._compileTemplate = function (template, options) {
//    return this.handlebars.compile(template, options);
//};

//ExpressReactServerPages.prototype._precompileTemplate = function (template, options) {
//    return this.handlebars.precompile(template, options);
//};

ExpressReactServerPages.prototype._renderTemplate = function (template, context, options) {
    return ReactDOMServer.renderToStaticMarkup(React.createElement(template, utils.assign({}, context, options), {}));
};

// -- Private ------------------------------------------------------------------

ExpressReactServerPages.prototype._getDir = function (dirPath, options) {
    dirPath = path.resolve(dirPath);
    options || (options = {});

    var cache = this._fsCache;
    var dir = options.cache && cache[dirPath];

    if (dir) {
        return dir.then(function (dir) {
            return dir.concat();
        });
    }

    var pattern = '**/*' + this.extname;

    // Optimistically cache dir promise to reduce file system I/O, but remove
    // from cache if there was a problem.
    dir = cache[dirPath] = new Promise(function (resolve, reject) {
        glob(pattern, {
            cwd: dirPath,
            follow: true
        }, function (err, dir) {
            if (err) {
                reject(err);
            } else {
                resolve(dir);
            }
        });
    });

    return dir.then(function (dir) {
        return dir.concat();
    }).catch(function (err) {
        delete cache[dirPath];
        throw err;
    });
};

ExpressReactServerPages.prototype._getFile = function (filePath, options) {
    filePath = path.resolve(filePath);
    options || (options = {});

    var cache = this._fsCache;
    var file = options.cache && cache[filePath];

    if (file) {
        return file;
    }

    // Optimistically cache file promise to reduce file system I/O, but remove
    // from cache if there was a problem.
    file = cache[filePath] = new Promise(function (resolve, reject) {
        fs.readFile(filePath, 'utf8', function (err, file) {
            if (err) {
                reject(err);
            } else {
                resolve(file);
            }
        });
    });

    return file.catch(function (err) {
        delete cache[filePath];
        throw err;
    });
};

ExpressReactServerPages.prototype._getTemplateName = function (filePath, namespace) {
    var extRegex = new RegExp(this.extname + '$');
    var name = filePath.replace(extRegex, '');

    if (namespace) {
        name = namespace + '/' + name;
    }

    return name;
};

ExpressReactServerPages.prototype._resolveLayoutPath = function (layoutPath) {
    if (!layoutPath) {
        return null;
    }

    if (!path.extname(layoutPath)) {
        layoutPath += this.wrapperExt;
    }

    return path.resolve(this.layoutsDir, layoutPath);
};
<commit_msg>support for live reload<commit_after>/*
 * Copyright (c) 2016, Rogassi Ent. All rights reserved.
 * Copyrights licensed under the New BSD License.
 * See the accompanying LICENSE file for terms.
 */

'use strict';

var Promise = global.Promise || require('promise');

var React = require('react');
var ReactDOM = require('react-dom');
var ReactDOMServer = require('react-dom/server');

var glob = require('glob');
//var Handlebars = require('handlebars');
var fs = require('graceful-fs');
var path = require('path');

var utils = require('./utils');

module.exports = ExpressReactServerPages;

// -----------------------------------------------------------------------------

function ExpressReactServerPages(config) {
    // Config properties with defaults.
    utils.assign(this, {
        //handlebars     : Handlebars,
        extname: '.rt',
        wrapperExt: '.html',
        layoutsDir: 'views/layouts/',
        partialsDir: 'views/partials/',
        defaultLayout: undefined,
        helpers: undefined,
        compilerOptions: undefined,
    }, config);

    // Express view engine integration point.
    this.engine = this.renderView.bind(this);

    // Normalize `extname`.
    if (this.extname.charAt(0) !== '.') {
        this.extname = '.' + this.extname;
    }

    // Internal caches of compiled and precompiled templates.
    this.compiled = Object.create(null);
    this.precompiled = Object.create(null);

    // Private internal file system cache.
    this._fsCache = Object.create(null);
}

ExpressReactServerPages.prototype.getPartials = function (options) {
    var partialsDirs = Array.isArray(this.partialsDir) ?
            this.partialsDir : [this.partialsDir];

    partialsDirs = partialsDirs.map(function (dir) {
        var dirPath;
        var dirTemplates;
        var dirNamespace;

        // Support `partialsDir` collection with object entries that contain a
        // templates promise and a namespace.
        if (typeof dir === 'string') {
            dirPath = dir;
        } else if (typeof dir === 'object') {
            dirTemplates = dir.templates;
            dirNamespace = dir.namespace;
            dirPath = dir.dir;
        }

        // We must have some path to templates, or templates themselves.
        if (!(dirPath || dirTemplates)) {
            throw new Error('A partials dir must be a string or config object');
        }

        // Make sure we're have a promise for the templates.
        var templatesPromise = dirTemplates ? Promise.resolve(dirTemplates) :
                this.getTemplates(dirPath, options);

        return templatesPromise.then(function (templates) {
            return {
                templates: templates,
                namespace: dirNamespace,
            };
        });
    }, this);

    return Promise.all(partialsDirs).then(function (dirs) {
        var getTemplateName = this._getTemplateName.bind(this);

        return dirs.reduce(function (partials, dir) {
            var templates = dir.templates;
            var namespace = dir.namespace;
            var filePaths = Object.keys(templates);

            filePaths.forEach(function (filePath) {
                var partialName = getTemplateName(filePath, namespace);
                partials[partialName] = templates[filePath];
            });

            return partials;
        }, {});
    }.bind(this));
};

ExpressReactServerPages.prototype.getTemplate = function (filePath, options) {
    filePath = path.resolve(filePath);
    options || (options = {});

    var precompiled = options.precompiled;
    var cache = precompiled ? this.precompiled : this.compiled;
    var template = options.cache && cache[filePath];

    if (template) {
        return template;
    }

    //// Optimistically cache template promise to reduce file system I/O, but
    //// remove from cache if there was a problem.
    //template = cache[filePath] = this._getFile(filePath, { cache: options.cache })
    //    .then(function (file) {
    //    /// WE DO NOT DO THIS
    //    //if (precompiled) {
    //    //    return this._precompileTemplate(file, this.compilerOptions);
    //    //}
    //    return this._compileTemplate(file, this.compilerOptions);
    //}.bind(this));

    template = cache[filePath] = require(filePath.replace(/\.rt.html/ig, '.js').replace(/\.rt/ig, '.js'));

    /// THIS IS PRETTY DIRTY
    if (!options.cache) {
        delete cache[filePath]
        delete require.cache[filePath];
        delete require.cache[filePath.replace(/\.js/, '-rt.js')];
    }

    //return template.catch(function (err) {
    //    delete cache[filePath];
    //    throw err;
    //});
    return template;
};

ExpressReactServerPages.prototype.getTemplates = function (dirPath, options) {
    options || (options = {});
    var cache = options.cache;

    return this._getDir(dirPath, { cache: cache }).then(function (filePaths) {
        var templates = filePaths.map(function (filePath) {
            return this.getTemplate(path.join(dirPath, filePath), options);
        }, this);

        return Promise.all(templates).then(function (templates) {
            return filePaths.reduce(function (hash, filePath, i) {
                hash[filePath] = templates[i];
                return hash;
            }, {});
        });
    }.bind(this));
};

ExpressReactServerPages.prototype.render = function (filePath, context, options) {
    options || (options = {});

    return Promise.all([
        this.getTemplate(filePath, { cache: options.cache }),
        options.partials || this.getPartials({ cache: options.cache }),
    ]).then(function (templates) {
        var template = templates[0];
        var partials = templates[1];
        var helpers = options.helpers || this.helpers;

        // DOES TEMPLATE EXPOSE OVERRIDE SETTINGS ?

        // DOES CURRENT DIRECTORY OVERRIDE SETTINGS ?

        // RECURSE THE DIRECTORY UP UNTIL WE FIND A OVERRIDE SETTINGS ?

        // DO NOTHING IF WE DO NOT FIND ONE AND USE THE OPTIONS SETTING

        context.template = template;
        // Add ExpressHandlebars metadata to the data channel so that it's
        // accessible within the templates and helpers, namespaced under:
        // `@exprsp.*`
        var data = utils.assign({}, options.data, {
            exprsp: utils.assign({}, options, {
                filePath: filePath,
                helpers: helpers,
                partials: partials,
            }),
        });

        return this._renderTemplate(template, context, {
            data: data,
            helpers: helpers,
            partials: partials,
        });
    }.bind(this));
};

ExpressReactServerPages.prototype.renderView = function (viewPath, options, callback) {
    options || (options = {});

    var context = options;

    // Express provides `settings.views` which is the path to the views dir that
    // the developer set on the Express app. When this value exists, it's used
    // to compute the view's name.
    var view;
    var viewsPath = options.settings && options.settings.views;
    if (viewsPath) {
        view = this._getTemplateName(path.relative(viewsPath, viewPath));
    }

    // Merge render-level and instance-level helpers together.
    var helpers = utils.assign({}, this.helpers, options.helpers);

    // Merge render-level and instance-level partials together.
    var partials = Promise.all([
        this.getPartials({ cache: options.cache }),
        Promise.resolve(options.partials),
    ]).then(function (partials) {
        return utils.assign.apply(null, [{}].concat(partials));
    });

    // Pluck-out ExpressHandlebars-specific options and Handlebars-specific
    // rendering options.
    options = {
        cache: options.cache,
        view: view,
        layout: 'layout' in options ? options.layout : this.defaultLayout,

        data: options.data,
        helpers: helpers,
        partials: partials,
    };

    this.render(viewPath, context, options)
        .then(function (body) {
            var layoutPath = this._resolveLayoutPath(options.layout);

            if (layoutPath) {

                var _body = this._getFile(layoutPath, options).then(function (str) {
                    var _template = context.template;
                    var templateOut = [];
                    var last = 0;
                    var rex = /<REACT.*"(.*)".*\/>/gm;
                    var myArray;
                    var fileToEnd = null;
                    while ((myArray = rex.exec(str)) != null) {

                        templateOut.push(myArray.input.substr(last, myArray.index - last));
                        last = myArray.index + myArray[0].length;
                        fileToEnd = myArray.input.substr(last, myArray.input.length - last);
                        var component = null
                        if (myArray[1] == 'body') {
                            component = body;
                        } else if (_template.renderSection != null) {
                            var _comp = React.createElement(_template.renderSection(myArray[1]), reqContext, {});
                            if (_comp != null) {
                                component = ReactDOMServer.renderToStaticMarkup(_comp);
                            }
                        }
                        if (component != null) {
                            templateOut.push(component);
                        }
                    }
                    templateOut.push(fileToEnd);

                    return templateOut.join('');
                });
                //return this.render(
                //    layoutPath,
                //        utils.assign({}, context, { body: body }),
                //        utils.assign({}, options, { layout: undefined })
                //);
                return _body;

            }

            return body;
        }.bind(this))
        .then(utils.passValue(callback))
        .catch(utils.passError(callback));
};

// -- Protected Hooks ----------------------------------------------------------

//ExpressReactServerPages.prototype._compileTemplate = function (template, options) {
//    return this.handlebars.compile(template, options);
//};

//ExpressReactServerPages.prototype._precompileTemplate = function (template, options) {
//    return this.handlebars.precompile(template, options);
//};

ExpressReactServerPages.prototype._renderTemplate = function (template, context, options) {
    return ReactDOMServer.renderToStaticMarkup(React.createElement(template, utils.assign({}, context, options), {}));
};

// -- Private ------------------------------------------------------------------

ExpressReactServerPages.prototype._getDir = function (dirPath, options) {
    dirPath = path.resolve(dirPath);
    options || (options = {});

    var cache = this._fsCache;
    var dir = options.cache && cache[dirPath];

    if (dir) {
        return dir.then(function (dir) {
            return dir.concat();
        });
    }

    var pattern = '**/*' + this.extname;

    // Optimistically cache dir promise to reduce file system I/O, but remove
    // from cache if there was a problem.
    dir = cache[dirPath] = new Promise(function (resolve, reject) {
        glob(pattern, {
            cwd: dirPath,
            follow: true
        }, function (err, dir) {
            if (err) {
                reject(err);
            } else {
                resolve(dir);
            }
        });
    });

    return dir.then(function (dir) {
        return dir.concat();
    }).catch(function (err) {
        delete cache[dirPath];
        throw err;
    });
};

ExpressReactServerPages.prototype._getFile = function (filePath, options) {
    filePath = path.resolve(filePath);
    options || (options = {});

    var cache = this._fsCache;
    var file = options.cache && cache[filePath];

    if (file) {
        return file;
    }

    // Optimistically cache file promise to reduce file system I/O, but remove
    // from cache if there was a problem.
    file = cache[filePath] = new Promise(function (resolve, reject) {
        fs.readFile(filePath, 'utf8', function (err, file) {
            if (err) {
                reject(err);
            } else {
                resolve(file);
            }
        });
    });

    return file.catch(function (err) {
        delete cache[filePath];
        throw err;
    });
};

ExpressReactServerPages.prototype._getTemplateName = function (filePath, namespace) {
    var extRegex = new RegExp(this.extname + '$');
    var name = filePath.replace(extRegex, '');

    if (namespace) {
        name = namespace + '/' + name;
    }

    return name;
};

ExpressReactServerPages.prototype._resolveLayoutPath = function (layoutPath) {
    if (!layoutPath) {
        return null;
    }

    if (!path.extname(layoutPath)) {
        layoutPath += this.wrapperExt;
    }

    return path.resolve(this.layoutsDir, layoutPath);
};
<|endoftext|>


<commit_before>import Matrix2D from "../Matrix2D";
import transformParser from "./transform";

const pooledMatrix = new Matrix2D();

function transformToMatrix(props, transform) {
    pooledMatrix.reset();
    appendTransform(props);

    if (transform) {
        appendTransform(transform);
    }

    return pooledMatrix.toArray();
}

function appendTransform(transform) {
    if (transform) {
        if (typeof transform === "string") {
            try {
                const [a, c, tx, b, d, ty] = transformParser.parse(transform);
                pooledMatrix.append(a, b, c, d, tx, ty);
            } catch (e) {
                console.error(e);
            }
        } else {
            pooledMatrix.appendTransform(
                transform.x + transform.originX,
                transform.y + transform.originY,
                transform.scaleX,
                transform.scaleY,
                transform.rotation,
                transform.skewX,
                transform.skewY,
                transform.originX,
                transform.originY,
            );
        }
    }
}

function universal2axis(universal, axisX, axisY, defaultValue) {
    let coords = [];
    let x;
    let y;
    if (typeof universal === "string") {
        coords = universal.split(/\s*,\s*/);
        if (coords.length === 2) {
            x = +coords[0];
            y = +coords[1];
        } else if (coords.length === 1) {
            x = y = +coords[0];
        }
    } else if (typeof universal === "number") {
        x = y = universal;
    }

    axisX = +axisX;
    if (!isNaN(axisX)) {
        x = axisX;
    }

    axisY = +axisY;
    if (!isNaN(axisY)) {
        y = axisY;
    }

    return [x || defaultValue || 0, y || defaultValue || 0];
}

export function props2transform(props) {
    if (props && typeof props === "string") {
        return props;
    }
    const [originX, originY] = universal2axis(
        props.origin,
        props.originX,
        props.originY,
    );
    const [scaleX, scaleY] = universal2axis(
        props.scale,
        props.scaleX,
        props.scaleY,
        1,
    );
    const [skewX, skewY] = universal2axis(props.skew, props.skewX, props.skewY);
    const [translateX, translateY] = universal2axis(
        props.translate,
        props.translateX === undefined || props.translateX === null
            ? props.x || 0
            : props.translateX,
        props.translateY === undefined || props.translateY === null
            ? props.y || 0
            : props.translateY,
    );

    return {
        rotation: +props.rotation || 0,
        scaleX: scaleX,
        scaleY: scaleY,
        originX: originX,
        originY: originY,
        skewX: skewX,
        skewY: skewY,
        x: translateX,
        y: translateY,
    };
}

export default function(props) {
    return transformToMatrix(
        props2transform(props),
        props.transform ? props2transform(props.transform) : null,
    );
}
<commit_msg>Use const where possible<commit_after>import Matrix2D from "../Matrix2D";
import transformParser from "./transform";

const pooledMatrix = new Matrix2D();

function transformToMatrix(props, transform) {
    pooledMatrix.reset();
    appendTransform(props);

    if (transform) {
        appendTransform(transform);
    }

    return pooledMatrix.toArray();
}

function appendTransform(transform) {
    if (transform) {
        if (typeof transform === "string") {
            try {
                const [a, c, tx, b, d, ty] = transformParser.parse(transform);
                pooledMatrix.append(a, b, c, d, tx, ty);
            } catch (e) {
                console.error(e);
            }
        } else {
            pooledMatrix.appendTransform(
                transform.x + transform.originX,
                transform.y + transform.originY,
                transform.scaleX,
                transform.scaleY,
                transform.rotation,
                transform.skewX,
                transform.skewY,
                transform.originX,
                transform.originY,
            );
        }
    }
}

function universal2axis(universal, axisX, axisY, defaultValue) {
    let x;
    let y;
    if (typeof universal === "string") {
        const coords = universal.split(/\s*,\s*/);
        if (coords.length === 2) {
            x = +coords[0];
            y = +coords[1];
        } else if (coords.length === 1) {
            x = y = +coords[0];
        }
    } else if (typeof universal === "number") {
        x = y = universal;
    }

    axisX = +axisX;
    if (!isNaN(axisX)) {
        x = axisX;
    }

    axisY = +axisY;
    if (!isNaN(axisY)) {
        y = axisY;
    }

    return [x || defaultValue || 0, y || defaultValue || 0];
}

export function props2transform(props) {
    if (props && typeof props === "string") {
        return props;
    }
    const [originX, originY] = universal2axis(
        props.origin,
        props.originX,
        props.originY,
    );
    const [scaleX, scaleY] = universal2axis(
        props.scale,
        props.scaleX,
        props.scaleY,
        1,
    );
    const [skewX, skewY] = universal2axis(props.skew, props.skewX, props.skewY);
    const [translateX, translateY] = universal2axis(
        props.translate,
        props.translateX === undefined || props.translateX === null
            ? props.x || 0
            : props.translateX,
        props.translateY === undefined || props.translateY === null
            ? props.y || 0
            : props.translateY,
    );

    return {
        rotation: +props.rotation || 0,
        scaleX: scaleX,
        scaleY: scaleY,
        originX: originX,
        originY: originY,
        skewX: skewX,
        skewY: skewY,
        x: translateX,
        y: translateY,
    };
}

export default function(props) {
    return transformToMatrix(
        props2transform(props),
        props.transform ? props2transform(props.transform) : null,
    );
}
<|endoftext|>


<commit_before>'use babel'
import axios from 'axios'
import path from 'path'
import url from 'url'
import validUrl from 'valid-url'
import fs from 'fs'

async function handleGithubCall(fullpath, rootPath, path, fileRoot) {
    console.log('%c Handling github import...', 'background: rgba(36, 194, 203, 0.3); color: #EF525B', new Date(Date.now()).toString());
    return await axios({
        method: 'get',
        url: 'https://api.github.com/repos/' + rootPath + '/contents/' + path,
        responseType: 'json'
    }).then(function(response) {
        if('content' in response.data) {
            const buf = Buffer.from(response.data.content, 'base64');
            fileRoot = fullpath.substring(0, fullpath.lastIndexOf("/"));
            fileRoot = fileRoot + '/';
            const resp = { content: buf.toString('UTF-8'), fileRoot };
            return resp;
        } else {
            throw 'Content not received!';
        }
    })
}
async function handleSwarmImport() {
    console.log('Handling swarm import');
}
async function handleIPFS() {
    console.log('Handling ipfs import');
    return ['Handling ipfs import'];
}
async function handleLocalImport(path, filename, fileRoot) {
    console.log('%c Handling local import...', 'background: rgba(36, 194, 203, 0.3); color: #EF525B', new Date(Date.now()).toString());
    const o = { encoding: 'UTF-8' };
    if(path) {
        fileRoot = fileRoot + path;
    }
    const content = fs.readFileSync(fileRoot + filename, o);
    const response = { content, fileRoot };
    return response;
}
async function getHandlers() {
    return [
        { type: 'local', match: /^(?!https?:\/\/)?(?!www.)?(?!github.com)?(\.\.|\.)*?(\/*[\w+/]*\/)*?(\w+.sol)/g, handle: async (match, fileRoot) => { return await handleLocalImport(match[2], match[3], fileRoot) } },
        { type: 'github', match: /^(https?:\/\/)?(www.)?github.com\/([^/]*\/[^/]*)\/(.*)/g, handle: async (match, fileRoot) => { return await handleGithubCall(match[0], match[3], match[4], fileRoot) } },
        { type: 'swarm', match: /^(bzz[ri]?:\/\/?(.*))$/, handle: (match) => { handleSwarmImport(match[1], match[2]) } },
        { type: 'ipfs', match: /^(ipfs:\/\/?.+)/, handle: (match) => { handleIPFS(match[1]) } }
    ];
}
async function resolveImports(fileRoot, sourcePath) {
    console.log('%c Resolving imports', 'background: rgba(36, 194, 203, 0.3); color: #EF525B', new Date(Date.now()).toString());
    const handlers = await getHandlers();
    let response = {};
    for(const handler of handlers) {
        try {
            // here we are trying to find type of import path github/swarm/ipfs/local
            const match = handler.match.exec(sourcePath);
            if(match) {
                response = await handler.handle(match, fileRoot);
                break;
            }
        } catch(e) {
            throw e;
        }
    }
    return response;
}
export async function combineSource(fileRoot, source) {
    console.log("%c Combining source...", 'background: rgba(36, 194, 203, 0.3); color: #EF525B', new Date(Date.now()).toString());
    let fn, iline, ir, subSource;
    var matches = [];
    ir = /import\ [\'\"](.+)[\'\"]\;/g;
    let match = null;
    while(match = ir.exec(source)) {
        matches.push(match);
    }
    for(let match of matches) {
        console.log("%c Matches found...", 'background: rgba(36, 194, 203, 0.3); color: #EF525B', new Date(Date.now()).toString());
        iline = match[0];
        if(validUrl.isUri(fileRoot)) {
            fn = url.resolve(fileRoot, match[1]);
        } else {
            fn = match[1];
        }
        const response = await resolveImports(fileRoot, fn);
        subSource = response.content;
        match.source = await combineSource(response.fileRoot, subSource);
        // replace source import line with actual content
        if(match.source) {
            console.log("%c Replacing source...", 'background: rgba(36, 194, 203, 0.3); color: #EF525B', new Date(Date.now()).toString());
            source = source.replace(iline, match.source);
        }
    }
    return source;
}
<commit_msg>handle / for no path<commit_after>'use babel'
import axios from 'axios'
import path from 'path'
import url from 'url'
import validUrl from 'valid-url'
import fs from 'fs'

async function handleGithubCall(fullpath, rootPath, path, fileRoot) {
    console.log('%c Handling github import...', 'background: rgba(36, 194, 203, 0.3); color: #EF525B', new Date(Date.now()).toString());
    return await axios({
        method: 'get',
        url: 'https://api.github.com/repos/' + rootPath + '/contents/' + path,
        responseType: 'json'
    }).then(function(response) {
        if('content' in response.data) {
            const buf = Buffer.from(response.data.content, 'base64');
            fileRoot = fullpath.substring(0, fullpath.lastIndexOf("/"));
            fileRoot = fileRoot + '/';
            const resp = { content: buf.toString('UTF-8'), fileRoot };
            return resp;
        } else {
            throw 'Content not received!';
        }
    })
}
async function handleSwarmImport() {
    console.log('Handling swarm import');
}
async function handleIPFS() {
    console.log('Handling ipfs import');
    return ['Handling ipfs import'];
}
async function handleLocalImport(path, filename, fileRoot) {
    console.log('%c Handling local import...', 'background: rgba(36, 194, 203, 0.3); color: #EF525B', new Date(Date.now()).toString());
    const o = { encoding: 'UTF-8' };
    if(path) {
        fileRoot = fileRoot + path;
    } else {
        fileRoot = fileRoot + '/';
    }
    const content = fs.readFileSync(fileRoot + filename, o);
    const response = { content, fileRoot };
    return response;
}
async function getHandlers() {
    return [
        { type: 'local', match: /^(?!https?:\/\/)?(?!www.)?(?!github.com)?(\.\.|\.)*?(\/*[\w+/]*\/)*?(\w+.sol)/g, handle: async (match, fileRoot) => { return await handleLocalImport(match[2], match[3], fileRoot) } },
        { type: 'github', match: /^(https?:\/\/)?(www.)?github.com\/([^/]*\/[^/]*)\/(.*)/g, handle: async (match, fileRoot) => { return await handleGithubCall(match[0], match[3], match[4], fileRoot) } },
        { type: 'swarm', match: /^(bzz[ri]?:\/\/?(.*))$/, handle: (match) => { handleSwarmImport(match[1], match[2]) } },
        { type: 'ipfs', match: /^(ipfs:\/\/?.+)/, handle: (match) => { handleIPFS(match[1]) } }
    ];
}
async function resolveImports(fileRoot, sourcePath) {
    console.log('%c Resolving imports', 'background: rgba(36, 194, 203, 0.3); color: #EF525B', new Date(Date.now()).toString());
    const handlers = await getHandlers();
    let response = {};
    for(const handler of handlers) {
        try {
            // here we are trying to find type of import path github/swarm/ipfs/local
            const match = handler.match.exec(sourcePath);
            if(match) {
                response = await handler.handle(match, fileRoot);
                break;
            }
        } catch(e) {
            throw e;
        }
    }
    return response;
}
export async function combineSource(fileRoot, source) {
    console.log("%c Combining source...", 'background: rgba(36, 194, 203, 0.3); color: #EF525B', new Date(Date.now()).toString());
    let fn, iline, ir, subSource;
    var matches = [];
    ir = /import\ [\'\"](.+)[\'\"]\;/g;
    let match = null;
    while(match = ir.exec(source)) {
        matches.push(match);
    }
    for(let match of matches) {
        console.log("%c Matches found...", 'background: rgba(36, 194, 203, 0.3); color: #EF525B', new Date(Date.now()).toString());
        iline = match[0];
        if(validUrl.isUri(fileRoot)) {
            fn = url.resolve(fileRoot, match[1]);
        } else {
            fn = match[1];
        }
        const response = await resolveImports(fileRoot, fn);
        subSource = response.content;
        match.source = await combineSource(response.fileRoot, subSource);
        // replace source import line with actual content
        if(match.source) {
            console.log("%c Replacing source...", 'background: rgba(36, 194, 203, 0.3); color: #EF525B', new Date(Date.now()).toString());
            source = source.replace(iline, match.source);
        }
    }
    return source;
}
<|endoftext|>