<commit_before>

$(function(){

  function ab2str(buf) {
    return String.fromCharCode.apply(null, new Uint16Array(buf));
  }
  function str2ab(str) {
    var buf = new ArrayBuffer(str.length*2); // 2 bytes for each char
    var bufView = new Uint16Array(buf);
    for (var i=0, strLen=str.length; i<strLen; i++) {
      bufView[i] = str.charCodeAt(i);
    }
    return buf;
  }

  function sendSign(signMsg){
    $.ajax({
      type: "POST",
      url:window.location,
			data:"'" + JSON.stringify(signMsg) + "'",
			dataType: 'json',
			contentType: 'application/json',
			charset:'UTF-8',
			success: function(data) {
			  console.log(data);
			}
    });

  }
  function signToken(privateKey) {
    var token = localStorage.getItem('swc.login.token');
    var abToken = str2ab(token);
    window.crypto.subtle.sign(
    {
        name: "RSASSA-PKCS1-v1_5",
    },
    privateKey, //from generateKey or importKey above
    abToken //ArrayBuffer of data you want to sign
    )
    .then(function(signature){
      //returns an ArrayBuffer containing the signature
      //console.log(signature);
      var jsonSign = {'token':token,'signature':ab2str(new Uint8Array(signature))};
      //console.log(JSON.stringify(jsonSign));
      sendSign(jsonSign)
    })
    .catch(function(err){
      console.error(err);
    });
  }
  function sendPublicKey(keydata){
    $.ajax({
      type: "POST",
      url:window.location,
			data:"'" + JSON.stringify(keydata) + "'",
			dataType: 'json',
			contentType: 'application/json',
			charset:'UTF-8',
			success: function(data) {
			  console.log(data);
			  if (data && data['token']) {
			    localStorage.setItem('swc.login.token',data['token']);
			    globalToken = data['token'];
			    signToken();
			  }
			}
    });
  }

  var savePublicKey = function(key) {
    window.crypto.subtle.exportKey(
      "spki", //can be "jwk" (public or private), "spki" (public only), or "pkcs8" (private only)
      key //can be a publicKey or privateKey, as long as extractable was true
      )
      .then(function(keydata){
        //returns the exported key data
        console.log(keydata);
        var name= 'swc.login.publicKey';
        localStorage.setItem(name,JSON.stringify(keydata));
        sendPublicKey(keydata);
      })
      .catch(function(err){
        console.error(err);
      });
  }
  var savePrivateKey = function(key) {
    window.crypto.subtle.exportKey(
      "jwk", //can be "jwk" (public or private), "spki" (public only), or "pkcs8" (private only)
      key //can be a publicKey or privateKey, as long as extractable was true
      )
      .then(function(keydata){
        //returns the exported key data
        //console.log(keydata);
        var name= 'swc.login.privateKey';
        localStorage.setItem(name,JSON.stringify(keydata));
      })
      .catch(function(err){
        console.error(err);
      });
  }
  function createKeyPair() {
    window.crypto.subtle.generateKey({
      name: "RSASSA-PKCS1-v1_5",
      modulusLength: 4096, //can be 1024, 2048, or 4096
      publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
      hash: {name: "SHA-512"}, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512"
      },
      true, //whether the key is extractable (i.e. can be used in exportKey)
      ["sign", "verify"] //can be any combination of "sign" and "verify"
    )
    .then(function(key){
      //returns a keypair object
      //console.log(key);
      console.log(key.publicKey);
      console.log(key.privateKey);
      savePublicKey(key.publicKey);
      savePrivateKey(key.privateKey);
    })
    .catch(function(err){
      console.error(err);
    });
  }
  function importKey(privateKey) {
    window.crypto.subtle.importKey(
      "jwk", //can be "jwk" (public or private), "spki" (public only), or "pkcs8" (private only)
      privateKey,
      {   //these are the algorithm options
      name: "RSASSA-PKCS1-v1_5",
      hash: {name: "SHA-512"}, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512"
      },
      false, //whether the key is extractable (i.e. can be used in exportKey)
      ["sign"] //"sign" for private key imports
    )
    .then(function(privateKey){
      //returns a publicKey (or privateKey if you are importing a private key)
      console.log(privateKey);
      signToken(privateKey);
    })
    .catch(function(err){
      console.error(err);
    });
  }

  var privateKey = localStorage.getItem('swc.login.privateKey');
  //console.log(privateKey);
  if (privateKey && 'string'== typeof privateKey) {
    var keyJson= JSON.parse(privateKey);
    importKey(keyJson);
  } else {
      createKeyPair();
  }
});
<commit_msg>Update login.js<commit_after>

$(function(){

  function ab2str(buf) {
    return String.fromCharCode.apply(null, new Uint16Array(buf));
  }
  function str2ab(str) {
    var buf = new ArrayBuffer(str.length*2); // 2 bytes for each char
    var bufView = new Uint16Array(buf);
    for (var i=0, strLen=str.length; i<strLen; i++) {
      bufView[i] = str.charCodeAt(i);
    }
    return buf;
  }

  function sendSign(signMsg){
    $.ajax({
      type: "POST",
      url:window.location,
			data:"'" + JSON.stringify(signMsg) + "'",
			dataType: 'json',
			contentType: 'application/json',
			charset:'UTF-8',
			success: function(data) {
			  console.log(data);
			}
    });

  }
  function signToken(privateKey) {
    var token = localStorage.getItem('swc.login.token');
    var abToken = str2ab(token);
    window.crypto.subtle.sign(
    {
        name: "RSASSA-PKCS1-v1_5",
    },
    privateKey, //from generateKey or importKey above
    abToken //ArrayBuffer of data you want to sign
    )
    .then(function(signature){
      //returns an ArrayBuffer containing the signature
      //console.log(signature);
      var jsonSign = {'token':token,'signature':ab2str(new Uint8Array(signature))};
      //console.log(JSON.stringify(jsonSign));
      sendSign(jsonSign)
    })
    .catch(function(err){
      console.error(err);
    });
  }
  function sendPublicKey(keydata){
    $.ajax({
      type: "POST",
      url:window.location,
			data:"'" + JSON.stringify(keydata) + "'",
			dataType: 'json',
			contentType: 'application/json',
			charset:'UTF-8',
			success: function(data) {
			  console.log(data);
			  if (data && data['token']) {
			    localStorage.setItem('swc.login.token',data['token']);
			    globalToken = data['token'];
			    signToken();
			  }
			}
    });
  }

  var savePublicKey = function(key) {
    window.crypto.subtle.exportKey(
      "spki", //can be "jwk" (public or private), "spki" (public only), or "pkcs8" (private only)
      key //can be a publicKey or privateKey, as long as extractable was true
      )
      .then(arrayBufferToBase64String)
      .then(toPem)
      .then(pem => {
        console.log(pem);
      })
/*
      .then(function(keydata){
        //returns the exported key data
        console.log(keydata);
        var name= 'swc.login.publicKey';
        localStorage.setItem(name,JSON.stringify(keydata));
        sendPublicKey(keydata);
      })
*/
      .catch(function(err){
        console.error(err);
      });
  }
  var savePrivateKey = function(key) {
    window.crypto.subtle.exportKey(
      "jwk", //can be "jwk" (public or private), "spki" (public only), or "pkcs8" (private only)
      key //can be a publicKey or privateKey, as long as extractable was true
      )
      .then(function(keydata){
        //returns the exported key data
        //console.log(keydata);
        var name= 'swc.login.privateKey';
        localStorage.setItem(name,JSON.stringify(keydata));
      })
      .catch(function(err){
        console.error(err);
      });
  }
  function createKeyPair() {
    window.crypto.subtle.generateKey({
      name: "RSASSA-PKCS1-v1_5",
      modulusLength: 4096, //can be 1024, 2048, or 4096
      publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
      hash: {name: "SHA-512"}, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512"
      },
      true, //whether the key is extractable (i.e. can be used in exportKey)
      ["sign", "verify"] //can be any combination of "sign" and "verify"
    )
    .then(function(key){
      //returns a keypair object
      //console.log(key);
      console.log(key.publicKey);
      console.log(key.privateKey);
      savePublicKey(key.publicKey);
      savePrivateKey(key.privateKey);
    })
    .catch(function(err){
      console.error(err);
    });
  }
  function importKey(privateKey) {
    window.crypto.subtle.importKey(
      "jwk", //can be "jwk" (public or private), "spki" (public only), or "pkcs8" (private only)
      privateKey,
      {   //these are the algorithm options
      name: "RSASSA-PKCS1-v1_5",
      hash: {name: "SHA-512"}, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512"
      },
      false, //whether the key is extractable (i.e. can be used in exportKey)
      ["sign"] //"sign" for private key imports
    )
    .then(function(privateKey){
      //returns a publicKey (or privateKey if you are importing a private key)
      console.log(privateKey);
      signToken(privateKey);
    })
    .catch(function(err){
      console.error(err);
    });
  }

  var privateKey = localStorage.getItem('swc.login.privateKey');
  //console.log(privateKey);
  if (privateKey && 'string'== typeof privateKey) {
    var keyJson= JSON.parse(privateKey);
    importKey(keyJson);
  } else {
      createKeyPair();
  }
});
<|endoftext|>


<commit_before>'use strict'

const path = require('path')
const webpack = require('webpack')
const config = require('./config')
const utils = require('./utils')

const NODE_ENV = process.env.NODE_ENV || 'production'

module.exports = {
  entry: {
    app: './resources/assets/js/index',
    editor: './resources/assets/js/editor',
  },
  output: {
    path: config[NODE_ENV].assetsRoot,
    publicPath: config[NODE_ENV].assetsPublicPath,
    filename: '[name].js',
  },
  resolve: {
    extensions: ['', '.js', '.vue', '.styl'],
    fallback: [path.join(__dirname, '../../../node_modules')],
    alias: {
      js: path.resolve(__dirname, '../js'),
      Components: path.resolve(__dirname, '../js/Components'),
      vue: 'vue/dist/vue.js',
    },
  },
  resolveLoader: {
    fallback: [path.join(__dirname, '../../../node_modules')],
  },
  module: {
    loaders: [
      {
        test: /\.vue$/,
        loader: 'vue',
      },
      {
        test: /\.js$/,
        loader: 'babel',
        include: path.resolve(__dirname, '../'),
        exclude: /node_modules/,
        query: {
          cacheDirectory: true,
        },
      },
      {
        test: /\.y$/,
        loader: 'raw',
      },
      {
        test: /\.html$/,
        loader: 'vue-html',
      },
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        loader: 'url',
        query: {
          limit: 10000,
          name: utils.assetsPath('img/[name].[hash:7].[ext]'),
        },
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        loader: 'url',
        query: {
          limit: 10000,
          name: utils.assetsPath('fonts/[name].[hash:7].[ext]'),
        },
      },
      {
        test: require.resolve('jquery'),
        loader: 'expose?jQuery!expose?$',
      },
      {
        test: require.resolve(__dirname + '/../js/Parser'),
        loader: 'expose?Parser!babel',
      },
      {
        test: require.resolve('brace'),
        loader: 'expose?ace',
      },
    ],
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env': config[NODE_ENV].env,
    }),
    new webpack.ProvidePlugin({
      $: 'jquery',
      jQuery: 'jquery',
    }),
    new webpack.NoErrorsPlugin(),
  ],
  node: {
    fs: 'empty',
  },
  vue: {
    loaders: utils.cssLoaders(),
  },
}
<commit_msg>style(eslint): fix eslint error<commit_after>'use strict'

