<commit_before>"use strict";
var deployService = soajsApp.components;
deployService.service('deploySrv', ['ngDataApi', '$timeout', '$modal', function(ngDataApi, $timeout, $modal) {

    function deployEnvironment(currentScope, envCode, haMode) {
        var formConfig = angular.copy(environmentsConfig.form.deploy);
        var kubeConfig = environmentsConfig.deployer.kubernetes;

        currentScope.isKubernetes = (currentScope.deployer.selected.split('.')[1] === "kubernetes");
        if(currentScope.isKubernetes){
            formConfig.entries[0].entries[1].min = kubeConfig.minPort;
            formConfig.entries[0].entries[1].max = kubeConfig.maxPort;
            formConfig.entries[0].entries[1].fieldMsg += ". Kubernetes port range: " + kubeConfig.minPort + " - " + kubeConfig.maxPort;
        }

        getControllerBranches(currentScope, function (branchInfo) {
            for (var i = 0; i < formConfig.entries.length; i++) {
                if (formConfig.entries[i].name === 'controllers') {
                    var ctrlEntries = formConfig.entries[i].entries;
                    for (var j = 0; j < ctrlEntries.length; j++) {
                        if (ctrlEntries[j].name === 'branch') {
                            branchInfo.branches.forEach(function (oneBranch) {
                                delete oneBranch.commit.url;
                                ctrlEntries[j].value.push({'v': oneBranch, 'l': oneBranch.name});
                            });
                        }
                    }
                }
            }

            var customUIEntry = {
                'name': 'useCustomUI',
                'label': 'Do you want to bundle static content?',
                'type': 'radio',
                'value': [{'v': true, 'l': 'Yes'}, {'v': false, 'l': 'No', 'selected': true}],
                'required': true,
                'onAction': function (label, selected, formConfig) {
                    if (selected === 'true' && (!formConfig.entries[0].entries[5] || formConfig.entries[0].entries[5].name !== 'selectCustomUI')) {
                        listStaticContent(currentScope, function (staticContentSources) {
                            var selectCustomUI = {
                                'name': 'selectCustomUI',
                                'label': 'Choose Static Content',
                                'type': 'select',
                                'value': [],
                                'required': true,
                                'onAction': function (label, selected, formConfig) {
                                    var selectUIBranch = {
                                        'name': 'selectUIBranch',
                                        'label': 'Choose Static Content Branch',
                                        'type': 'select',
                                        'value': [],
                                        'required': true
                                    };
                                    selected = JSON.parse(selected);
                                    overlayLoading.show();
                                    getSendDataFromServer(currentScope, ngDataApi, {
                                        method: 'get',
                                        routeName: '/dashboard/gitAccounts/getBranches',
                                        params: {
                                            name: selected.name,
                                            type: 'static'
                                        }
                                    }, function (error, response) {
                                        overlayLoading.hide();
                                        if (error) {
                                            currentScope.generateNewMsg(envCode, 'danger', error.message);
                                        }
                                        else {
                                            response.branches.forEach(function (oneBranch) {
                                                selectUIBranch.value.push({'v': oneBranch, 'l': oneBranch.name});
                                            });

                                            formConfig.entries[0].entries.splice(6, 0, selectUIBranch);
                                        }
                                    });
                                }
                            };
                            staticContentSources.forEach (function (oneSource) {
                                selectCustomUI.value.push ({'v': oneSource, 'l': oneSource.name});
                            });
                            formConfig.entries[0].entries.splice(5, 0, selectCustomUI);
                        });
                    } else if (selected === 'false' && formConfig.entries[0].entries[5].name === 'selectCustomUI') {
                        if (formConfig.entries[0].entries[6] && formConfig.entries[0].entries[6].name === 'selectUIBranch') {
                            formConfig.entries[0].entries.splice(6, 1);
                            delete formConfig.formData.selectUIBranch;
                        }
                        formConfig.entries[0].entries.splice(5, 1);
                        delete formConfig.formData.selectCustomUI;
                    }
                }
            };
            formConfig.entries[0].entries.splice(4, 0, customUIEntry);

            for (var i = 0; i < formConfig.entries[1].entries.length; i++) {
                if (formConfig.entries[1].entries[i].name === 'defaultENVVAR') {
                    formConfig.entries[1].entries[i].value = formConfig.entries[1].entries[i].value.replace("%envName%", envCode);
                    formConfig.entries[1].entries[i].value = formConfig.entries[1].entries[i].value.replace("%profilePathToUse%", currentScope.profile);
                }
            }

            var options = {
                timeout: $timeout,
                form: formConfig,
                name: 'deployEnv',
                label: translation.deployEnvironment[LANG] + ' ' + envCode,
                actions: [
                    {
                        'type': 'submit',
                        'label': translation.submit[LANG],
                        'btn': 'primary',
                        'action': function(formData) {
                            if(!formData.controllers || formData.controllers < 1) {
                                $timeout(function() {
                                    alert(translation.youMustChooseLeastControllerDeployEnvironment[LANG]);
                                }, 100);
                            }
                            else {
                                currentScope.modalInstance.dismiss("ok");
                                var text = "
" + translation.deployingNew[LANG] + envCode + " Environment
";
                                text += "
" +  translation.deploying[LANG] + formData.controllers + translation.newControllersEnvironment[LANG] + envCode + ".
";
                                text += "
" + translation.doNotRefreshThisPageThisWillTakeFewMinutes[LANG] + "
";
                                text += "

";
                                jQuery('#overlay').html("

" + text + "
");
                                jQuery("#overlay .content").css("width", "40%").css("left", "30%");
                                overlay.show();

                                formData.owner = branchInfo.owner;
                                formData.repo = branchInfo.repo;

                                return deployEnvironment(formData);
                            }

                        }
                    },
                    {
                        'type': 'reset',
                        'label': translation.cancel[LANG],
                        'btn': 'danger',
                        'action': function() {
                            currentScope.modalInstance.dismiss('cancel');
                            currentScope.form.formData = {};
                        }
                    }
                ]
            };
            buildFormWithModal(currentScope, $modal, options);
        });

        function deployEnvironment(formData) {
            var branchObj = JSON.parse(formData.branch);
            var params = {
                'envCode': envCode,
                "number": formData.controllers,
                'owner': formData.owner,
                'repo': formData.repo,
                'branch': branchObj.name,
                'commit': branchObj.commit.sha,
                'useLocalSOAJS': formData.useLocalSOAJS,
                'imagePrefix': formData.ctrlImagePrefix
            };

            if(currentScope.isKubernetes) {
                params.isKubernetes = true;
            }

            if (formData.exposedPort) {
                params.exposedPort = formData.exposedPort;
            }

            if (formData.useCustomUI) {
                formData.selectUIBranch = JSON.parse(formData.selectUIBranch);
                formData.selectCustomUI = JSON.parse(formData.selectCustomUI);
                params.nginxConfig = {
                    customUIId: formData.selectCustomUI._id,
                    branch: formData.selectUIBranch.name,
                    commit: formData.selectUIBranch.commit.sha
                };
            }

            if(formData.variables && formData.variables !== ''){
                params.variables = formData.variables.split(",");
                for(var i =0; i < params.variables.length; i++){
                    params.variables[i] = params.variables[i].trim();
                }
            }

            if (haMode) {
                params.name = 'controller';
                params.haService = true;
                params.haCount = formData.controllers;
                params.memoryLimit = (formData.ctrlMemoryLimit * 1048576);
            }

            getSendDataFromServer(currentScope, ngDataApi, {
                "method": "send",
                "routeName": "/dashboard/hosts/deployController",
                "data": params
            }, function(error, response) {
                if(error) {
                    overlay.hide();
                    currentScope.form.displayAlert('danger', error.message);
                    return false;
                }
                else {
                    params.supportSSL = formData.supportSSL;
                    params.haCount = formData.nginxCount;
                    params.memoryLimit = (formData.nginxMemoryLimit * 1048576);
                    params.imagePrefix = formData.nginxImagePrefix;
                    getSendDataFromServer(currentScope, ngDataApi, {
                        "method": "send",
                        "routeName": "/dashboard/hosts/deployNginx",
                        "data": params
                    }, function(error, response) {
                        if(error) {
                            currentScope.form.displayAlert('danger', error.message);
                            overlay.hide();
                            return false;
                        }
                        else {
                            return true;
                            overlay.hide(function(){
                                if (!haMode) {
                                    currentScope.listNginxHosts(envCode);
                                    currentScope.listHosts(envCode);
                                }
                                else {
                                    currentScope.isDeploying = true;
                                    $timeout(function () {
                                        currentScope.listNginxServices();
                                        currentScope.listServices();
                                    }, 15000);
                                }
                            });
                        }
                    });
                }
            });
        }

        function listStaticContent (currentScope, cb) {
            getSendDataFromServer(currentScope, ngDataApi, {
                'method': 'send',
                'routeName': '/dashboard/staticContent/list'
            }, function (error, response) {
                if (error) {
                    currentScope.$parent.displayAlert('danger', error.code, true, 'dashboard', error.message);
                } else {
                    cb(response);
                }
            });
        }

        function getControllerBranches (currentScope, cb) {
            overlayLoading.show();
            getSendDataFromServer(currentScope, ngDataApi, {
                method: 'get',
                routeName: '/dashboard/gitAccounts/getBranches',
                params: {
                    name: 'controller',
                    type: 'service'
                }
            }, function (error, response) {
                overlayLoading.hide();
                if (error) {
                    currentScope.displayAlert('danger', error.code, true, 'dashboard', error.message);
                }
                else {
                    return cb (response);
                }
            });
        }
    }

    return {
        'deployEnvironment': deployEnvironment
    }
}]);
<commit_msg>bug fix, do not close form until response is true.<commit_after>"use strict";
var deployService = soajsApp.components;
deployService.service('deploySrv', ['ngDataApi', '$timeout', '$modal', function(ngDataApi, $timeout, $modal) {

    function deployEnvironment(currentScope, envCode, haMode) {
        var formConfig = angular.copy(environmentsConfig.form.deploy);
        var kubeConfig = environmentsConfig.deployer.kubernetes;

        currentScope.isKubernetes = (currentScope.deployer.selected.split('.')[1] === "kubernetes");
        if(currentScope.isKubernetes){
            formConfig.entries[0].entries[1].min = kubeConfig.minPort;
            formConfig.entries[0].entries[1].max = kubeConfig.maxPort;
            formConfig.entries[0].entries[1].fieldMsg += ". Kubernetes port range: " + kubeConfig.minPort + " - " + kubeConfig.maxPort;
        }

        getControllerBranches(currentScope, function (branchInfo) {
            for (var i = 0; i < formConfig.entries.length; i++) {
                if (formConfig.entries[i].name === 'controllers') {
                    var ctrlEntries = formConfig.entries[i].entries;
                    for (var j = 0; j < ctrlEntries.length; j++) {
                        if (ctrlEntries[j].name === 'branch') {
                            branchInfo.branches.forEach(function (oneBranch) {
                                delete oneBranch.commit.url;
                                ctrlEntries[j].value.push({'v': oneBranch, 'l': oneBranch.name});
                            });
                        }
                    }
                }
            }

            var customUIEntry = {
                'name': 'useCustomUI',
                'label': 'Do you want to bundle static content?',
                'type': 'radio',
                'value': [{'v': true, 'l': 'Yes'}, {'v': false, 'l': 'No', 'selected': true}],
                'required': true,
                'onAction': function (label, selected, formConfig) {
                    if (selected === 'true' && (!formConfig.entries[0].entries[5] || formConfig.entries[0].entries[5].name !== 'selectCustomUI')) {
                        listStaticContent(currentScope, function (staticContentSources) {
                            var selectCustomUI = {
                                'name': 'selectCustomUI',
                                'label': 'Choose Static Content',
                                'type': 'select',
                                'value': [],
                                'required': true,
                                'onAction': function (label, selected, formConfig) {
                                    var selectUIBranch = {
                                        'name': 'selectUIBranch',
                                        'label': 'Choose Static Content Branch',
                                        'type': 'select',
                                        'value': [],
                                        'required': true
                                    };
                                    selected = JSON.parse(selected);
                                    overlayLoading.show();
                                    getSendDataFromServer(currentScope, ngDataApi, {
                                        method: 'get',
                                        routeName: '/dashboard/gitAccounts/getBranches',
                                        params: {
                                            name: selected.name,
                                            type: 'static'
                                        }
                                    }, function (error, response) {
                                        overlayLoading.hide();
                                        if (error) {
                                            currentScope.generateNewMsg(envCode, 'danger', error.message);
                                        }
                                        else {
                                            response.branches.forEach(function (oneBranch) {
                                                selectUIBranch.value.push({'v': oneBranch, 'l': oneBranch.name});
                                            });

                                            formConfig.entries[0].entries.splice(6, 0, selectUIBranch);
                                        }
                                    });
                                }
                            };
                            staticContentSources.forEach (function (oneSource) {
                                selectCustomUI.value.push ({'v': oneSource, 'l': oneSource.name});
                            });
                            formConfig.entries[0].entries.splice(5, 0, selectCustomUI);
                        });
                    } else if (selected === 'false' && formConfig.entries[0].entries[5].name === 'selectCustomUI') {
                        if (formConfig.entries[0].entries[6] && formConfig.entries[0].entries[6].name === 'selectUIBranch') {
                            formConfig.entries[0].entries.splice(6, 1);
                            delete formConfig.formData.selectUIBranch;
                        }
                        formConfig.entries[0].entries.splice(5, 1);
                        delete formConfig.formData.selectCustomUI;
                    }
                }
            };
            formConfig.entries[0].entries.splice(4, 0, customUIEntry);

            for (var i = 0; i < formConfig.entries[1].entries.length; i++) {
                if (formConfig.entries[1].entries[i].name === 'defaultENVVAR') {
                    formConfig.entries[1].entries[i].value = formConfig.entries[1].entries[i].value.replace("%envName%", envCode);
                    formConfig.entries[1].entries[i].value = formConfig.entries[1].entries[i].value.replace("%profilePathToUse%", currentScope.profile);
                }
            }

            var options = {
                timeout: $timeout,
                form: formConfig,
                name: 'deployEnv',
                label: translation.deployEnvironment[LANG] + ' ' + envCode,
                actions: [
                    {
                        'type': 'submit',
                        'label': translation.submit[LANG],
                        'btn': 'primary',
                        'action': function(formData) {
                            if(!formData.controllers || formData.controllers < 1) {
                                $timeout(function() {
                                    alert(translation.youMustChooseLeastControllerDeployEnvironment[LANG]);
                                }, 100);
                            }
                            else {
                                var text = "
" + translation.deployingNew[LANG] + envCode + " Environment
";
                                text += "
" +  translation.deploying[LANG] + formData.controllers + translation.newControllersEnvironment[LANG] + envCode + ".
";
                                text += "
" + translation.doNotRefreshThisPageThisWillTakeFewMinutes[LANG] + "
";
                                text += "

";
                                jQuery('#overlay').html("

" + text + "
");
                                jQuery("#overlay .content").css("width", "40%").css("left", "30%");
                                overlay.show();

                                formData.owner = branchInfo.owner;
                                formData.repo = branchInfo.repo;

                                deployEnvironment(formData);
                            }

                        }
                    },
                    {
                        'type': 'reset',
                        'label': translation.cancel[LANG],
                        'btn': 'danger',
                        'action': function() {
                            currentScope.modalInstance.dismiss('cancel');
                            currentScope.form.formData = {};
                        }
                    }
                ]
            };
            buildFormWithModal(currentScope, $modal, options);
        });

        function deployEnvironment(formData) {
            var branchObj = JSON.parse(formData.branch);
            var params = {
                'envCode': envCode,
                "number": formData.controllers,
                'owner': formData.owner,
                'repo': formData.repo,
                'branch': branchObj.name,
                'commit': branchObj.commit.sha,
                'useLocalSOAJS': formData.useLocalSOAJS,
                'imagePrefix': formData.ctrlImagePrefix
            };

            if(currentScope.isKubernetes) {
                params.isKubernetes = true;
            }

            if (formData.exposedPort) {
                params.exposedPort = formData.exposedPort;
            }

            if (formData.useCustomUI) {
                formData.selectUIBranch = JSON.parse(formData.selectUIBranch);
                formData.selectCustomUI = JSON.parse(formData.selectCustomUI);
                params.nginxConfig = {
                    customUIId: formData.selectCustomUI._id,
                    branch: formData.selectUIBranch.name,
                    commit: formData.selectUIBranch.commit.sha
                };
            }

            if(formData.variables && formData.variables !== ''){
                params.variables = formData.variables.split(",");
                for(var i =0; i < params.variables.length; i++){
                    params.variables[i] = params.variables[i].trim();
                }
            }

            if (haMode) {
                params.name = 'controller';
                params.haService = true;
                params.haCount = formData.controllers;
                params.memoryLimit = (formData.ctrlMemoryLimit * 1048576);
            }

            getSendDataFromServer(currentScope, ngDataApi, {
                "method": "send",
                "routeName": "/dashboard/hosts/deployController",
                "data": params
            }, function(error, response) {
                if(error) {
                    overlay.hide();
                    currentScope.form.displayAlert('danger', error.message);
                }
                else {
                    params.supportSSL = formData.supportSSL;
                    params.haCount = formData.nginxCount;
                    params.memoryLimit = (formData.nginxMemoryLimit * 1048576);
                    params.imagePrefix = formData.nginxImagePrefix;
                    getSendDataFromServer(currentScope, ngDataApi, {
                        "method": "send",
                        "routeName": "/dashboard/hosts/deployNginx",
                        "data": params
                    }, function(error, response) {
                        if(error) {
                            currentScope.form.displayAlert('danger', error.message);
                            overlay.hide();
                        }
                        else {
                            currentScope.modalInstance.dismiss("ok");
                            overlay.hide(function(){
                                if (!haMode) {
                                    currentScope.listNginxHosts(envCode);
                                    currentScope.listHosts(envCode);
                                }
                                else {
                                    currentScope.isDeploying = true;
                                    $timeout(function () {
                                        currentScope.listNginxServices();
                                        currentScope.listServices();
                                    }, 15000);
                                }
                            });
                        }
                    });
                }
            });
        }

        function listStaticContent (currentScope, cb) {
            getSendDataFromServer(currentScope, ngDataApi, {
                'method': 'send',
                'routeName': '/dashboard/staticContent/list'
            }, function (error, response) {
                if (error) {
                    currentScope.$parent.displayAlert('danger', error.code, true, 'dashboard', error.message);
                } else {
                    cb(response);
                }
            });
        }

        function getControllerBranches (currentScope, cb) {
            overlayLoading.show();
            getSendDataFromServer(currentScope, ngDataApi, {
                method: 'get',
                routeName: '/dashboard/gitAccounts/getBranches',
                params: {
                    name: 'controller',
                    type: 'service'
                }
            }, function (error, response) {
                overlayLoading.hide();
                if (error) {
                    currentScope.displayAlert('danger', error.code, true, 'dashboard', error.message);
                }
                else {
                    return cb (response);
                }
            });
        }
    }

    return {
        'deployEnvironment': deployEnvironment
    }
}]);
<|endoftext|>


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

(function($) {

  function startEditing(elem, options) {
    var editable = $(elem);
    var origHtml = editable.html();
    var origText = options.populate($.trim(editable.text()));

    if (!options.begin.apply(elem, [origText])) {
      return;
    }

    var input = options.createInput.apply(elem, [origText])
      .addClass("editinline").val(origText)
      .dblclick(function() { return false; })
      .keydown(function(evt) {
        switch (evt.keyCode) {
          case 13: { // return
            if (!input.is("textarea")) applyChange(evt.keyCode);
            break;
          }
          case 27: { // escape
            cancelChange(evt.keyCode);
            break;
          }
          case 9: { // tab
            if (!input.is("textarea")) {
              applyChange(evt.keyCode);
              return false;
            }
          }
        }
      });
    if (options.acceptOnBlur) {
      input.blur(function() {
        return applyChange();
      });
    }

    function applyChange(keyCode) {
      var newText = input.val();
      if (newText == origText) {
        cancelChange(keyCode);
        return true;
      }
      if ((!options.allowEmpty && !newText.length) ||
          !options.validate.apply(elem, [newText, origText])) {
        input.addClass("invalid");
        return false;
      }
      input.remove();
      tools.remove();
      options.accept.apply(elem, [newText, origText]);
      editable.removeClass("editinline-container");
      options.end.apply(elem, [keyCode]);
      return true;
    }

    function cancelChange(keyCode) {
      options.cancel.apply(elem, [origText]);
      editable.html(origHtml).removeClass("editinline-container");
      options.end.apply(elem, [keyCode]);
    }

    var tools = $("");
    $("<button type='button' class='apply'></button>")
      .text(options.acceptLabel).click(applyChange).appendTo(tools);
    $("<button type='button' class='cancel'></button>")
      .text(options.cancelLabel).click(cancelChange).appendTo(tools)

    editable.html("").append(tools).append(input)
      .addClass("editinline-container");
    options.prepareInput.apply(elem, [input[0]]);
    input.each(function() { this.focus(); this.select(); });
  }

  $.fn.makeEditable = function(options) {
    options = $.extend({
      allowEmpty: true,
      acceptLabel: "",
      cancelLabel: "",
      toolTip: "Click to edit",
      acceptOnBlur: true,

      // callbacks
      begin: function() { return true },
      accept: function(newValue, oldValue) {},
      cancel: function(oldValue) {},
      createInput: function(value) { return $("<input type='text'>") },
      prepareInput: function(input) {},
      end: function(keyCode) {},
      populate: function(value) { return value },
      validate: function() { return true }
    }, options || {});

    return this.each(function() {
      $(this).attr("title", options.toolTip).click(function() {
        startEditing(this, options);
      });
    });
  }

})(jQuery);
<commit_msg>Revert "click to edit config in Futon instead of double click. thanks Aaron Miller" Turns out this has some issues. Getting Futon to work nicely on tap-style mobile browsers will require a deeper look.<commit_after>// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.

(function($) {

  function startEditing(elem, options) {
    var editable = $(elem);
    var origHtml = editable.html();
    var origText = options.populate($.trim(editable.text()));

    if (!options.begin.apply(elem, [origText])) {
      return;
    }

    var input = options.createInput.apply(elem, [origText])
      .addClass("editinline").val(origText)
      .dblclick(function() { return false; })
      .keydown(function(evt) {
        switch (evt.keyCode) {
          case 13: { // return
            if (!input.is("textarea")) applyChange(evt.keyCode);
            break;
          }
          case 27: { // escape
            cancelChange(evt.keyCode);
            break;
          }
          case 9: { // tab
            if (!input.is("textarea")) {
              applyChange(evt.keyCode);
              return false;
            }
          }
        }
      });
    if (options.acceptOnBlur) {
      input.blur(function() {
        return applyChange();
      });
    }

    function applyChange(keyCode) {
      var newText = input.val();
      if (newText == origText) {
        cancelChange(keyCode);
        return true;
      }
      if ((!options.allowEmpty && !newText.length) ||
          !options.validate.apply(elem, [newText, origText])) {
        input.addClass("invalid");
        return false;
      }
      input.remove();
      tools.remove();
      options.accept.apply(elem, [newText, origText]);
      editable.removeClass("editinline-container");
      options.end.apply(elem, [keyCode]);
      return true;
    }

    function cancelChange(keyCode) {
      options.cancel.apply(elem, [origText]);
      editable.html(origHtml).removeClass("editinline-container");
      options.end.apply(elem, [keyCode]);
    }

    var tools = $("");
    $("<button type='button' class='apply'></button>")
      .text(options.acceptLabel).click(applyChange).appendTo(tools);
    $("<button type='button' class='cancel'></button>")
      .text(options.cancelLabel).click(cancelChange).appendTo(tools)

    editable.html("").append(tools).append(input)
      .addClass("editinline-container");
    options.prepareInput.apply(elem, [input[0]]);
    input.each(function() { this.focus(); this.select(); });
  }

  $.fn.makeEditable = function(options) {
    options = $.extend({
      allowEmpty: true,
      acceptLabel: "",
      cancelLabel: "",
      toolTip: "Double click to edit",
      acceptOnBlur: true,

      // callbacks
      begin: function() { return true },
      accept: function(newValue, oldValue) {},
      cancel: function(oldValue) {},
      createInput: function(value) { return $("<input type='text'>") },
      prepareInput: function(input) {},
      end: function(keyCode) {},
      populate: function(value) { return value },
      validate: function() { return true }
    }, options || {});

    return this.each(function() {
      $(this).attr("title", options.toolTip).dblclick(function() {
        startEditing(this, options);
      });
    });
  }

})(jQuery);
<|endoftext|>


<commit_before>/**
  This mixin provides `blank` and `present` to determine whether properties are
  there, accounting for more cases than just null and undefined.

  @class Discourse.Presence
  @extends Ember.Mixin
  @namespace Discourse
  @module Discourse
**/
Discourse.Presence = Em.Mixin.create({

  /**
    Returns whether a property is blank. It considers empty arrays, string, objects, undefined and null
    to be blank, otherwise true.

    @method blank
    @param {String} name the name of the property we want to check
    @return {Boolean}
  */
  blank: function(name) {
    var prop;
    prop = this.get(name);
    if (!prop) return true;

    switch (typeof prop) {
      case "string":
        return prop.trim().isBlank();
      case "object":
        return Object.isEmpty(prop);
    }
    return false;
  },

  /**
    Returns whether a property is present. A present property is the opposite of a `blank` one.

    @method present
    @param {String} name the name of the property we want to check
    @return {Boolean}
  */
  present: function(name) {
    return !this.blank(name);
  }
});

<commit_msg>slight optimisation<commit_after>/**
  This mixin provides `blank` and `present` to determine whether properties are
  there, accounting for more cases than just null and undefined.

  @class Discourse.Presence
  @extends Ember.Mixin
  @namespace Discourse
  @module Discourse
**/
Discourse.Presence = Em.Mixin.create({

  /**
    Returns whether a property is blank. It considers empty arrays, string, objects, undefined and null
    to be blank, otherwise true.

    @method blank
    @param {String} name the name of the property we want to check
    @return {Boolean}
  */
  blank: function(name) {
    var prop;
    prop = this[name] || this.get(name);
    if (!prop) return true;

    switch (typeof prop) {
      case "string":
        return prop.trim().isBlank();
      case "object":
        return Object.isEmpty(prop);
    }
    return false;
  },

  /**
    Returns whether a property is present. A present property is the opposite of a `blank` one.

    @method present
    @param {String} name the name of the property we want to check
    @return {Boolean}
  */
  present: function(name) {
    return !this.blank(name);
  }
});

<|endoftext|>


<commit_before>/**
 h Created by ksinger on 23.09.2015.
 *
 * Contains a list of actions to be used with the dispatcher and documentation
 * for their expected payloads.
 *
 * # Redux Primer - Actions
 *
 * Actions are small objects like:
 *
 * `{type: 'someaction', payload: {...}}`
 *
 * that are usually created via action-creators (ACs), e.g.:
 *
 * `function someaction(args) { return { type: 'someaction', payload: args }}`
 *
 * and then passed on to the reducer via `redux.dispatch(action)`.
 *
 * *Note:* The calls to `$ngRedux.connect` wrap the ACs in this call to `dispatch`
 *
 * # Best Practices
 *
 * Even though it's possible to have ACs trigger multiple ACs (which is
 * necessary asynchronous actions), try avoiding that. All actions are
 * broadcasted to all reducers anyway.  Mostly it's a symptom of actions
 * that aren't high-level enough. (high-level: `publish`,
 * low-level: `inDraftSetPublishPending`).
 *
 * ACs function is to do simple data-processing that is needed by multiple
 * reducers (e.g. creating the post-publish messages that are needed by
 * the drafts-reducer as well) and dealing with side-effects (e.g. routing,
 * http-calls)
 *
 * As a rule of thumb the lion's share of all processing should happen
 * in the reducers.
 */
// <utils>

import { tree2constants } from "../utils.js";
import { hierarchy2Creators } from "./action-utils.js";

import {
  needCreate,
  createWhatsNew,
  createWhatsAround,
} from "./create-need-action.js";

import {
  needsConnect,
  fetchUnloadedNeeds,
  fetchSuggested,
  needsClose,
  needsOpen,
  needsClosedBySystem,
} from "./needs-actions.js";

import {
  stateBack,
  stateGoAbs,
  stateGoCurrent,
  stateGoDefault,
  stateGoKeepParams,
  stateGoResetParams,
} from "./cstm-router-actions.js";

// </utils>

// <action-creators>

import {
  accountLogin,
  accountLogout,
  accountRegister,
  accountTransfer,
  accountAcceptDisclaimer,
  accountAcceptTermsOfService,
  accountVerifyEmailAddress,
  accountResendVerificationEmail,
  reconnect,
} from "./account-actions.js";

import * as cnct from "./connections-actions.js";
import * as messages from "./messages-actions.js";
import * as configActions from "./config-actions.js";

import { pageLoadAction } from "./load-action.js";
import { stateGo, stateReload } from "redux-ui-router";
import { createPersona, reviewPersona } from "./persona-actions.js";

// </action-creators>

/**
 * all values equal to this string will be replaced by action-creators that simply
 * passes it's argument on as payload on to the reducers
 */
const INJ_DEFAULT = "INJECT_DEFAULT_ACTION_CREATOR";
const actionHierarchy = {
  initialPageLoad: pageLoadAction,
  initialLoadFinished: INJ_DEFAULT,
  connections: {
    open: cnct.connectionsOpen,
    connectAdHoc: cnct.connectionsConnectAdHoc,
    close: cnct.connectionsClose,
    closeRemote: cnct.connectionsCloseRemote,
    rate: cnct.connectionsRate,
    sendChatMessage: cnct.connectionsChatMessage,
    sendChatMessageClaimOnSuccess: cnct.connectionsChatMessageClaimOnSuccess,
    sendChatMessageRefreshDataOnSuccess: INJ_DEFAULT, //will be dispatched solely within sendChatMessage (only if chatMessage that is sent contains References)
    sendChatMessageFailed: INJ_DEFAULT,
    showLatestMessages: cnct.showLatestMessages,
    showMoreMessages: cnct.showMoreMessages,
    markAsRead: INJ_DEFAULT,
    setLoadingAgreementData: INJ_DEFAULT,
    setLoadingPetriNetData: INJ_DEFAULT,
    setLoadingMessages: INJ_DEFAULT,
    showAgreementData: INJ_DEFAULT,
    showPetriNetData: INJ_DEFAULT,
    setMultiSelectType: INJ_DEFAULT,
    updateAgreementData: INJ_DEFAULT, //cnct.loadAgreementData,
    updatePetriNetData: INJ_DEFAULT,

    fetchActiveUrisLoading: INJ_DEFAULT,
    fetchActive: INJ_DEFAULT,
  },
  needs: {
    received: INJ_DEFAULT,
    connectionsReceived: INJ_DEFAULT,
    clean: INJ_DEFAULT,
    create: needCreate,
    whatsNew: createWhatsNew,
    whatsAround: createWhatsAround,
    createSuccessful: INJ_DEFAULT,
    reopen: needsOpen,
    close: needsClose,
    closedBySystem: needsClosedBySystem,
    failed: INJ_DEFAULT,
    connect: needsConnect,
    fetchUnloadedNeeds: fetchUnloadedNeeds,
    fetchSuggested: fetchSuggested,

    fetchOwnedInactiveUris: INJ_DEFAULT,
    fetchOwnedInactiveUrisLoading: INJ_DEFAULT,
    fetchOwnedActiveUris: INJ_DEFAULT,
    fetchTheirUrisLoading: INJ_DEFAULT,

    fetchOwned: INJ_DEFAULT,
    fetchTheirs: INJ_DEFAULT,
  },
  personas: {
    create: createPersona,
    createSuccessful: INJ_DEFAULT,
    review: reviewPersona,

    fetchTheirs: INJ_DEFAULT,
  },
  router: {
    stateGo, // only overwrites parameters that are explicitly mentioned, unless called without queryParams object (which also resets "pervasive" parameters, that shouldn't be removed
    stateGoAbs, // reset's all parameters but the one passed as arguments
    stateGoResetParams, // goes to new state and resets all parameters (except for "pervasive" ones like `privateId`)
    stateGoKeepParams, // goes to new state and keeps listed parameters at their current values
    stateGoCurrent,
    stateGoDefault,
    stateReload,
    //stateTransitionTo, // should not be used directly
    back: stateBack,
    accessedNonLoadedPost: INJ_DEFAULT, //dispatched in configRouting.js
  },

  /**
   * Server triggered interactions (aka received messages)
   */
  messages: {
    /* websocket messages, e.g. post-creation, chatting */
    //TODO get rid of send and rename to receivedMessage

    send: INJ_DEFAULT, //TODO this should be part of proper, user-story-level actions (e.g. need.publish or sendCnctMsg)

    /*
         * posting things to the server should be optimistic and assume
         * success that is rolled back in case of a failure or timeout.
         */

    create: {
      success: messages.successfulCreate,
      //TODO failure: messages.failedCreate
    },
    open: {
      successRemote: INJ_DEFAULT, //2nd successResponse
      successOwn: INJ_DEFAULT, //1st successResponse
      failure: INJ_DEFAULT,
      //TODO failure: messages.failedOpen
    },
    close: {
      //TODO: NAME SEEMS GENERIC EVEN THOUGH IT IS ONLY USED FOR CLOSING CONNECITONS; REFACTOR THIS SOMEDAY
      success: messages.successfulCloseConnection,
      //TODO failure: messages.failedClose
    },
    connect: {
      //success: messages.successfulConnect,
      successRemote: INJ_DEFAULT, //2nd successResponse
      successOwn: INJ_DEFAULT, //1st successResponse
      failure: INJ_DEFAULT,
    },
    chatMessage: {
      //success: messages.successfulChatMessage,
      successRemote: INJ_DEFAULT, //2nd successResponse
      successOwn: INJ_DEFAULT, //1st successResponse
      failure: INJ_DEFAULT,
    },
    closeNeed: {
      success: messages.successfulCloseNeed,
      failure: messages.failedCloseNeed,
    },
    reopenNeed: {
      success: messages.successfulReopenNeed,
      failure: messages.failedReopenNeed,
    },
    markAsRead: INJ_DEFAULT,
    messageStatus: {
      markAsProposed: messages.markAsProposed,
      markAsClaimed: messages.markAsClaimed,
      markAsRetracted: messages.markAsRetracted,
      markAsRejected: messages.markAsRejected,
      markAsAccepted: messages.markAsAccepted,
      markAsCancelled: messages.markAsCancelled,
      markAsCancellationPending: messages.markAsCancellationPending,
    },
    viewState: {
      markAsCollapsed: INJ_DEFAULT,
      markAsSelected: INJ_DEFAULT,
      markShowActions: INJ_DEFAULT,
      markExpandReference: INJ_DEFAULT,
    },
    updateMessageStatus: messages.updateMessageStatus,
    processConnectionMessage: messages.processConnectionMessage,
    processAgreementMessage: messages.processAgreementMessage,
    needMessageReceived: messages.needMessageReceived,
    processConnectMessage: messages.processConnectMessage,
    connectMessageReceived: INJ_DEFAULT,
    connectMessageSent: INJ_DEFAULT,
    processHintMessage: messages.processHintMessage,
    hintMessageReceived: INJ_DEFAULT,
    openMessageReceived: INJ_DEFAULT,
    openMessageSent: INJ_DEFAULT,
    processOpenMessage: messages.processOpenMessage,

    // register a fully prepared action object to be dispatched
    // after a specific message (identified by URI)  has been processed
    // (when the respective success message is processed)
    dispatchActionOn: {
      // registers the action (in action.actionToDispatch)
      registerSuccessOwn: INJ_DEFAULT,
      registerFailureOwn: INJ_DEFAULT,
      registerSuccessRemote: INJ_DEFAULT,
      registerFailureRemote: INJ_DEFAULT,
      // the action creator dispatches the registered actions
      successOwn: messages.dispatchActionOnSuccessOwn,
      successRemote: messages.dispatchActionOnSuccessRemote,
      // failure actions clear the list of registered success actions
      // and vice versa
      failureOwn: messages.dispatchActionOnSuccessOwn,
      failureRemote: messages.dispatchActionOnSuccessOwn,
    },

    waitingForAnswer: INJ_DEFAULT,
  },
  account: {
    login: accountLogin,
    loginStarted: INJ_DEFAULT,
    loginFinished: INJ_DEFAULT,
    loginFailed: INJ_DEFAULT,

    logout: accountLogout,
    logoutStarted: INJ_DEFAULT,

    register: accountRegister,
    transfer: accountTransfer,
    registerFailed: INJ_DEFAULT,

    acceptDisclaimer: accountAcceptDisclaimer,
    acceptDisclaimerSuccess: INJ_DEFAULT,

    acceptTermsOfService: accountAcceptTermsOfService,
    acceptTermsOfServiceStarted: INJ_DEFAULT,
    acceptTermsOfServiceSuccess: INJ_DEFAULT,
    acceptTermsOfServiceFailed: INJ_DEFAULT,

    verifyEmailAddress: accountVerifyEmailAddress,
    verifyEmailAddressStarted: INJ_DEFAULT,
    verifyEmailAddressSuccess: INJ_DEFAULT,
    verifyEmailAddressFailed: INJ_DEFAULT,

    resendVerificationEmail: accountResendVerificationEmail,
    resendVerificationEmailStarted: INJ_DEFAULT,
    resendVerificationEmailSuccess: INJ_DEFAULT,
    resendVerificationEmailFailed: INJ_DEFAULT,
  },

  geoLocationDenied: INJ_DEFAULT,
  lostConnection: INJ_DEFAULT,
  failedToGetLocation: INJ_DEFAULT,
  upgradeHttpSession: INJ_DEFAULT,

  reconnect: {
    start: reconnect,
    success: INJ_DEFAULT,
    startingToLoadConnectionData: INJ_DEFAULT,
    receivedConnectionData: INJ_DEFAULT,
    connectionFailedToLoad: INJ_DEFAULT,
  },

  view: {
    toggleRdf: INJ_DEFAULT,

    toggleClosedNeeds: INJ_DEFAULT,

    showMainMenu: INJ_DEFAULT,
    hideMainMenu: INJ_DEFAULT,

    toggleAddMessageContent: INJ_DEFAULT,
    hideAddMessageContent: INJ_DEFAULT,

    selectAddMessageContent: INJ_DEFAULT,
    removeAddMessageContent: INJ_DEFAULT,

    showModalDialog: INJ_DEFAULT,
    hideModalDialog: INJ_DEFAULT,

    clearLoginError: INJ_DEFAULT,
    clearRegisterError: INJ_DEFAULT,
  },

  toasts: {
    delete: INJ_DEFAULT,
    test: INJ_DEFAULT,
    push: INJ_DEFAULT,
  },
  config: {
    init: configActions.configInit,
    update: configActions.update,
  },
  tick: startTicking,
};

//as string constans, e.g. actionTypes.needs.close === "needs.close"
export const actionTypes = tree2constants(actionHierarchy);

/**
 * actionCreators are functions that take the payload and output
 * an action object, thus prebinding the action-type.
 * This object follows the structure of the actionTypes-object,
 * but is flattened for use with ng-redux. Thus calling
 * `$ngRedux.dispatch(actionCreators.drafts__new(myDraft))` will trigger an action
 * `{type: actionTypes.drafts.new, payload: myDraft}`
 *
 * e.g.:
 *
 * ```javascript
 * function newDraft(draft) {
 *   return { type: 'draft.new', payload: draft }
 * }
 * ```
 */
export const actionCreators = hierarchy2Creators(actionHierarchy);

/*
 * TODO deletme; for debugging
 */
window.actionCreators4Dbg = actionCreators;
window.actionTypes4Dbg = actionTypes;

//////////// STUFF THAT SHOULD BE IN OTHER FILES BELOW //////////////////

export function startTicking() {
  return dispatch =>
    setInterval(
      () => dispatch({ type: actionTypes.tick, payload: Date.now() }),
      60000
    );
}
<commit_msg>add reducer account.store -> for storing the user in the state<commit_after>/**
 h Created by ksinger on 23.09.2015.
 *
 * Contains a list of actions to be used with the dispatcher and documentation
 * for their expected payloads.
 *
 * # Redux Primer - Actions
 *
 * Actions are small objects like:
 *
 * `{type: 'someaction', payload: {...}}`
 *
 * that are usually created via action-creators (ACs), e.g.:
 *
 * `function someaction(args) { return { type: 'someaction', payload: args }}`
 *
 * and then passed on to the reducer via `redux.dispatch(action)`.
 *
 * *Note:* The calls to `$ngRedux.connect` wrap the ACs in this call to `dispatch`
 *
 * # Best Practices
 *
 * Even though it's possible to have ACs trigger multiple ACs (which is
 * necessary asynchronous actions), try avoiding that. All actions are
 * broadcasted to all reducers anyway.  Mostly it's a symptom of actions
 * that aren't high-level enough. (high-level: `publish`,
 * low-level: `inDraftSetPublishPending`).
 *
 * ACs function is to do simple data-processing that is needed by multiple
 * reducers (e.g. creating the post-publish messages that are needed by
 * the drafts-reducer as well) and dealing with side-effects (e.g. routing,
 * http-calls)
 *
 * As a rule of thumb the lion's share of all processing should happen
 * in the reducers.
 */
// <utils>

import { tree2constants } from "../utils.js";
import { hierarchy2Creators } from "./action-utils.js";

import {
  needCreate,
  createWhatsNew,
  createWhatsAround,
} from "./create-need-action.js";

import {
  needsConnect,
  fetchUnloadedNeeds,
  fetchSuggested,
  needsClose,
  needsOpen,
  needsClosedBySystem,
} from "./needs-actions.js";

import {
  stateBack,
  stateGoAbs,
  stateGoCurrent,
  stateGoDefault,
  stateGoKeepParams,
  stateGoResetParams,
} from "./cstm-router-actions.js";

// </utils>

// <action-creators>

import {
  accountLogin,
  accountLogout,
  accountRegister,
  accountTransfer,
  accountAcceptDisclaimer,
  accountAcceptTermsOfService,
  accountVerifyEmailAddress,
  accountResendVerificationEmail,
  reconnect,
} from "./account-actions.js";

import * as cnct from "./connections-actions.js";
import * as messages from "./messages-actions.js";
import * as configActions from "./config-actions.js";

import { pageLoadAction } from "./load-action.js";
import { stateGo, stateReload } from "redux-ui-router";
import { createPersona, reviewPersona } from "./persona-actions.js";

// </action-creators>

/**
 * all values equal to this string will be replaced by action-creators that simply
 * passes it's argument on as payload on to the reducers
 */
const INJ_DEFAULT = "INJECT_DEFAULT_ACTION_CREATOR";
const actionHierarchy = {
  initialPageLoad: pageLoadAction,
  initialLoadFinished: INJ_DEFAULT,
  connections: {
    open: cnct.connectionsOpen,
    connectAdHoc: cnct.connectionsConnectAdHoc,
    close: cnct.connectionsClose,
    closeRemote: cnct.connectionsCloseRemote,
    rate: cnct.connectionsRate,
    sendChatMessage: cnct.connectionsChatMessage,
    sendChatMessageClaimOnSuccess: cnct.connectionsChatMessageClaimOnSuccess,
    sendChatMessageRefreshDataOnSuccess: INJ_DEFAULT, //will be dispatched solely within sendChatMessage (only if chatMessage that is sent contains References)
    sendChatMessageFailed: INJ_DEFAULT,
    showLatestMessages: cnct.showLatestMessages,
    showMoreMessages: cnct.showMoreMessages,
    markAsRead: INJ_DEFAULT,
    setLoadingAgreementData: INJ_DEFAULT,
    setLoadingPetriNetData: INJ_DEFAULT,
    setLoadingMessages: INJ_DEFAULT,
    showAgreementData: INJ_DEFAULT,
    showPetriNetData: INJ_DEFAULT,
    setMultiSelectType: INJ_DEFAULT,
    updateAgreementData: INJ_DEFAULT, //cnct.loadAgreementData,
    updatePetriNetData: INJ_DEFAULT,

    fetchActiveUrisLoading: INJ_DEFAULT,
    fetchActive: INJ_DEFAULT,
  },
  needs: {
    received: INJ_DEFAULT,
    connectionsReceived: INJ_DEFAULT,
    clean: INJ_DEFAULT,
    create: needCreate,
    whatsNew: createWhatsNew,
    whatsAround: createWhatsAround,
    createSuccessful: INJ_DEFAULT,
    reopen: needsOpen,
    close: needsClose,
    closedBySystem: needsClosedBySystem,
    failed: INJ_DEFAULT,
    connect: needsConnect,
    fetchUnloadedNeeds: fetchUnloadedNeeds,
    fetchSuggested: fetchSuggested,

    fetchOwnedInactiveUris: INJ_DEFAULT,
    fetchOwnedInactiveUrisLoading: INJ_DEFAULT,
    fetchOwnedActiveUris: INJ_DEFAULT,
    fetchTheirUrisLoading: INJ_DEFAULT,

    fetchOwned: INJ_DEFAULT,
    fetchTheirs: INJ_DEFAULT,
  },
  personas: {
    create: createPersona,
    createSuccessful: INJ_DEFAULT,
    review: reviewPersona,

    fetchTheirs: INJ_DEFAULT,
  },
  router: {
    stateGo, // only overwrites parameters that are explicitly mentioned, unless called without queryParams object (which also resets "pervasive" parameters, that shouldn't be removed
    stateGoAbs, // reset's all parameters but the one passed as arguments
    stateGoResetParams, // goes to new state and resets all parameters (except for "pervasive" ones like `privateId`)
    stateGoKeepParams, // goes to new state and keeps listed parameters at their current values
    stateGoCurrent,
    stateGoDefault,
    stateReload,
    //stateTransitionTo, // should not be used directly
    back: stateBack,
    accessedNonLoadedPost: INJ_DEFAULT, //dispatched in configRouting.js
  },

  /**
   * Server triggered interactions (aka received messages)
   */
  messages: {
    /* websocket messages, e.g. post-creation, chatting */
    //TODO get rid of send and rename to receivedMessage

    send: INJ_DEFAULT, //TODO this should be part of proper, user-story-level actions (e.g. need.publish or sendCnctMsg)

    /*
         * posting things to the server should be optimistic and assume
         * success that is rolled back in case of a failure or timeout.
         */

    create: {
      success: messages.successfulCreate,
      //TODO failure: messages.failedCreate
    },
    open: {
      successRemote: INJ_DEFAULT, //2nd successResponse
      successOwn: INJ_DEFAULT, //1st successResponse
      failure: INJ_DEFAULT,
      //TODO failure: messages.failedOpen
    },
    close: {
      //TODO: NAME SEEMS GENERIC EVEN THOUGH IT IS ONLY USED FOR CLOSING CONNECITONS; REFACTOR THIS SOMEDAY
      success: messages.successfulCloseConnection,
      //TODO failure: messages.failedClose
    },
    connect: {
      //success: messages.successfulConnect,
      successRemote: INJ_DEFAULT, //2nd successResponse
      successOwn: INJ_DEFAULT, //1st successResponse
      failure: INJ_DEFAULT,
    },
    chatMessage: {
      //success: messages.successfulChatMessage,
      successRemote: INJ_DEFAULT, //2nd successResponse
      successOwn: INJ_DEFAULT, //1st successResponse
      failure: INJ_DEFAULT,
    },
    closeNeed: {
      success: messages.successfulCloseNeed,
      failure: messages.failedCloseNeed,
    },
    reopenNeed: {
      success: messages.successfulReopenNeed,
      failure: messages.failedReopenNeed,
    },
    markAsRead: INJ_DEFAULT,
    messageStatus: {
      markAsProposed: messages.markAsProposed,
      markAsClaimed: messages.markAsClaimed,
      markAsRetracted: messages.markAsRetracted,
      markAsRejected: messages.markAsRejected,
      markAsAccepted: messages.markAsAccepted,
      markAsCancelled: messages.markAsCancelled,
      markAsCancellationPending: messages.markAsCancellationPending,
    },
    viewState: {
      markAsCollapsed: INJ_DEFAULT,
      markAsSelected: INJ_DEFAULT,
      markShowActions: INJ_DEFAULT,
      markExpandReference: INJ_DEFAULT,
    },
    updateMessageStatus: messages.updateMessageStatus,
    processConnectionMessage: messages.processConnectionMessage,
    processAgreementMessage: messages.processAgreementMessage,
    needMessageReceived: messages.needMessageReceived,
    processConnectMessage: messages.processConnectMessage,
    connectMessageReceived: INJ_DEFAULT,
    connectMessageSent: INJ_DEFAULT,
    processHintMessage: messages.processHintMessage,
    hintMessageReceived: INJ_DEFAULT,
    openMessageReceived: INJ_DEFAULT,
    openMessageSent: INJ_DEFAULT,
    processOpenMessage: messages.processOpenMessage,

    // register a fully prepared action object to be dispatched
    // after a specific message (identified by URI)  has been processed
    // (when the respective success message is processed)
    dispatchActionOn: {
      // registers the action (in action.actionToDispatch)
      registerSuccessOwn: INJ_DEFAULT,
      registerFailureOwn: INJ_DEFAULT,
      registerSuccessRemote: INJ_DEFAULT,
      registerFailureRemote: INJ_DEFAULT,
      // the action creator dispatches the registered actions
      successOwn: messages.dispatchActionOnSuccessOwn,
      successRemote: messages.dispatchActionOnSuccessRemote,
      // failure actions clear the list of registered success actions
      // and vice versa
      failureOwn: messages.dispatchActionOnSuccessOwn,
      failureRemote: messages.dispatchActionOnSuccessOwn,
    },

    waitingForAnswer: INJ_DEFAULT,
  },
  account: {
    login: accountLogin,
    loginStarted: INJ_DEFAULT, //will only be dispatched on login not on page reload
    loginFinished: INJ_DEFAULT, //will be dispatched when data has been loaded on login not on page reload
    loginFailed: INJ_DEFAULT,

    store: INJ_DEFAULT, //stores the retrieved account in the state

    logout: accountLogout,
    logoutStarted: INJ_DEFAULT,

    register: accountRegister,
    transfer: accountTransfer,
    registerFailed: INJ_DEFAULT,

    acceptDisclaimer: accountAcceptDisclaimer,
    acceptDisclaimerSuccess: INJ_DEFAULT,

    acceptTermsOfService: accountAcceptTermsOfService,
    acceptTermsOfServiceStarted: INJ_DEFAULT,
    acceptTermsOfServiceSuccess: INJ_DEFAULT,
    acceptTermsOfServiceFailed: INJ_DEFAULT,

    verifyEmailAddress: accountVerifyEmailAddress,
    verifyEmailAddressStarted: INJ_DEFAULT,
    verifyEmailAddressSuccess: INJ_DEFAULT,
    verifyEmailAddressFailed: INJ_DEFAULT,

    resendVerificationEmail: accountResendVerificationEmail,
    resendVerificationEmailStarted: INJ_DEFAULT,
    resendVerificationEmailSuccess: INJ_DEFAULT,
    resendVerificationEmailFailed: INJ_DEFAULT,
  },

  geoLocationDenied: INJ_DEFAULT,
  lostConnection: INJ_DEFAULT,
  failedToGetLocation: INJ_DEFAULT,
  upgradeHttpSession: INJ_DEFAULT,

  reconnect: {
    start: reconnect,
    success: INJ_DEFAULT,
    startingToLoadConnectionData: INJ_DEFAULT,
    receivedConnectionData: INJ_DEFAULT,
    connectionFailedToLoad: INJ_DEFAULT,
  },

  view: {
    toggleRdf: INJ_DEFAULT,

    toggleClosedNeeds: INJ_DEFAULT,

    showMainMenu: INJ_DEFAULT,
    hideMainMenu: INJ_DEFAULT,

    toggleAddMessageContent: INJ_DEFAULT,
    hideAddMessageContent: INJ_DEFAULT,

    selectAddMessageContent: INJ_DEFAULT,
    removeAddMessageContent: INJ_DEFAULT,

    showModalDialog: INJ_DEFAULT,
    hideModalDialog: INJ_DEFAULT,

    clearLoginError: INJ_DEFAULT,
    clearRegisterError: INJ_DEFAULT,
  },

  toasts: {
    delete: INJ_DEFAULT,
    test: INJ_DEFAULT,
    push: INJ_DEFAULT,
  },
  config: {
    init: configActions.configInit,
    update: configActions.update,
  },
  tick: startTicking,
};

//as string constans, e.g. actionTypes.needs.close === "needs.close"
export const actionTypes = tree2constants(actionHierarchy);

/**
 * actionCreators are functions that take the payload and output
 * an action object, thus prebinding the action-type.
 * This object follows the structure of the actionTypes-object,
 * but is flattened for use with ng-redux. Thus calling
 * `$ngRedux.dispatch(actionCreators.drafts__new(myDraft))` will trigger an action
 * `{type: actionTypes.drafts.new, payload: myDraft}`
 *
 * e.g.:
 *
 * ```javascript
 * function newDraft(draft) {
 *   return { type: 'draft.new', payload: draft }
 * }
 * ```
 */
export const actionCreators = hierarchy2Creators(actionHierarchy);

/*
 * TODO deletme; for debugging
 */
window.actionCreators4Dbg = actionCreators;
window.actionTypes4Dbg = actionTypes;

//////////// STUFF THAT SHOULD BE IN OTHER FILES BELOW //////////////////

export function startTicking() {
  return dispatch =>
    setInterval(
      () => dispatch({ type: actionTypes.tick, payload: Date.now() }),
      60000
    );
}
<|endoftext|>


<commit_before>var coge = window.coge = (function(ns) {
    ns.utils = {
        ascending: function(a, b) {
            return a < b ? -1 : a > b ? 1 : 0;
        },

        descending: function(a, b) {
            return a > b ? -1 : a < b ? 1 : 0;
        },

        open: function(link) {
            window.open(link, "_self");
        },
        shuffle: function(array) {
            var copy = [], n = array.length, i = 0;

            while (n) {
                i = Math.floor(Math.random() * array.length);
                if (i in array) {
                    copy.push(array[i]);
                    delete array[i];
                    n--;
                }
            };

            return copy;
        }
    };

    return ns;
})(coge || {});
<commit_msg>fix shuffle to run in linear time<commit_after>var coge = window.coge = (function(ns) {
    ns.utils = {
        ascending: function(a, b) {
            return a < b ? -1 : a > b ? 1 : 0;
        },

        descending: function(a, b) {
            return a > b ? -1 : a < b ? 1 : 0;
        },

        open: function(link) {
            window.open(link, "_self");
        },
        shuffle: function(array) {
            var copy = array.slice(0), n = array.length, tmp, i;

            while (n) {
                i = Math.floor(Math.random() * n--);
                tmp = copy[n];
                copy[n] = copy[i];
                copy[i] = tmp;
            };

            return copy;
        }
    };

    return ns;
})(coge || {});
<|endoftext|>


<commit_before>import debounce from 'lodash.debounce';

/**
 * @return {boolean}
 */
export function inIframe() {
  return window.location !== window.parent.location;
}

/**
 * Get array of HTMLElements from CSS selector
 * Fires `document.querySelectorAll` but returns an Array instead of a NodeList
 * @param {string} selector
 * @return {HTMLElement[]}
 */
export function query(selector) {
  return [].slice.call(document.querySelectorAll(selector));
}

/**
 * Trigger animations on this element.
 * Adds data attribute and triggers event handlers
 * @param {HTMLElement} el - The element
 * @todo trigger event `anim-trigger`
 */
export function triggerAnimation(el) {
  if (el.getAttribute('data-anim-triggered') !== 'yes') {
    // console.log(`triggering...`);
    el.setAttribute('data-anim-triggered', 'yes');

    // if (window.CustomEvent) {
    //   const event = new CustomEvent('anim-trigger', {detail: {some: 'data'}});
    // } else {
    //   const event = document.createEvent('CustomEvent');
    //   event.initCustomEvent('anim-trigger', true, true, {some: 'data'});
    // }
    //
    // el.dispatchEvent(event);
  }
}

/**
 * @param {HTMLElement} el - The element
 * @return {boolean}
 */
export function isElementInViewport(el) {
  // const isInIframe = inIframe();
  const { top, left, bottom, right } = el.getBoundingClientRect();
  const {
    innerHeight,
    innerWidth,
    document: { documentElement },
  } = window.top;
  const { clientHeight, clientWidth } = documentElement;

  // console.table({
  //   isInIframe,
  //   top,
  //   left,
  //   bottom,
  //   right,
  //   innerHeight,
  //   innerWidth,
  //   clientHeight,
  //   clientWidth,
  // });

  return (
    top >= 0 &&
    left >= 0 &&
    bottom <= (innerHeight || clientHeight) &&
    right <= (innerWidth || clientWidth)
  );
}

/**
 * @param {HTMLElement[]} items
 */
export function triggerVisibleAnimations(items) {
  // console.log('triggerVisibleAnimations');
  items.forEach(item => {
    if (isElementInViewport(item)) {
      // console.log('is Visible');
      triggerAnimation(item);
    } else {
      // console.log('is NOT Visible');
    }
  });
}

export function watchForOnViewAnims() {
  const elementsToTrigger = query('[data-anim-trigger="view"]');
  if (!elementsToTrigger.length > 0) {
    return;
  }
  const doIt = debounce(() => triggerVisibleAnimations(elementsToTrigger), 500);

  // placing function call at bottom of call stack so other function can finish up first
  setTimeout(doIt, 0);

  // @todo these events are not firing inside the PL iFrame, but are when viewed alone via "Open in New Window"
  document.addEventListener('scroll', () => {
    doIt();
  });
  document.addEventListener('resize', () => {
    doIt();
  });
}
<commit_msg>refactor: fix onScroll animation trigger for PL iframes<commit_after>import debounce from 'lodash.debounce';

/**
 * @return {boolean}
 */
export function inIframe() {
  return window.location !== window.parent.location;
}

/**
 * Get array of HTMLElements from CSS selector
 * Fires `document.querySelectorAll` but returns an Array instead of a NodeList
 * @param {string} selector
 * @return {HTMLElement[]}
 */
export function query(selector) {
  return [].slice.call(document.querySelectorAll(selector));
}

/**
 * Trigger animations on this element.
 * Adds data attribute and triggers event handlers
 * @param {HTMLElement} el - The element
 * @todo trigger event `anim-trigger`
 */
export function triggerAnimation(el) {
  if (el.getAttribute('data-anim-triggered') !== 'yes') {
    // console.log(`triggering...`);
    el.setAttribute('data-anim-triggered', 'yes');

    // if (window.CustomEvent) {
    //   const event = new CustomEvent('anim-trigger', {detail: {some: 'data'}});
    // } else {
    //   const event = document.createEvent('CustomEvent');
    //   event.initCustomEvent('anim-trigger', true, true, {some: 'data'});
    // }
    //
    // el.dispatchEvent(event);
  }
}

/**
 * @param {HTMLElement} el - The element
 * @return {boolean}
 */
export function isElementInViewport(el) {
  // const isInIframe = inIframe();
  const { top, left, bottom, right } = el.getBoundingClientRect();
  const {
    innerHeight,
    innerWidth,
  } = window;
  const { innerHeight: clientHeight, innerWidth: clientWidth } = window.top;
  // console.table({
  //   isInIframe,
  //   top,
  //   left,
  //   bottom,
  //   right,
  //   innerHeight,
  //   innerWidth,
  //   clientHeight,
  //   clientWidth,
  // });

  return (
    top >= 0 &&
    left >= 0 &&
    bottom <= (innerHeight || clientHeight) &&
    right <= (innerWidth || clientWidth)
  );
}

/**
 * @param {HTMLElement[]} items
 */
export function triggerVisibleAnimations(items) {
  items.forEach(item => {
    if (isElementInViewport(item)) {
      // console.log('is Visible');
      triggerAnimation(item);
    } else {
      // console.log('is NOT Visible');
    }
  });
}

export function watchForOnViewAnims() {
  const elementsToTrigger = query('[data-anim-trigger="view"]');
  if (!elementsToTrigger.length > 0) {
    return;
  }
  const doIt = debounce(() => triggerVisibleAnimations(elementsToTrigger), 300);

  // placing function call at bottom of call stack so other function can finish up first
  setTimeout(doIt, 0);

  window.top.document.addEventListener('scroll', () => {
    doIt();
  });
  document.addEventListener('resize', () => {
    doIt();
  });
}
<|endoftext|>


<commit_before>
export default new Cachier()
export { Cachier }

function Cachier(databaseName) {

  var indexedDB = window.indexedDB || window.webkitIndexedDB ||
                  window.mozIndexedDB || window.OIndexedDB ||
                  window.msIndexedDB

  var connection = connect()

  databaseName = databaseName || 'cachier'

  function connect() {
    return new Promise(function(resolve, reject) {
      var request = indexedDB.open(databaseName, 1)
      request.onupgradeneeded = function(event) {
        var db = event.target.result
        var store = db.createObjectStore('cachier', { keyPath: '_id' })
        store.transaction.oncomplete = function() {
          resolve(db)
        }
        store.transaction.onerror = function() {
          reject(new Error('Cannot upgrade database!'))
        }
      }
      request.onerror = function() {
        reject(new Error('Cannot request database!'))
      }
      request.onsuccess = function(event) {
        var db = event.target.result
        resolve(db)
      }
    })
  }

  return {
    connection: connection,
    save(key, blob, metadata) {
      let NO_BLOB = !!this._NO_BLOB // for testing purpose
      return connection.then(function(db) {
        return Promise.resolve().then(function tryBlob() {
          if (NO_BLOB) throw new Error('Requested non-Blob storing mode')
          var request = db.transaction('cachier', 'readwrite')
                .objectStore('cachier')
                .put({ _id: key, blob: blob, metadata: metadata })
          return trap(request)
        })
        .catch(function tryObject() {
          console.log('Cannot store as blob, store as data-URL instead.')
          return blobToObject(blob).then(function(object) {
            var request = db.transaction('cachier', 'readwrite')
                  .objectStore('cachier')
                  .put({ _id: key, blob: object, metadata: metadata })
            return trap(request)
          })
        })
      })
    },
    load(key) {
      return connection.then(function(db) {
        var request = db.transaction('cachier').objectStore('cachier').get(key)
        return trap(request).then(function() {
          var result = request.result
          return {
            blob: objectToBlob(result.blob),
            metadata: result.metadata,
          }
        })
      })
    },
    delete(key) {
      return connection.then(function(db) {
        var request = db.transaction('cachier', 'readwrite')
              .objectStore('cachier')
              .delete(key)
        return trap(request)
      })
    },
    destroyDatabase() {
      if (!connection) return Promise.resolve()
      return connection.then(function(db) {
        db.close()
      }).then(function() {
        let request = indexedDB.deleteDatabase(databaseName)
        return trap(request)
      }).tap(function() {
        connection = null
      })
    },
  }

  function trap(request) {
    return new Promise(function(resolve, reject) {
      request.onerror = function() {
        reject(new Error('IndexedDB Error: ' + request.error))
      }
      request.onblocked = function() {
        console.log(request)
        reject(new Error('IndexedDB Blocked: ' + request))
      }
      request.onsuccess = function(event) {
        resolve(event)
      }
    })
  }

  function blobToObject(blob) {
    return new Promise(function(resolve, reject) {
      var reader = new FileReader()
      reader.onload = function() {
        resolve({ buffer: reader.result, type: blob.type })
      }
      reader.onerror = function() {
        reject(new Error('Unable to convert blob to object!'))
      }
      reader.readAsArrayBuffer(blob)
    })
  }

  function objectToBlob(object) {
    if (object instanceof Blob) {
      return object
    } else if (object.buffer) {
      return new Blob([object.buffer], { type: object.type })
    }
  }

}

<commit_msg>fix(cachier): workaround 6to5 bug<commit_after>
export default new Cachier()
export { Cachier }

function Cachier(databaseName) {

  var indexedDB = window.indexedDB || window.webkitIndexedDB ||
                  window.mozIndexedDB || window.OIndexedDB ||
                  window.msIndexedDB

  var connection = connect()

  databaseName = databaseName || 'cachier'

  function connect() {
    return new Promise(function(resolve, reject) {
      var request = indexedDB.open(databaseName, 1)
      request.onupgradeneeded = function(event) {
        var db = event.target.result
        var store = db.createObjectStore('cachier', { keyPath: '_id' })
        store.transaction.oncomplete = function() {
          resolve(db)
        }
        store.transaction.onerror = function() {
          reject(new Error('Cannot upgrade database!'))
        }
      }
      request.onerror = function() {
        reject(new Error('Cannot request database!'))
      }
      request.onsuccess = function(event) {
        var db = event.target.result
        resolve(db)
      }
    })
  }

  return {
    connection: connection,
    save(key, blob, metadata) {
      let NO_BLOB = !!this._NO_BLOB // for testing purpose
      return connection.then(function(db) {
        return Promise.resolve().then(function tryBlob() {
          if (NO_BLOB) throw new Error('Requested non-Blob storing mode')
          var request = db.transaction('cachier', 'readwrite')
                .objectStore('cachier')
                .put({ _id: key, blob: blob, metadata: metadata })
          return trap(request)
        })
        .catch(function tryObject() {
          console.log('Cannot store as blob, store as data-URL instead.')
          return blobToObject(blob).then(function(object) {
            var request = db.transaction('cachier', 'readwrite')
                  .objectStore('cachier')
                  .put({ _id: key, blob: object, metadata: metadata })
            return trap(request)
          })
        })
      })
    },
    load(key) {
      return connection.then(function(db) {
        var request = db.transaction('cachier').objectStore('cachier').get(key)
        return trap(request).then(function() {
          var result = request.result
          return {
            blob: objectToBlob(result.blob),
            metadata: result.metadata,
          }
        })
      })
    },
    delete: function(key) {
      return connection.then(function(db) {
        var request = db.transaction('cachier', 'readwrite')
              .objectStore('cachier')
              .delete(key)
        return trap(request)
      })
    },
    destroyDatabase() {
      if (!connection) return Promise.resolve()
      return connection.then(function(db) {
        db.close()
      }).then(function() {
        let request = indexedDB.deleteDatabase(databaseName)
        return trap(request)
      }).tap(function() {
        connection = null
      })
    },
  }

  function trap(request) {
    return new Promise(function(resolve, reject) {
      request.onerror = function() {
        reject(new Error('IndexedDB Error: ' + request.error))
      }
      request.onblocked = function() {
        console.log(request)
        reject(new Error('IndexedDB Blocked: ' + request))
      }
      request.onsuccess = function(event) {
        resolve(event)
      }
    })
  }

  function blobToObject(blob) {
    return new Promise(function(resolve, reject) {
      var reader = new FileReader()
      reader.onload = function() {
        resolve({ buffer: reader.result, type: blob.type })
      }
      reader.onerror = function() {
        reject(new Error('Unable to convert blob to object!'))
      }
      reader.readAsArrayBuffer(blob)
    })
  }

  function objectToBlob(object) {
    if (object instanceof Blob) {
      return object
    } else if (object.buffer) {
      return new Blob([object.buffer], { type: object.type })
    }
  }

}

<|endoftext|>