const path = require('path')
const webpack = require('webpack')
const config = require('./config')
const utils = require('./utils')

const NODE_ENV = process.env.NODE_ENV || 'production'

module.exports = {
  entry: {
    app: './resources/assets/js/index',
    editor: './resources/assets/js/editor',
  },
  output: {
    path: config[NODE_ENV].assetsRoot,
    publicPath: config[NODE_ENV].assetsPublicPath,
    filename: '[name].js',
  },
  resolve: {
    extensions: ['', '.js', '.vue', '.styl'],
    fallback: [path.join(__dirname, '../../../node_modules')],
    alias: {
      js: path.resolve(__dirname, '../js'),
      Components: path.resolve(__dirname, '../js/Components'),
      vue: 'vue/dist/vue.js',
    },
  },
  resolveLoader: {
    fallback: [path.join(__dirname, '../../../node_modules')],
  },
  module: {
    loaders: [
      {
        test: /\.vue$/,
        loader: 'vue',
      },
      {
        test: /\.js$/,
        loader: 'babel',
        include: path.resolve(__dirname, '../'),
        exclude: /node_modules/,
        query: {
          cacheDirectory: true,
        },
      },
      {
        test: /\.y$/,
        loader: 'raw',
      },
      {
        test: /\.html$/,
        loader: 'vue-html',
      },
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        loader: 'url',
        query: {
          limit: 10000,
          name: utils.assetsPath('img/[name].[hash:7].[ext]'),
        },
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        loader: 'url',
        query: {
          limit: 10000,
          name: utils.assetsPath('fonts/[name].[hash:7].[ext]'),
        },
      },
      {
        test: require.resolve('jquery'),
        loader: 'expose?jQuery!expose?$',
      },
      {
        test: require.resolve(path.join(__dirname, '../js/Parser')),
        loader: 'expose?Parser!babel',
      },
      {
        test: require.resolve('brace'),
        loader: 'expose?ace',
      },
    ],
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env': config[NODE_ENV].env,
    }),
    new webpack.ProvidePlugin({
      $: 'jquery',
      jQuery: 'jquery',
    }),
    new webpack.NoErrorsPlugin(),
  ],
  node: {
    fs: 'empty',
  },
  vue: {
    loaders: utils.cssLoaders(),
  },
}
<|endoftext|>


<commit_before>
import fetch from 'isomorphic-fetch';
import moment from 'moment';

import * as types from '../constants/ActionTypes';
import Config from '../config';
import Mixins from '../mixins/global';
import { expiredToken } from './account';
import { getOneSurvey, postSurvey, receiveQuestionsFailure } from './questions';

function requestSurveysFailure(err) {
    return (dispatch) => {
        dispatch(expiredToken());
        dispatch({
            type: types.RECIEVE_SURVEYS_FAILURE,
            errorMsg: err
        });
    };
}

export function receiveSurveysSuccess(data) {
    return {
        type: types.RECIEVE_SURVEYS_SUCCESS,
        surveys: data
    };
}

export function getSurveys() {
    return (dispatch, getState) => {
        dispatch({ type: types.REMOVE_SELECTED_SURVEYS });
        dispatch({ type: types.REQUEST_SURVEYS_LIST });
        const { account, selectedUser, token } = getState();
        // fetch selected user account or user's account
        const accountid = selectedUser.hasOwnProperty('accountid') ?
            selectedUser.accountid : account.accountid;

        return fetch(`${Config.baseURL}/api/v1/mgnt/surveys/${accountid}`, {
            method: 'GET',
            credentials: 'same-origin',
            headers: {
                authorization: token
            }
        })
        .then(response => response.json())
        .then(data => {
            const surveys = data.surveys.sort((a, b) => {
                if (a.datetime < b.datetime) return 1;
                if (a.datetime > b.datetime) return -1;
                return 0;
            });
            dispatch(receiveSurveysSuccess(surveys));
        })
        .catch(err => dispatch(requestSurveysFailure(err)));
    };
}

export function toggleSelectedSurveys(data) {
    return (dispatch, getState) => {
        if (getState().selectedSurveys === data) {
            dispatch({
                type: types.REMOVE_SELECTED_SURVEYS
            });
        } else {
            dispatch({
                type: types.ADD_SELECTED_SURVEYS,
                selectedSurveys: data
            });
        }
    };
}

function requestDeleteSurveysFailure(err) {
    return (dispatch) => {
        dispatch(expiredToken());
        dispatch({
            type: types.RECIEVE_DELETE_SURVEYS_FAILURE,
            errorMsg: err
        });
    };
}

function receiveDeleteSurveysSuccess() {
    return {
        type: types.RECIEVE_DELETE_SURVEYS_SUCCESS
    };
}

export function deleteSurvey() {
    return (dispatch, getState) => {
        dispatch({ type: types.REQUEST_DELETE_SURVEYS });
        const { account, selectedUser, selectedSurveys, token } = getState();
        // delete selected user account or user's account
        const accountid = selectedUser.hasOwnProperty('accountid') ?
            selectedUser.accountid : account.accountid;
        return fetch(
            `${Config.baseURL}/api/v1/mgnt/surveys/${accountid}/${selectedSurveys}`, {
                method: 'DELETE',
                credentials: 'same-origin',
                headers: {
                    authorization: token
                }
            })
            .then(response => response.json())
            .then(() => {
                dispatch(receiveDeleteSurveysSuccess());
                dispatch(toggleSelectedSurveys(selectedSurveys));
                dispatch(getSurveys());
            })
            .catch(err => dispatch(requestDeleteSurveysFailure(err)));
    };
}

function receiveReportSuccess() {
    return {
        type: types.RECIEVE_REPORT_SUCCESS
    };
}

function receiveReportFailure(err) {
    return {
        type: types.RECIEVE_REPORT_FAILURE,
        errorMsg: err
    };
}

function handleReportHeader(survey, privacy) {
    const header = ['Client ID'];
    survey.forEach((que) => {
        header.push(que.label);
        switch (que.type) {
        case 'checkbox':
            for (const opt of que.data) {
                header.push(opt.label);
                if (opt.hasOwnProperty('input')) {
                    header.push(opt.input);
                }
            }
            break;
        case 'radio':
            for (const opt of que.data) {
                if (opt.hasOwnProperty('input')) {
                    header.push(opt.input);
                    break;
                }
            }
            break;
        case 'rating':
            if (que.hasOwnProperty('input')) {
                header.push(que.input);
            }
            break;
        default:
        }
    });
    if (privacy) header.push('Privacy email');
    header.push('Feedback time');

    return [header];
}

function handleReportContent(survey, privacy, feedbackAllData) {
    const content = [];
    for (const feed of feedbackAllData) {
        const data = feed.feedback;
        const body = [`${feed.clientid}${String.fromCharCode(8)}`];
        survey.forEach((que, idx) => {
            const num = idx + 1;
            const feedbackQue = data[`Q${num}`];
            if (feedbackQue) {
                let i = 0;
                const chk = [];
                switch (que.type) {
                case 'checkbox':
                    que.data.forEach((opt, optIdx) => {
                        chk.push(feedbackQue.data[optIdx].label);
                        if (opt.hasOwnProperty('input')) {
                            chk.push(feedbackQue.data[optIdx].input);
                        }
                        if (opt.label === feedbackQue.data[optIdx].label) i ++;
                    });
                    body.push(i.toString());
                    body.push(...chk);
                    break;
                case 'radio':
                    body.push(feedbackQue.data[0].label);
                    for (const opt of que.data) {
                        if (opt.hasOwnProperty('input')) {
                            body.push(feedbackQue.data[0].hasOwnProperty('input') ?
                                feedbackQue.data[0].input : '');
                            break;
                        }
                    }
                    break;
                case 'rating':
                    body.push(feedbackQue.data[0].label);
                    if (que.hasOwnProperty('input')) {
                        body.push(feedbackQue.data[0].hasOwnProperty('input') ?
                            feedbackQue.data[0].input : '');
                    }
                    break;
                default:
                }
            } else {
                // if no feedback in this one question
                body.push('');
                switch (que.type) {
                case 'checkbox':
                    que.data.forEach((opt) => {
                        if (opt.hasOwnProperty('input')) {
                            body.push('');
                        }
                    });
                    break;
                case 'radio':
                    for (const opt of que.data) {
                        if (opt.hasOwnProperty('input')) {
                            body.push('');
                            break;
                        }
                    }
                    break;
                case 'rating':
                    if (que.hasOwnProperty('input')) {
                        body.push('');
                    }
                    break;
                default:
                }
            }
        });
        if (privacy) {
            body.push(
                data.hasOwnProperty('thankyou') ?
                data.thankyou.privacy.input :
                ''
            );
        }
        body.push(moment(feed.datetime).format('LLL'));

        content.push(body);
    }

    return content;
}

export function exportSurvey() {
    return (dispatch, getState) => {
        dispatch({ type: types.REQUEST_REPORT });
        const { account, selectedUser, selectedSurveys, token } = getState();
        // export selected user account or user's account
        const accountid = selectedUser.hasOwnProperty('accountid') ?
            selectedUser.accountid : account.accountid;
        return fetch(
            `${Config.baseURL}/api/v1/mgnt/report/${accountid}/${selectedSurveys}`, {
                method: 'GET',
                credentials: 'same-origin',
                headers: {
                    authorization: token
                }
            })
            .then(response => response.json())
            .then(report => {
                const survey = report.survey.content;
                const feedback = report.data;
                const privacy = report.survey.thankyou.privacy.hasOwnProperty('label');

                let allSurvey = [];
                survey.forEach((page) => {
                    allSurvey = [...allSurvey, ...page.question];
                });

                Mixins.exportCSV(
                    `[Qustom]${report.subject}_${moment(Date.now()).format('YYYYMMDDHHmmss')}`,
                    'v1',
                    handleReportHeader(allSurvey, privacy),
                    handleReportContent(allSurvey, privacy, feedback)
                );
                dispatch(receiveReportSuccess());
            })
            .catch(err => dispatch(receiveReportFailure(err)));
    };
}

function postCopiedSurveySuccess() {
    return {
        type: types.POST_COPIEDSURVEY_SUCCESS
    };
}

function postCopiedSurveyFailure(err) {
    return {
        type: types.POST_COPIEDSURVEY_FAILURE,
        errorMsg: err
    };
}

function postCopiedSurvey(questions) {
    return (dispatch, getState) => {
        const { account, token } = getState();
        const postData = {
            subject: questions.subject,
            survey: questions.survey
        };

        return postSurvey(account.accountid, postData, token)
            .then(response => response.json())
            .then(data => {
                if (data.surveyid) {
                    dispatch(postCopiedSurveySuccess());
                    dispatch(getSurveys());
                } else {
                    dispatch(postCopiedSurveyFailure(data));
                }
            })
            .catch(err => dispatch(postCopiedSurveyFailure(err)));
    };
}

export function copySurvey() {
    return (dispatch, getState) => {
        dispatch({ type: types.REQUEST_COPY_SURVEY });
        const { account, selectedSurveys } = getState();

        return getOneSurvey(account.accountid, selectedSurveys)
            .then(response => response.json())
            .then(data => {
                if (data.surveyid) {
                    dispatch(postCopiedSurvey(data));
                } else {
                    dispatch(receiveQuestionsFailure(data));
                }
            })
            .catch(err => dispatch(receiveQuestionsFailure(err)));
    };
}
<commit_msg>Fix export checkbox content error when no data<commit_after>
import fetch from 'isomorphic-fetch';
import moment from 'moment';

import * as types from '../constants/ActionTypes';
import Config from '../config';
import Mixins from '../mixins/global';
import { expiredToken } from './account';
import { getOneSurvey, postSurvey, receiveQuestionsFailure } from './questions';

function requestSurveysFailure(err) {
    return (dispatch) => {
        dispatch(expiredToken());
        dispatch({
            type: types.RECIEVE_SURVEYS_FAILURE,
            errorMsg: err
        });
    };
}

export function receiveSurveysSuccess(data) {
    return {
        type: types.RECIEVE_SURVEYS_SUCCESS,
        surveys: data
    };
}

export function getSurveys() {
    return (dispatch, getState) => {
        dispatch({ type: types.REMOVE_SELECTED_SURVEYS });
        dispatch({ type: types.REQUEST_SURVEYS_LIST });
        const { account, selectedUser, token } = getState();
        // fetch selected user account or user's account
        const accountid = selectedUser.hasOwnProperty('accountid') ?
            selectedUser.accountid : account.accountid;

        return fetch(`${Config.baseURL}/api/v1/mgnt/surveys/${accountid}`, {
            method: 'GET',
            credentials: 'same-origin',
            headers: {
                authorization: token
            }
        })
        .then(response => response.json())
        .then(data => {
            const surveys = data.surveys.sort((a, b) => {
                if (a.datetime < b.datetime) return 1;
                if (a.datetime > b.datetime) return -1;
                return 0;
            });
            dispatch(receiveSurveysSuccess(surveys));
        })
        .catch(err => dispatch(requestSurveysFailure(err)));
    };
}

export function toggleSelectedSurveys(data) {
    return (dispatch, getState) => {
        if (getState().selectedSurveys === data) {
            dispatch({
                type: types.REMOVE_SELECTED_SURVEYS
            });
        } else {
            dispatch({
                type: types.ADD_SELECTED_SURVEYS,
                selectedSurveys: data
            });
        }
    };
}

function requestDeleteSurveysFailure(err) {
    return (dispatch) => {
        dispatch(expiredToken());
        dispatch({
            type: types.RECIEVE_DELETE_SURVEYS_FAILURE,
            errorMsg: err
        });
    };
}

function receiveDeleteSurveysSuccess() {
    return {
        type: types.RECIEVE_DELETE_SURVEYS_SUCCESS
    };
}

export function deleteSurvey() {
    return (dispatch, getState) => {
        dispatch({ type: types.REQUEST_DELETE_SURVEYS });
        const { account, selectedUser, selectedSurveys, token } = getState();
        // delete selected user account or user's account
        const accountid = selectedUser.hasOwnProperty('accountid') ?
            selectedUser.accountid : account.accountid;
        return fetch(
            `${Config.baseURL}/api/v1/mgnt/surveys/${accountid}/${selectedSurveys}`, {
                method: 'DELETE',
                credentials: 'same-origin',
                headers: {
                    authorization: token
                }
            })
            .then(response => response.json())
            .then(() => {
                dispatch(receiveDeleteSurveysSuccess());
                dispatch(toggleSelectedSurveys(selectedSurveys));
                dispatch(getSurveys());
            })
            .catch(err => dispatch(requestDeleteSurveysFailure(err)));
    };
}

function receiveReportSuccess() {
    return {
        type: types.RECIEVE_REPORT_SUCCESS
    };
}

function receiveReportFailure(err) {
    return {
        type: types.RECIEVE_REPORT_FAILURE,
        errorMsg: err
    };
}

function handleReportHeader(survey, privacy) {
    const header = ['Client ID'];
    survey.forEach((que) => {
        header.push(que.label);
        switch (que.type) {
        case 'checkbox':
            for (const opt of que.data) {
                header.push(opt.label);
                if (opt.hasOwnProperty('input')) {
                    header.push(opt.input);
                }
            }
            break;
        case 'radio':
            for (const opt of que.data) {
                if (opt.hasOwnProperty('input')) {
                    header.push(opt.input);
                    break;
                }
            }
            break;
        case 'rating':
            if (que.hasOwnProperty('input')) {
                header.push(que.input);
            }
            break;
        default:
        }
    });
    if (privacy) header.push('Privacy email');
    header.push('Feedback time');

    return [header];
}

function handleReportContent(survey, privacy, feedbackAllData) {
    const content = [];
    for (const feed of feedbackAllData) {
        const data = feed.feedback;
        const body = [`${feed.clientid}${String.fromCharCode(8)}`];
        survey.forEach((que, idx) => {
            const num = idx + 1;
            const feedbackQue = data[`Q${num}`];
            if (feedbackQue) {
                let i = 0;
                const chk = [];
                switch (que.type) {
                case 'checkbox':
                    que.data.forEach((opt, optIdx) => {
                        chk.push(feedbackQue.data[optIdx].label);
                        if (opt.hasOwnProperty('input')) {
                            chk.push(feedbackQue.data[optIdx].input);
                        }
                        if (opt.label === feedbackQue.data[optIdx].label) i ++;
                    });
                    body.push(i.toString());
                    body.push(...chk);
                    break;
                case 'radio':
                    body.push(feedbackQue.data[0].label);
                    for (const opt of que.data) {
                        if (opt.hasOwnProperty('input')) {
                            body.push(feedbackQue.data[0].hasOwnProperty('input') ?
                                feedbackQue.data[0].input : '');
                            break;
                        }
                    }
                    break;
                case 'rating':
                    body.push(feedbackQue.data[0].label);
                    if (que.hasOwnProperty('input')) {
                        body.push(feedbackQue.data[0].hasOwnProperty('input') ?
                            feedbackQue.data[0].input : '');
                    }
                    break;
                default:
                }
            } else {
                // if no feedback in this one question
                body.push('');
                switch (que.type) {
                case 'checkbox':
                    que.data.forEach((opt) => {
                        body.push('');
                        if (opt.hasOwnProperty('input')) {
                            body.push('');
                        }
                    });
                    break;
                case 'radio':
                    for (const opt of que.data) {
                        if (opt.hasOwnProperty('input')) {
                            body.push('');
                            break;
                        }
                    }
                    break;
                case 'rating':
                    if (que.hasOwnProperty('input')) {
                        body.push('');
                    }
                    break;
                default:
                }
            }
        });
        if (privacy) {
            body.push(
                data.hasOwnProperty('thankyou') ?
                data.thankyou.privacy.input :
                ''
            );
        }
        body.push(moment(feed.datetime).format('LLL'));

        content.push(body);
    }

    return content;
}

export function exportSurvey() {
    return (dispatch, getState) => {
        dispatch({ type: types.REQUEST_REPORT });
        const { account, selectedUser, selectedSurveys, token } = getState();
        // export selected user account or user's account
        const accountid = selectedUser.hasOwnProperty('accountid') ?
            selectedUser.accountid : account.accountid;
        return fetch(
            `${Config.baseURL}/api/v1/mgnt/report/${accountid}/${selectedSurveys}`, {
                method: 'GET',
                credentials: 'same-origin',
                headers: {
                    authorization: token
                }
            })
            .then(response => response.json())
            .then(report => {
                const survey = report.survey.content;
                const feedback = report.data;
                const privacy = report.survey.thankyou.privacy.hasOwnProperty('label');

                let allSurvey = [];
                survey.forEach((page) => {
                    allSurvey = [...allSurvey, ...page.question];
                });

                Mixins.exportCSV(
                    `[Qustom]${report.subject}_${moment(Date.now()).format('YYYYMMDDHHmmss')}`,
                    'v1',
                    handleReportHeader(allSurvey, privacy),
                    handleReportContent(allSurvey, privacy, feedback)
                );
                dispatch(receiveReportSuccess());
            })
            .catch(err => dispatch(receiveReportFailure(err)));
    };
}

function postCopiedSurveySuccess() {
    return {
        type: types.POST_COPIEDSURVEY_SUCCESS
    };
}

function postCopiedSurveyFailure(err) {
    return {
        type: types.POST_COPIEDSURVEY_FAILURE,
        errorMsg: err
    };
}

function postCopiedSurvey(questions) {
    return (dispatch, getState) => {
        const { account, token } = getState();
        const postData = {
            subject: questions.subject,
            survey: questions.survey
        };

        return postSurvey(account.accountid, postData, token)
            .then(response => response.json())
            .then(data => {
                if (data.surveyid) {
                    dispatch(postCopiedSurveySuccess());
                    dispatch(getSurveys());
                } else {
                    dispatch(postCopiedSurveyFailure(data));
                }
            })
            .catch(err => dispatch(postCopiedSurveyFailure(err)));
    };
}

export function copySurvey() {
    return (dispatch, getState) => {
        dispatch({ type: types.REQUEST_COPY_SURVEY });
        const { account, selectedSurveys } = getState();

        return getOneSurvey(account.accountid, selectedSurveys)
            .then(response => response.json())
            .then(data => {
                if (data.surveyid) {
                    dispatch(postCopiedSurvey(data));
                } else {
                    dispatch(receiveQuestionsFailure(data));
                }
            })
            .catch(err => dispatch(receiveQuestionsFailure(err)));
    };
}
<|endoftext|>


<commit_before>'use strict';

let cli      = require('heroku-cli-util');
let co       = require('co');
let _        = require('lodash');
let strftime = require('strftime');

let trunc = s => _.trunc(s, {length: 35, omission: '…'});

function printJSON (data) {
  cli.log(JSON.stringify(data.dynos, null, 2));
}

function timeAgo (since) {
  let elapsed = Math.floor((new Date() - since)/1000);
  let message = strftime('%Y/%m/%d %H:%M:%S', since);
  if (elapsed <= 60) return `${message} (~ ${Math.floor(elapsed)}s ago)`;
  else if (elapsed <= 60*60) return `${message} (~ ${Math.floor(elapsed/60)}m ago)`;
  else if (elapsed <= 60*60*25) return `${message} (~ ${Math.floor(elapsed/60/60)}h ago)`;
  else return message;
}

function timeRemaining (from, to) {
  let secs  = Math.floor(to/1000 - from/1000);
  let mins  = Math.floor(secs / 60);
  let hours = Math.floor(mins / 60);
  if (hours > 0) return `${hours}h ${mins % 60}m`;
  if (mins > 0)  return `${mins}m ${secs % 60}s`;
  if (secs > 0)  return `${secs}s`;
  return '';
}

function printQuota (quota) {
  let lbl;
  if (quota.allow_until) lbl = 'Free quota left';
  else if (quota.deny_until) lbl = 'Free quota exhausted. Unidle available in';
  if (lbl) {
    let timestamp = quota.allow_until ? new Date(quota.allow_until) : new Date(quota.deny_until);
    let time = timeRemaining(new Date(), timestamp);
    console.log(`${lbl}: ${time}`);
  }
}

function printExtended (dynos) {
  cli.table(dynos, {
    columns: [
      {key: 'id', label: 'ID'},
      {key: 'name', label: 'Process'},
      {key: 'state', label: 'State', format: (state, row) => `${state} ${timeAgo(new Date(row.updated_at))}`},
      {key: 'extended.region', label: 'Region'},
      {key: 'extended.instance', label: 'Instance'},
      {key: 'extended.port', label: 'Port'},
      {key: 'extended.az', label: 'AZ'},
      {key: 'release.version', label: 'Release'},
      {key: 'command', label: 'Command', format: trunc},
      {key: 'extended.route', label: 'Route'},
      {key: 'size', label: 'Size'},
    ]
  });
}

function printDynos (dynos) {
  let dynosByCommand = _.reduce(dynos, function (dynosByCommand, dyno) {
    let since = timeAgo(new Date(dyno.updated_at));
    let size = dyno.size || '1X';

    if (dyno.type === 'run') {
      let key = `run: one-off processes`;
      if (dynosByCommand[key] === undefined) dynosByCommand[key] = [];
      dynosByCommand[key].push(`${dyno.name} (${size}): ${dyno.state} ${since}: ${dyno.command}`);
    } else {
      let key = `${dyno.type} (${size}): ${dyno.command}`;
      if (dynosByCommand[key] === undefined) dynosByCommand[key] = [];
      let item = `${dyno.name}: ${dyno.state} ${since}`;
      dynosByCommand[key].push(item);
    }
    return dynosByCommand;
  }, {});
  for (let key of Object.keys(dynosByCommand).sort()) {
    cli.styledHeader(key);
    for (let dyno of dynosByCommand[key]) cli.log(dyno);
    cli.log();
  }
}

function* run (context, heroku) {
  let suffix = context.flags.extended ? '?extended=true' : '';
  let data = yield {
    quota: heroku.request({path: `/apps/${context.app}/actions/get-quota${suffix}`, method: 'post', headers: {accept: 'application/vnd.heroku+json; version=3.app-quotas'}}),
    dynos: heroku.request({path: `/apps/${context.app}/dynos${suffix}`}),
  };
  if (context.flags.json) {
    printJSON(data);
  } else if (context.flags.extended) {
    printExtended(data.dynos);
  } else {
    printQuota(data.quota);
    printDynos(data.dynos);
  }
}

module.exports = {
  topic: 'ps',
  description: 'list dynos for an app',
  flags: [
    {name: 'json', description: 'display as json'},
    {name: 'extended', char: 'x', hidden: true},
  ],
  help: `
Example:

 $ heroku ps
 === run: one-off dyno
 run.1: up for 5m: bash

 === web: bundle exec thin start -p $PORT
 web.1: created for 30s`,
  needsAuth: true,
  needsApp: true,
  run: cli.command(co.wrap(run))
};
<commit_msg>do not fail if quota is unavailable<commit_after>'use strict';

let cli      = require('heroku-cli-util');
let co       = require('co');
let _        = require('lodash');
let strftime = require('strftime');

let trunc = s => _.trunc(s, {length: 35, omission: '…'});

function printJSON (data) {
  cli.log(JSON.stringify(data.dynos, null, 2));
}

function timeAgo (since) {
  let elapsed = Math.floor((new Date() - since)/1000);
  let message = strftime('%Y/%m/%d %H:%M:%S', since);
  if (elapsed <= 60) return `${message} (~ ${Math.floor(elapsed)}s ago)`;
  else if (elapsed <= 60*60) return `${message} (~ ${Math.floor(elapsed/60)}m ago)`;
  else if (elapsed <= 60*60*25) return `${message} (~ ${Math.floor(elapsed/60/60)}h ago)`;
  else return message;
}

function timeRemaining (from, to) {
  let secs  = Math.floor(to/1000 - from/1000);
  let mins  = Math.floor(secs / 60);
  let hours = Math.floor(mins / 60);
  if (hours > 0) return `${hours}h ${mins % 60}m`;
  if (mins > 0)  return `${mins}m ${secs % 60}s`;
  if (secs > 0)  return `${secs}s`;
  return '';
}

function printQuota (quota) {
  if (!quota) return;
  let lbl;
  if (quota.allow_until) lbl = 'Free quota left';
  else if (quota.deny_until) lbl = 'Free quota exhausted. Unidle available in';
  if (lbl) {
    let timestamp = quota.allow_until ? new Date(quota.allow_until) : new Date(quota.deny_until);
    let time = timeRemaining(new Date(), timestamp);
    console.log(`${lbl}: ${time}`);
  }
}

function printExtended (dynos) {
  cli.table(dynos, {
    columns: [
      {key: 'id', label: 'ID'},
      {key: 'name', label: 'Process'},
      {key: 'state', label: 'State', format: (state, row) => `${state} ${timeAgo(new Date(row.updated_at))}`},
      {key: 'extended.region', label: 'Region'},
      {key: 'extended.instance', label: 'Instance'},
      {key: 'extended.port', label: 'Port'},
      {key: 'extended.az', label: 'AZ'},
      {key: 'release.version', label: 'Release'},
      {key: 'command', label: 'Command', format: trunc},
      {key: 'extended.route', label: 'Route'},
      {key: 'size', label: 'Size'},
    ]
  });
}

function printDynos (dynos) {
  let dynosByCommand = _.reduce(dynos, function (dynosByCommand, dyno) {
    let since = timeAgo(new Date(dyno.updated_at));
    let size = dyno.size || '1X';

    if (dyno.type === 'run') {
      let key = `run: one-off processes`;
      if (dynosByCommand[key] === undefined) dynosByCommand[key] = [];
      dynosByCommand[key].push(`${dyno.name} (${size}): ${dyno.state} ${since}: ${dyno.command}`);
    } else {
      let key = `${dyno.type} (${size}): ${dyno.command}`;
      if (dynosByCommand[key] === undefined) dynosByCommand[key] = [];
      let item = `${dyno.name}: ${dyno.state} ${since}`;
      dynosByCommand[key].push(item);
    }
    return dynosByCommand;
  }, {});
  for (let key of Object.keys(dynosByCommand).sort()) {
    cli.styledHeader(key);
    for (let dyno of dynosByCommand[key]) cli.log(dyno);
    cli.log();
  }
}

function* run (context, heroku) {
  let suffix = context.flags.extended ? '?extended=true' : '';
  let data = yield {
    quota: heroku.request({
      path: `/apps/${context.app}/actions/get-quota${suffix}`,
      method: 'post', headers: {accept: 'application/vnd.heroku+json; version=3.app-quotas'}
    }).catch(() => {}),
    dynos: heroku.request({path: `/apps/${context.app}/dynos${suffix}`}),
  };
  if (context.flags.json) {
    printJSON(data);
  } else if (context.flags.extended) {
    printExtended(data.dynos);
  } else {
    printQuota(data.quota);
    printDynos(data.dynos);
  }
}

module.exports = {
  topic: 'ps',
  description: 'list dynos for an app',
  flags: [
    {name: 'json', description: 'display as json'},
    {name: 'extended', char: 'x', hidden: true},
  ],
  help: `
Example:

 $ heroku ps
 === run: one-off dyno
 run.1: up for 5m: bash

 === web: bundle exec thin start -p $PORT
 web.1: created for 30s`,
  needsAuth: true,
  needsApp: true,
  run: cli.command(co.wrap(run))
};
<|endoftext|>


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

/*global Windows:true */

var cordova = require('cordova'),
    channel = require('cordova/channel');

var browserWrap;

var IAB = {

    close: function (win,lose) {
        if (browserWrap) {
            browserWrap.parentNode.removeChild(browserWrap);
            browserWrap = null;
        }
    },
    show: function (win,lose) {
        if (browserWrap) {

        }
    },
    open: function (win,lose,args) {
        var strUrl = args[0];
        var target = args[1];
        var features = args[2];

        if (target == "_system") {
            var url = new Windows.Foundation.Uri(strUrl)
            Windows.System.Launcher.launchUriAsync(url);
        }
        else if (target == "_blank") {
            if (!browserWrap) {
                browserWrap = document.createElement("div");
                browserWrap.style.position = "absolute";
                browserWrap.style.width = (window.innerWidth - 80) + "px";
                browserWrap.style.height = (window.innerHeight - 80) + "px";
                browserWrap.style.borderWidth = "40px";
                browserWrap.style.borderStyle = "solid";
                browserWrap.style.borderColor = "rgba(0,0,0,0.25)";

                browserWrap.onclick = function () {
                    setTimeout(function () {
                        IAB.close();
                    }, 0);
                }

                document.body.appendChild(browserWrap);
            }

            var elem = document.createElement("iframe");
                elem.style.width = (window.innerWidth - 80)+ "px";
                elem.style.height = (window.innerHeight - 80) + "px";
                elem.style.borderWidth = "0px";
                elem.name = "targetFrame";
                elem.src = strUrl;

                window.addEventListener("resize", function () {
                    if (browserWrap && elem) {
                        elem.style.width = (window.innerWidth - 80) + "px";
                        elem.style.height = (window.innerHeight - 80) + "px";
                    }
                });

            browserWrap.appendChild(elem);
        }
        else {
            window.location = strUrl;
        }

        //var object = new WinJS.UI.HtmlControl(elem, { uri: strUrl });

    },

    injectScriptCode:function(code, bCB) {

        // "(function(d) { var c = d.createElement('script'); c.src = %@; d.body.appendChild(c); })(document)"
    },

    injectScriptFile:function(file, bCB) {

    }
};

module.exports = IAB;

require("cordova/commandProxy").add("InAppBrowser",IAB);});
<commit_msg>[windows8] commandProxy was moved<commit_after>cordova.define("org.apache.cordova.inappbrowser.InAppBrowserProxy", function(require, exports, module) {  /*
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
*/

/*global Windows:true */

var cordova = require('cordova'),
    channel = require('cordova/channel');

var browserWrap;

var IAB = {

    close: function (win,lose) {
        if (browserWrap) {
            browserWrap.parentNode.removeChild(browserWrap);
            browserWrap = null;
        }
    },
    show: function (win,lose) {
        if (browserWrap) {

        }
    },
    open: function (win,lose,args) {
        var strUrl = args[0];
        var target = args[1];
        var features = args[2];

        if (target == "_system") {
            var url = new Windows.Foundation.Uri(strUrl)
            Windows.System.Launcher.launchUriAsync(url);
        }
        else if (target == "_blank") {
            if (!browserWrap) {
                browserWrap = document.createElement("div");
                browserWrap.style.position = "absolute";
                browserWrap.style.width = (window.innerWidth - 80) + "px";
                browserWrap.style.height = (window.innerHeight - 80) + "px";
                browserWrap.style.borderWidth = "40px";
                browserWrap.style.borderStyle = "solid";
                browserWrap.style.borderColor = "rgba(0,0,0,0.25)";

                browserWrap.onclick = function () {
                    setTimeout(function () {
                        IAB.close();
                    }, 0);
                }

                document.body.appendChild(browserWrap);
            }

            var elem = document.createElement("iframe");
                elem.style.width = (window.innerWidth - 80)+ "px";
                elem.style.height = (window.innerHeight - 80) + "px";
                elem.style.borderWidth = "0px";
                elem.name = "targetFrame";
                elem.src = strUrl;

                window.addEventListener("resize", function () {
                    if (browserWrap && elem) {
                        elem.style.width = (window.innerWidth - 80) + "px";
                        elem.style.height = (window.innerHeight - 80) + "px";
                    }
                });

            browserWrap.appendChild(elem);
        }
        else {
            window.location = strUrl;
        }

        //var object = new WinJS.UI.HtmlControl(elem, { uri: strUrl });

    },

    injectScriptCode:function(code, bCB) {

        // "(function(d) { var c = d.createElement('script'); c.src = %@; d.body.appendChild(c); })(document)"
    },

    injectScriptFile:function(file, bCB) {

    }
};

module.exports = IAB;

require("cordova/windows8/commandProxy").add("InAppBrowser",module.exports);
<|endoftext|>


<commit_before>
(function() {

    /**
     * A Moveable implementation.
     * @implements{Moveable}
     */
    function ClientMoveable(object, transform, constraint) {
		//oject
		this.object = object;
		//transform
		this.transform = transform;
		//constraint
		this.constraint = constraint;
		//current position; needed ONLY for the tween callback, not updated in other functions
		this.currentPosition = {x:this.transform.translation.x, y:this.transform.translation.y, z:this.transform.translation.z};
    };

    var p = ClientMoveable.prototype;

    /** @inheritDoc */
    p.setPosition = function(position){
    	if(this.constraint.constrainTranslation(position))
    		this.transform.translation.set(position[0],position[1],position[2]);
    	return this;
    };

    /** @inheritDoc */
	p.setOrientation = function(orientation){
		if(this.constraint.constrainRotation(orientation))
			this.transform.rotation.setQuaternion(new XML3DVec3(orientation[0],orientation[1],orientation[2]), orientation[3]);
		return this;
    };

    /** @inheritDoc */
    p.translate = function(translation){
		var destination = this.transform.translation.add( new XML3DRotation.setQuaternion(XML3DVec3(translation[0],translation[1],translation[2])) );
		if(this.constraint.constrainTranslation(destination))
			this.transform.translation.set(destination);
		return this;
    };

    /** @inheritDoc */
    p.rotate = function(orientation){
		//TODO: check how the rotate should really work oO
		var modifier = new XML3DRotation();
		modifier.setQuaternion( new XML3DVec3(orientation[0],orientation[1],orientation[2]), orientation[3] );
		var destination = this.transform.rotation.multiply( modifier );
		if(this.constraint.constrainRotation(orientation))
			this.transform.rotation.setQuaternion(destination);
		return this;
    };

    /** @inheritDoc */
    p.moveTo = function(position, time, opt){
		var dest_position = {x:position[0], y:position[1], z:position[2]};
		this.currentPosition.x = this.transform.translation.x;
		this.currentPosition.y = this.transform.translation.y;
		this.currentPosition.z = this.transform.translation.z;
		var tween = new TWEEN.Tween(this.currentPosition).to(dest_position, time);
		var that = this;
		tween.onUpdate( function() {
			that.setPosition([that.currentPosition.x,that.currentPosition.y,that.currentPosition.z]);
		} );
		tween.start();
		return this;
    };

    /** @inheritDoc */
    p.setConstraint = function(constraint){
		this.constraint = constraint;
    };

    //export
    XMOT.ClientMoveable = ClientMoveable;
}());
<commit_msg>Simplified the moveTo function<commit_after>
(function() {

    /**
     * A Moveable implementation.
     * @implements{Moveable}
     */
    function ClientMoveable(object, transform, constraint) {
		this.object = object;
		this.transform = transform;
		this.constraint = constraint;
		//movement queue
		this.queue = undefined; ?//TODO: implement movement queue
    };

    var p = ClientMoveable.prototype;

    /** @inheritDoc */
    p.setPosition = function(position){
    	if(this.constraint.constrainTranslation(position))
    		this.transform.translation.set(position[0],position[1],position[2]);
    	return this;
    };

    /** @inheritDoc */
	p.setOrientation = function(orientation){
		if(this.constraint.constrainRotation(orientation))
			this.transform.rotation.setQuaternion(new XML3DVec3(orientation[0],orientation[1],orientation[2]), orientation[3]);
		return this;
    };

    /** @inheritDoc */
    p.translate = function(translation){
		var destination = this.transform.translation.add( new XML3DRotation.setQuaternion(XML3DVec3(translation[0],translation[1],translation[2])) );
		if(this.constraint.constrainTranslation(destination))
			this.transform.translation.set(destination);
		return this;
    };

    /** @inheritDoc */
    p.rotate = function(orientation){
		//TODO: check how the rotate should really work oO
		var modifier = new XML3DRotation();
		modifier.setQuaternion( new XML3DVec3(orientation[0],orientation[1],orientation[2]), orientation[3] );
		var destination = this.transform.rotation.multiply( modifier );
		if(this.constraint.constrainRotation(orientation))
			this.transform.rotation.setQuaternion(destination);
		return this;
    };

    /** @inheritDoc */
    p.moveTo = function(position, time, opt){
		var dest_position = {x:position[0], y:position[1], z:position[2]};
		var currentPosition = {x:this.transform.translation.x, y:this.transform.translation.y, z:this.transform.translation.z};
		var tween = new TWEEN.Tween(currentPosition).to(dest_position, time);
		var that = this;
		tween.onUpdate( function() {
			that.setPosition([currentPosition.x, currentPosition.y, currentPosition.z]);
		} );
		tween.start();
		return this;
    };

    /** @inheritDoc */
    p.setConstraint = function(constraint){
		this.constraint = constraint;
    };

    //export
    XMOT.ClientMoveable = ClientMoveable;
}());
<|endoftext|>


<commit_before>import Alert from "../helpers/Alert";

import removeElementMixin from "./RemoveElementMixin";

export default {

    mixins: [removeElementMixin],

    props: {

        // The url where to submit the form.
        action: {
            type: String,
            required: true
        },

        // The method to use for the submit.
        method: {
            type: String,
            required: true
        },

        // The predefined data to submit with the form.
        data: {
            type: Object,
            default: () => {
                return {}
            }
        },

        // An object to define the messages to show to the user within a confirm alert, before the form will be submitted.
        // If not defined, no confirm message will be shown.
        // This object can contain the following key-value-pairs to modify the confirm alert:
        // - 'title': [The title of the confirm message]
        // - 'message': [The body message of the confirm message]
        // - 'type': [The alert type of the confirm dialog (info, success, warning [DEFAULT], error]
        // - 'accept': [The button text to show on the 'accept' button]
        // - 'cancel': [The button text to show on the 'cancel' button]
        confirm: {
            type: Object,
            default: null
        },

        // States if an error alert message shall be shown, if an error occurred.
        alertError: {
            type: Boolean,
            default: true
        },

        // The duration of the alert that will be shown after the form has been submitted.
        // Will only be used if the duration is not defined by the server response.
        alertDuration: {
            type: Number,
            default: 3000
        },

        // The base name of the events that get triggered by the form during a submit.
        eventName: {
            type: String,
            default: 'ajaxForm'
        },

        // The selector of the wrapper, where to append the response's data to.
        appendResponse: {
            type: String,
            default: null
        },

        // The selector of the wrapper, where to prepend the response's data to.
        prependResponse: {
            type: String,
            default: null
        },

        // The selector of the element, to replace with the response's data.
        replaceResponse: {
            type: String,
            default: null
        },

        // States if the form shall be submitted with ajax. Even though this is the purpose of this package,
        // it is sometimes useful to use the functionality of this package without submitting the form via ajax.
        ajax: {
            type: Boolean,
            default: true
        }
    },

    computed: {

        // The submit button of the form. Used to show the loader as soon as the submit request is pending.
        button: function () {
            return $(this.$el).find('button[type=submit]');
        }
    },

    data() {
        return {

            // States, if the form can be submitted.
            valid: true,

            // The html content to put in the submit button, while the form is submitting.
            loadingContent: '',

            // The html content to put in the loading button, after the form has been submitted and the loader has stopped.
            originalLoadingContent: '',

            // Defines the keys to extract from the server response to define the further handling of the form
            serverKeys: {
                showAlert: 'alert',
                alert: {
                    title: 'title',
                    message: 'message',
                    accept: 'accept',
                    duration: 'duration'
                },
                redirect: 'redirect',
                reload: 'reload',
                data: 'data',
                error: 'error'
            },

            // The editable data to submit with the form.
            submitData: {},
        }
    },

    watch: {

        /**
         * Watch the submit permission of the form, to enable or disable the submit button.
         *
         * @param isValid {@code true} if a submit is allowed, {@code false} otherwise.
         */
        valid: function (isValid) {
            window.eventHub.$emit('validated-' + this.eventName, isValid);
            this.button.prop('disabled', !isValid);
        },
    },

    mounted: function () {
        this.$nextTick(function () {

            // Get the original content from the submit button to replace the loader with the original content
            // after the serve response was received
            if (this.button) {
                this.originalLoadingContent = this.button.html();
            }

            // Disable the submit permission to let the user make at least one change
            this.validate();

            // Insert Laravel CSRF token, if normal submit is specified
            if (!this.ajax) {
                let token = document.head.querySelector('meta[name="csrf-token"]');
                if (token) {
                    $(this.$el).prepend('<input type="hidden" name="_token" value="' + token.content + '">');
                } else {
                    console.warn('Vue Forms: No CSRF token specified.');
                }
            }
        })
    },

    methods: {

        /**
         * Starts the form submitting process.
         */
        submit: function (event) {

            // Check if the ajax submit of the form is disabled or enabled
            if (this.ajax) {
                if (event) {
                    event.preventDefault();
                }
            } else {
                this.startLoader();

                return true;
            }

            // Don't let the user submit the form, if some inputs are not valid
            if (!this.valid) {
                window.eventHub.$emit('prevented_submit-' + this.eventName, this);
                return;
            }

            // Let the user confirm his submit action, if a confirm is specified in the properties.
            if (this.confirm && _.isObject(this.confirm)) {
                let confirmTitle = this.confirm.hasOwnProperty('title') ? this.confirm.title : null;
                let confirmMessage = this.confirm.hasOwnProperty('message') ? this.confirm.message : null;
                let confirmAccept = this.confirm.hasOwnProperty('accept') ? this.confirm.accept : null;
                let confirmCancel = this.confirm.hasOwnProperty('cancel') ? this.confirm.cancel : null;
                let confirmType = this.confirm.hasOwnProperty('type') ? this.confirm.type : 'warning';

                new Alert(confirmMessage, confirmTitle, confirmType).confirm(confirmAccept, confirmCancel).then((confirmed) => {
                    if (confirmed) {
                        this.startLoader();
                        this.sendData();
                    }
                });

            } else {
                this.startLoader();
                this.sendData();
            }
        },

        /**
         * Shows the loader, if a loader shall be shown.
         */
        startLoader: function () {
            if (this.button) {
                this.originalLoadingContent = this.button.html();
                this.button.html(this.loadingContent);
                this.button.prop('disabled', true);
            }
        },

        /**
         * Stops the loader, if a loader is shown.
         */
        stopLoader: function () {
            if (this.button) {
                this.button.html(this.originalLoadingContent);
                this.button.prop('disabled', false);
            }
        },

        /**
         * Sends the data of the form to the server.
         */
        sendData: function () {

            // Let the parent chain know, that the submit will be processed.
            window.eventHub.$emit('submitting-' + this.eventName, this);

            let data = Object.assign(this.data, this.submitData);
            let inputs = $(this.$el).serializeArray();
            _.each(inputs, function (input) {
                if (input.hasOwnProperty('name')) {

                    // Transform checkbox 'on'/'off' values to 'real' booleans
                    if (input.value === 'on') {
                        input.value = 1;
                    } else if (input.value === 'off') {
                        input.value = 0;
                    }

                    data[input.name] = input.value;
                }
            });

            $.ajax({
                type: this.method.toLowerCase(),
                url: this.action,
                data: data,
                success: response => {
                    this.handleResponse(true, response);
                },
                error: error => {
                    this.handleResponse(false, error.responseJSON);
                }
            });
        },

        /**
         * Handles the response from the server, after the form has been submitted.
         *
         * @param success {@code true} if the submit was successful, {@code false} otherwise.
         * @param response The response from the server.
         */
        handleResponse: function (success, response) {
            this.stopLoader();

            this.validate();

            this.showAlert(response, success).then(() => {
                if (success) {
                    this.handleSuccess(response);
                } else {
                    this.$emit('error');
                    this.onError(response);
                }

                // Call the callback to handle the after submit action directly on the page.
                // The callback has 4 parameters (+ the callback name):
                // - eventName: The name of the event to listen to for the callback.
                // - success: {@code true} if the request was successful handled on the server, {@code false} otherwise.
                // - response: The response message retrieved from the server.
                // - method: The method that was used to proceed the request.
                // - component: The current instance of this component (useful to extract the form with 'component.$el'
                window.eventHub.$emit('response-' + this.eventName, success, response, this.method.toLowerCase(), this);

                this.redirectUser(response);
            });
        },

        /**
         * Shows an alert based on the specified response and success field.
         *
         * @param response
         * @param success
         * @returns {Promise}
         */
        showAlert: function (response, success = true) {
            return new Promise((resolve) => {

                let message = null;
                let title = '';
                let accept = false;
                let duration = this.alertDuration;

                if (response && response.hasOwnProperty(this.serverKeys.showAlert) && response[this.serverKeys.showAlert].hasOwnProperty(this.serverKeys.alert.message)) {
                    let alertInfo = response[this.serverKeys.showAlert];

                    message = alertInfo[this.serverKeys.alert.message];
                    if (alertInfo.hasOwnProperty(this.serverKeys.alert.title)) {
                        title = alertInfo[this.serverKeys.alert.title];
                    }
                    if (alertInfo.hasOwnProperty(this.serverKeys.alert.accept)) {
                        accept = alertInfo[this.serverKeys.alert.accept];
                    }
                    if (alertInfo.hasOwnProperty(this.serverKeys.alert.duration)) {
                        duration = alertInfo[this.serverKeys.alert.duration];
                    }
                } else if (!success) {
                    title = 'Sorry!';
                    message = 'An unknown error occurred! Please try again later.';
                    accept = 'Ok!';

                    if (response && response.hasOwnProperty(this.serverKeys.error)) {
                        message = response[this.serverKeys.error];
                    } else if (response) {
                        for (let key in response) {
                            if (response.hasOwnProperty(key)) {
                                message = response[key];
                                break;
                            }
                        }
                    }
                }

                if (message) {
                    new Alert(message, title, success ? 'success' : 'error').show(accept, accept ? null : duration).then(() => {
                        resolve();
                    });
                } else {
                    resolve();
                }
            });
        },

        /**
         * Handles the successful response from the server.
         *
         * @param response The response from the server.
         */
        handleSuccess: function (response) {
            if (this.method.toLowerCase() === 'get') {
                updateHrefParamsWithData(this.form.data());
            }

            if (response.hasOwnProperty(this.serverKeys.data)) {
                let data = response[this.serverKeys.data];

                if (this.appendResponse) {
                    appendData(this.appendResponse, data);
                }

                if (this.prependResponse) {
                    prependData(this.prependResponse, data);
                }

                if (this.replaceResponse) {
                    replaceData(this.replaceResponse, data);
                }
            }
            this.removeElement();

            this.onSuccess(response);
            this.$emit('success');
        },

        /**
         * Redirects the user to the redirect path specified in the response
         */
        redirectUser: function (response) {
            if (response && response.hasOwnProperty(this.serverKeys.redirect)) {
                let redirect = response[this.serverKeys.redirect];
                let isSamePage = redirect.startsWith(window.location.href);
                window.location.href = redirect;
                if (isSamePage) {
                    window.location.reload(true);
                }
            } else if (response && response.hasOwnProperty(this.serverKeys.reload)) {
                window.location.reload(true);
            }
        },

        /**
         * Updates the state of the submit button and checks if the form can be submitted,
         * depending if the child inputs allow a submit.
         */
        validate: function () {
            let allInputsValid = true;
            let children = getListOfChildren(this);
            for (let index in children) {
                let child = children[index];
                if (child.hasOwnProperty("valid") && !child.valid) {
                    allInputsValid = false;
                }
            }

            this.valid = allInputsValid;
        },

        /**
         * Will be called if the form was successfully submitted.
         *
         * @param response The response from the server.
         */
        onSuccess: function (response) {
        },

        /**
         * Will be called if an error occurred on the form submit.
         *
         * @param response The response from the server.
         */
        onError: function (response) {
        },
    }
};<commit_msg>Finished organizer members manage page with new layout<commit_after>import Alert from "../helpers/Alert";

import removeElementMixin from "./RemoveElementMixin";

export default {

    mixins: [removeElementMixin],

    props: {

        // The url where to submit the form.
        action: {
            type: String,
            required: true
        },

        // The method to use for the submit.
        method: {
            type: String,
            required: true
        },

        // The predefined data to submit with the form.
        data: {
            type: Object,
            default: () => {
                return {}
            }
        },

        // An object to define the messages to show to the user within a confirm alert, before the form will be submitted.
        // If not defined, no confirm message will be shown.
        // This object can contain the following key-value-pairs to modify the confirm alert:
        // - 'title': [The title of the confirm message]
        // - 'message': [The body message of the confirm message]
        // - 'type': [The alert type of the confirm dialog (info, success, warning [DEFAULT], error]
        // - 'accept': [The button text to show on the 'accept' button]
        // - 'cancel': [The button text to show on the 'cancel' button]
        confirm: {
            type: Object,
            default: null
        },

        // States if an error alert message shall be shown, if an error occurred.
        alertError: {
            type: Boolean,
            default: true
        },

        // The duration of the alert that will be shown after the form has been submitted.
        // Will only be used if the duration is not defined by the server response.
        alertDuration: {
            type: Number,
            default: 3000
        },

        // The base name of the events that get triggered by the form during a submit.
        eventName: {
            type: String,
            default: 'ajaxForm'
        },

        // The selector of the wrapper, where to append the response's data to.
        appendResponse: {
            type: String,
            default: null
        },

        // The selector of the wrapper, where to prepend the response's data to.
        prependResponse: {
            type: String,
            default: null
        },

        // The selector of the element, to replace with the response's data.
        replaceResponse: {
            type: String,
            default: null
        },

        // States if the form shall be submitted with ajax. Even though this is the purpose of this package,
        // it is sometimes useful to use the functionality of this package without submitting the form via ajax.
        ajax: {
            type: Boolean,
            default: true
        }
    },

    computed: {

        // The submit button of the form. Used to show the loader as soon as the submit request is pending.
        button: function () {
            return $(this.$el).find('button[type=submit]');
        }
    },

    data() {
        return {

            // States, if the form can be submitted.
            valid: true,

            // The html content to put in the submit button, while the form is submitting.
            loadingContent: '',

            // The html content to put in the loading button, after the form has been submitted and the loader has stopped.
            originalLoadingContent: '',

            // Defines the keys to extract from the server response to define the further handling of the form
            serverKeys: {
                showAlert: 'alert',
                alert: {
                    title: 'title',
                    message: 'message',
                    accept: 'accept',
                    duration: 'duration'
                },
                redirect: 'redirect',
                reload: 'reload',
                data: 'data',
                error: 'error'
            },

            // The editable data to submit with the form.
            submitData: {},
        }
    },

    watch: {

        /**
         * Watch the submit permission of the form, to enable or disable the submit button.
         *
         * @param isValid {@code true} if a submit is allowed, {@code false} otherwise.
         */
        valid: function (isValid) {
            window.eventHub.$emit('validated-' + this.eventName, isValid);
            this.button.prop('disabled', !isValid);
        },
    },

    mounted: function () {
        this.$nextTick(function () {

            // Get the original content from the submit button to replace the loader with the original content
            // after the serve response was received
            if (this.button) {
                this.originalLoadingContent = this.button.html();
            }

            // Disable the submit permission to let the user make at least one change
            this.validate();

            // Insert Laravel CSRF token, if normal submit is specified
            if (!this.ajax) {
                let token = document.head.querySelector('meta[name="csrf-token"]');
                if (token) {
                    $(this.$el).prepend('<input type="hidden" name="_token" value="' + token.content + '">');
                } else {
                    console.warn('Vue Forms: No CSRF token specified.');
                }
            }
        })
    },

    methods: {

        /**
         * Starts the form submitting process.
         */
        submit: function (event) {

            // Check if the ajax submit of the form is disabled or enabled
            if (this.ajax) {
                if (event) {
                    event.preventDefault();
                }
            } else {
                this.startLoader();

                return true;
            }

            // Don't let the user submit the form, if some inputs are not valid
            if (!this.valid) {
                window.eventHub.$emit('prevented_submit-' + this.eventName, this);
                return;
            }

            // Let the user confirm his submit action, if a confirm is specified in the properties.
            if (this.confirm && _.isObject(this.confirm)) {
                let confirmTitle = this.confirm.hasOwnProperty('title') ? this.confirm.title : null;
                let confirmMessage = this.confirm.hasOwnProperty('message') ? this.confirm.message : null;
                let confirmAccept = this.confirm.hasOwnProperty('accept') ? this.confirm.accept : null;
                let confirmCancel = this.confirm.hasOwnProperty('cancel') ? this.confirm.cancel : null;
                let confirmType = this.confirm.hasOwnProperty('type') ? this.confirm.type : 'warning';

                new Alert(confirmMessage, confirmTitle, confirmType).confirm(confirmAccept, confirmCancel).then((confirmed) => {
                    if (confirmed) {
                        this.startLoader();
                        this.sendData();
                    }
                });

            } else {
                this.startLoader();
                this.sendData();
            }
        },

        /**
         * Shows the loader, if a loader shall be shown.
         */
        startLoader: function () {
            if (this.button) {
                this.originalLoadingContent = this.button.html();
                this.button.html(this.loadingContent);
                this.button.prop('disabled', true);
            }
        },

        /**
         * Stops the loader, if a loader is shown.
         */
        stopLoader: function () {
            if (this.button) {
                this.button.html(this.originalLoadingContent);
                this.button.prop('disabled', false);
            }
        },

        /**
         * Sends the data of the form to the server.
         */
        sendData: function () {

            // Let the parent chain know, that the submit will be processed.
            window.eventHub.$emit('submitting-' + this.eventName, this);

            let data = Object.assign(this.data, this.submitData);
            let inputs = $(this.$el).serializeArray();
            _.each(inputs, function (input) {
                if (input.hasOwnProperty('name')) {

                    // Transform checkbox 'on'/'off' values to 'real' booleans
                    if (input.value === 'on') {
                        input.value = 1;
                    } else if (input.value === 'off') {
                        input.value = 0;
                    }

                    data[input.name] = input.value;
                }
            });

            $.ajax({
                type: this.method.toLowerCase(),
                url: this.action,
                data: data,
                success: response => {
                    this.handleResponse(true, response);
                },
                error: error => {
                    this.handleResponse(false, error.responseJSON);
                }
            });
        },

        /**
         * Handles the response from the server, after the form has been submitted.
         *
         * @param success {@code true} if the submit was successful, {@code false} otherwise.
         * @param response The response from the server.
         */
        handleResponse: function (success, response) {
            this.stopLoader();

            this.validate();

            this.showAlert(response, success).then(() => {
                if (success) {
                    this.handleSuccess(response);
                } else {
                    this.$emit('error');
                    this.onError(response);
                }

                // Call the callback to handle the after submit action directly on the page.
                // The callback has 4 parameters (+ the callback name):
                // - eventName: The name of the event to listen to for the callback.
                // - success: {@code true} if the request was successful handled on the server, {@code false} otherwise.
                // - response: The response message retrieved from the server.
                // - method: The method that was used to proceed the request.
                // - component: The current instance of this component (useful to extract the form with 'component.$el'
                window.eventHub.$emit('response-' + this.eventName, success, response, this.method.toLowerCase(), this);

                this.redirectUser(response);
            });
        },

        /**
         * Shows an alert based on the specified response and success field.
         *
         * @param response
         * @param success
         * @returns {Promise}
         */
        showAlert: function (response, success = true) {
            return new Promise((resolve) => {

                let message = null;
                let title = '';
                let accept = false;
                let duration = this.alertDuration;

                if (response && response.hasOwnProperty(this.serverKeys.showAlert) && response[this.serverKeys.showAlert].hasOwnProperty(this.serverKeys.alert.message)) {
                    let alertInfo = response[this.serverKeys.showAlert];

                    message = alertInfo[this.serverKeys.alert.message];
                    if (alertInfo.hasOwnProperty(this.serverKeys.alert.title)) {
                        title = alertInfo[this.serverKeys.alert.title];
                    }
                    if (alertInfo.hasOwnProperty(this.serverKeys.alert.accept)) {
                        accept = alertInfo[this.serverKeys.alert.accept];
                    }
                    if (alertInfo.hasOwnProperty(this.serverKeys.alert.duration)) {
                        duration = alertInfo[this.serverKeys.alert.duration];
                    }
                } else if (!success) {
                    title = 'Sorry!';
                    message = 'An unknown error occurred! Please try again later.';
                    accept = 'Ok!';

                    if (response && response.hasOwnProperty(this.serverKeys.error)) {
                        message = response[this.serverKeys.error];
                    } else if (response) {
                        for (let key in response) {
                            if (response.hasOwnProperty(key)) {
                                message = response[key];
                                break;
                            }
                        }
                    }
                }

                if (message) {
                    new Alert(message, title, success ? 'success' : 'error').show(accept, accept ? null : duration).then(() => {
                        resolve();
                    });
                } else {
                    resolve();
                }
            });
        },

        /**
         * Handles the successful response from the server.
         *
         * @param response The response from the server.
         */
        handleSuccess: function (response) {
            if (this.method.toLowerCase() === 'get') {
                updateHrefParamsWithData(this.form.data());
            }

            let data = null;
            if (response.hasOwnProperty(this.serverKeys.data)) {
                data = response[this.serverKeys.data];

                if (this.appendResponse) {
                    appendData(this.appendResponse, data);
                }

                if (this.prependResponse) {
                    prependData(this.prependResponse, data);
                }

                if (this.replaceResponse) {
                    replaceData(this.replaceResponse, data);
                }
            }
            this.removeElement();

            this.onSuccess(response);
            this.$emit('success', data);
        },

        /**
         * Redirects the user to the redirect path specified in the response
         */
        redirectUser: function (response) {
            if (response && response.hasOwnProperty(this.serverKeys.redirect)) {
                let redirect = response[this.serverKeys.redirect];
                let isSamePage = redirect.startsWith(window.location.href);
                window.location.href = redirect;
                if (isSamePage) {
                    window.location.reload(true);
                }
            } else if (response && response.hasOwnProperty(this.serverKeys.reload)) {
                window.location.reload(true);
            }
        },

        /**
         * Updates the state of the submit button and checks if the form can be submitted,
         * depending if the child inputs allow a submit.
         */
        validate: function () {
            let allInputsValid = true;
            let children = getListOfChildren(this);
            for (let index in children) {
                let child = children[index];
                if (child.hasOwnProperty("valid") && !child.valid) {
                    allInputsValid = false;
                }
            }

            this.valid = allInputsValid;
        },

        /**
         * Will be called if the form was successfully submitted.
         *
         * @param response The response from the server.
         */
        onSuccess: function (response) {
        },

        /**
         * Will be called if an error occurred on the form submit.
         *
         * @param response The response from the server.
         */
        onError: function (response) {
        },
    }
};<|endoftext|>


<commit_before>import React from 'react'
import ReactDOM from 'react-dom'
import Resumable from 'resumablejs'
import when from 'when'
import Config from '../utils/config'
import Logger from '../utils/logger'

class FilePreview extends React.Component {
  render() {
    const url = Config.get('api') + `/admin/assets/${this.props.id}/preview`
    if(this.props.id) {
      return
    }
    else {
      return null
    }
  }
}

export default class FileField extends React.Component {

  static propTypes = {
    code: React.PropTypes.string,
    disabled: React.PropTypes.bool,
    placeholder: React.PropTypes.string,
    defaultValue: React.PropTypes.string,
    query: React.PropTypes.object,
    mode: React.PropTypes.oneOf('single', 'multi'),
    target: React.PropTypes.string
  }

  static defaultProps = {
    code: null,
    disabled: false,
    placeholder: '',
    defaultValue: '',
    query: {},
    mode: 'single',
    target: '/admin/chunks'
  }

  constructor(props) {
    super(props)
    this.state = {
      focused: false,
      validated: false,
      isValid: null,
      filesFailed: [],
      multi: {
        files: [],
        status: 'WAITING',
        filesComplete: []
      },
      preview: props.defaultValue
    }

    this.r = new Resumable({
      target: Config.get('api') + props.target,
      query: props.query,
      withCredentials: true,
      maxFiles: (props.mode === 'single' ? 1 : props.maxFiles),
    });

    this.isResumableSupported = this.r.support;

    this.r.on('fileAdded', this.onFileAdded.bind(this))
    this.r.on('fileProgress', this.onFileProgress.bind(this))
    this.r.on('fileError', this.onFileError.bind(this))
    this.r.on('fileSuccess', this.onFileSuccess.bind(this))
    this.r.on('fileRetry', this.onFileRetry.bind(this))

    this.r.on('complete', this.onComplete.bind(this))
    this.r.on('pause', this.onPause.bind(this))
    this.r.on('cancel', this.onCancel.bind(this))
    this.r.on('error', this.onError.bind(this))
  }

  render() {
    if (this.props.mode === 'single') {
      if(this.r.files.length > 0) {
        return(

              {this.r.files[0].fileName} ({this.formatSize(this.r.files[0].size)})

        )
      }
      else {
        return (

            <FilePreview id={this.state.preview}/>

              Add File

        )
      }
    }
    else {
      return (

                  Drop Files Here

OR

              Add Files

              {this.r.files.map(file => {
                let progressClass = 'ui progress'
                if(_.includes(this.state.filesFailed, file.uniqueIdentifier)) {
                  progressClass += ' error'
                }
                return (

{file.fileName}

                )
              })}

      )
    }
  }

  componentDidMount() {
    this.r.assignBrowse(this.refs.browseButton)

    if (this.props.mode === 'multi') {
      this.r.assignDrop(this.refs.dropzone)
    }
  }

  componentDidUpdate() {

  }

  clearFiles() {
    while(this.r.files.length > 1) {
      r.files[0].cancel()
    }
  }

  beginUpload() {
    const single = this.props.mode === 'single'
    this.rPromise = when.promise((resolve, reject) => {
      let fileResults = []
      this.r.on('complete', () => resolve(fileResults))
      this.r.on('error', reject)
      this.r.on('fileSuccess', (_file, r) => {
        Logger.log(_file, r)
        let resp = JSON.parse(r)
        let assetId = _.get(resp, 'asset_id', null) || _.get(resp, 'id', null)
        fileResults.push(assetId)
      })
      this.r.upload()
    })
    .then(assetIds => {
      if(single) {
        return assetIds[0]
      }
      else {
        return assetIds
      }
    })
    .tap(Logger.log.bind(Logger))
    .catch(failure => {
      Logger.error(failure)
    })
  }

  getOverallProgress() {
    return this.r.progress()
  }

  onFileAdded(_file) {
    this.forceUpdate()
  }

  onFileSuccess(file, serverResponse) {
    Logger.log(file, serverResponse)
  }

  onFileError(file, serverResponse) {
    Logger.log(file, serverResponse)
    this.setState({
      filesFailed: this.state.filesFailed.concat([file.uniqueIdentifier])
    })
  }

  onFileProgress(file) {
    Logger.log(file.fileName, file.progress())
    $(this.refs.fileTable).find(`#${file.uniqueIdentifier}`).progress({percent: Math.floor(file.progress() * 100)})
    //this.forceUpdate()
  }

  onFileRetry(_file) {
    //this.forceUpdate()
  }

  onComplete() {
    this.setState({
      multi: {
        status: 'COMPLETE'
      }
    })
  }

  onPause() {
    this.setState({
      multi: {
        status: 'PAUSED'
      }
    })
  }

  onCancel() {
    this.setState({
      multi: {
        status: 'CANCELLED'
      }
    })
  }

  onError(message, file) {
    this.setState({
      multi: {
        status: 'FAILED'
      }
    })
  }

  // Ripped straight outta Resumable
  formatSize(size){
    if(size<1024) {
      return size + ' bytes';
    } else if(size<1024*1024) {
      return (size/1024.0).toFixed(0) + ' KB';
    } else if(size<1024*1024*1024) {
      return (size/1024.0/1024.0).toFixed(1) + ' MB';
    } else {
      return (size/1024.0/1024.0/1024.0).toFixed(1) + ' GB';
    }
  }

  getValue() {
    this.beginUpload()
    return this.rPromise
  }

  setValue(value) {
    this.setState({preview: value})
  }

  getReference() {
    return {[this.props.code]: this}
  }
}
<commit_msg>Add eager uploading and error handling UI to FileField control<commit_after>import React from 'react'
import ReactDOM from 'react-dom'
import Resumable from 'resumablejs'
import when from 'when'
import Config from '../utils/config'
import Logger from '../utils/logger'

class FilePreview extends React.Component {
  render() {
    const url = Config.get('api') + `/admin/assets/${this.props.id}/preview`
    if(this.props.id) {
      return
    }
    else {
      return null
    }
  }
}

export default class FileField extends React.Component {

  static propTypes = {
    code: React.PropTypes.string,
    disabled: React.PropTypes.bool,
    placeholder: React.PropTypes.string,
    defaultValue: React.PropTypes.string,
    query: React.PropTypes.object,
    mode: React.PropTypes.oneOf('single', 'multi'),
    target: React.PropTypes.string,
    eager: React.PropTypes.bool
  }

  static defaultProps = {
    code: null,
    disabled: false,
    placeholder: '',
    defaultValue: '',
    query: {},
    mode: 'single',
    target: '/admin/chunks',
    eager: true
  }

  constructor(props) {
    super(props)
    this.state = {
      focused: false,
      validated: false,
      isValid: null,
      filesFailed: [],
      multi: {
        files: [],
        status: 'WAITING',
        filesComplete: []
      },
      preview: props.defaultValue,
      uploadInProgress: false,
      uploadComplete: false,
      uploadFailed: false
    }

    this.r = new Resumable({
      target: Config.get('api.pathPrefix') + props.target,
      query: props.query,
      withCredentials: true,
      maxFiles: (props.mode === 'single' ? 1 : props.maxFiles),
    });

    this.isResumableSupported = this.r.support;

    this.r.on('fileAdded', this.onFileAdded.bind(this))
    this.r.on('fileProgress', this.onFileProgress.bind(this))
    this.r.on('fileError', this.onFileError.bind(this))
    this.r.on('fileSuccess', this.onFileSuccess.bind(this))
    this.r.on('fileRetry', this.onFileRetry.bind(this))

    this.r.on('complete', this.onComplete.bind(this))
    this.r.on('pause', this.onPause.bind(this))
    this.r.on('cancel', this.onCancel.bind(this))
    this.r.on('error', this.onError.bind(this))
  }

  render() {
    const allFilesFailed = this.r.files.length > 0 && this.state.filesFailed.length === this.r.files.length

    if (this.props.mode === 'single') {
      if(allFilesFailed) {
        return (

Uploading failed.

              Retry

              Choose Files...

        )
      }
      if(this.state.uploadInProgress) {
        return <FileProgress/>
      }
      if(this.r.files.length > 0) {
        return(

              {this.r.files[0].fileName} ({this.formatSize(this.r.files[0].size)})

        )
      }
      else {
        return (

            <FilePreview id={this.state.preview}/>

              Add File

        )
      }
    }
    else {
      return (

                  Drop Files Here

OR

              Add Files

              {this.r.files.map(file => {
                let progressClass = 'ui progress'
                if(_.includes(this.state.filesFailed, file.uniqueIdentifier)) {
                  progressClass += ' error'
                }
                return (

{file.fileName}

                )
              })}

      )
    }
  }

  componentDidMount() {
    this.r.assignBrowse(this.refs.browseButton)

    if (this.props.mode === 'multi') {
      this.r.assignDrop(this.refs.dropzone)
    }
  }

  componentDidUpdate() {

  }

  clearFiles() {
    while(this.r.files.length > 1) {
      r.files[0].cancel()
    }
    this.setState({filesFailed: []})
  }

  clearAndChoose() {
    this.clearFiles()
  }

  retry() {
    _.forEach(this.r.files, f => f.retry())
    this.setState({filesFailed: [], uploadInProgress: true, uploadComplete: false, uploadFailed: false})
  }

  beginUpload() {
    const single = this.props.mode === 'single'
    this.setState({uploadInProgress: true})
    this.rPromise = when.promise((resolve, reject) => {
      let fileResults = []
      this.r.on('complete', () => resolve(fileResults))
      this.r.on('error', reject)
      this.r.on('fileSuccess', (_file, r) => {
        Logger.log(_file, r)
        let resp = JSON.parse(r)
        let assetId = _.get(resp, 'asset_id', null) || _.get(resp, 'id', null)
        fileResults.push(assetId)
      })
      this.r.upload()
    })
    .tap(() => this.setState({uploadInProgress: false, uploadComplete: true}))
    .then(assetIds => {
      if(single) {
        return assetIds[0]
      }
      else {
        return assetIds
      }
    })
    .tap(Logger.log.bind(Logger))
    .catch(failure => {
      Logger.error(failure)
    })
  }

  getOverallProgress() {
    return this.r.progress()
  }

  onFileAdded(_file) {
    this.forceUpdate()
    if(this.props.mode === 'single' && this.props.eager) {
      this.beginUpload()
    }
  }

  onFileSuccess(file, serverResponse) {
    Logger.log(file, serverResponse)
  }

  onFileError(file, serverResponse) {
    Logger.log(file, serverResponse)
    const newFailures = this.state.filesFailed.concat([file.uniqueIdentifier])
    this.setState({
      filesFailed: newFailures
    })

    if(newFailures.length === this.r.files.length) {
      this.r.assignBrowse(this.refs.reBrowseButton)
    }
  }

  onFileProgress(file) {
    Logger.log(file.fileName, file.progress())
    $(this.refs.fileTable).find(`#${file.uniqueIdentifier}`).progress({percent: Math.floor(file.progress() * 100)})
    if(this.state.uploadInProgress) {
      $(".file.progress").progress({
        percent: Math.ceil(this.getOverallProgress() * 100)
      })
    }
  }

  onFileRetry(_file) {
    //this.forceUpdate()
  }

  onComplete() {
    this.setState({
      multi: {
        status: 'COMPLETE'
      }
    })
  }

  onPause() {
    this.setState({
      multi: {
        status: 'PAUSED'
      }
    })
  }

  onCancel() {
    this.setState({
      multi: {
        status: 'CANCELLED'
      }
    })
  }

  onError(message, file) {
    this.setState({
      multi: {
        status: 'FAILED'
      }
    })
  }

  // Ripped straight outta Resumable
  formatSize(size){
    if(size<1024) {
      return size + ' bytes';
    } else if(size<1024*1024) {
      return (size/1024.0).toFixed(0) + ' KB';
    } else if(size<1024*1024*1024) {
      return (size/1024.0/1024.0).toFixed(1) + ' MB';
    } else {
      return (size/1024.0/1024.0/1024.0).toFixed(1) + ' GB';
    }
  }

  getValue() {
    // Only begin the upload here if there is no upload in progress and an upload has not already completed
    if(!this.state.uploadInProgress && !this.state.uploadComplete) {
      this.beginUpload()
    }
    return this.rPromise
  }

  setValue(value) {
    this.setState({preview: value})
  }

  getReference() {
    return {[this.props.code]: this}
  }
}

const FileProgress = props => {
  return (

Uploading

  )
}
<|endoftext|>