<commit_before>//= require ./main

"use strict";

var
    esPhinx;

(function ($) {

    $.extend({
        prototype: {
            removeAttr: function (attrName) {
                var
                    self = this;

                self.each(function (node) {
                    node.removeAttribute(attrName);
                });

                return self;
            },

            attr: function (attrName, value) {
                var
                    self = this,
                    first = self.first();

                if (self.length === 0) {
                    return self;
                }

                if (typeof value === "boolean" || value || value === "") {
                    self.each(function (node) {
                        node.setAttribute(attrName, value);
                    });

                    return self;
                } else {
                    if (first.attributes[attrName]) {
                        return first.attributes[attrName].value;
                    }
                }

                return undefined;
            },

            property: function (propertyName, value) {
                var
                    self = this,
                    first = self.first();

                if (self.length === 0) {
                    return self;
                }

                if (typeof value === "boolean" || value || value === "") {
                    self.each(function (node) {
                        node[propertyName] = value;
                    });

                    return self;
                } else {
                    if (first[propertyName] ||
                        typeof first[propertyName] === "boolean") {
                        return first[propertyName];
                    }
                }

                return undefined;
            },

            value: function (value) {
                var
                    self = this;

                if (value || value === "") {
                    self.property("value", value);
                    return self;
                }

                return self.property("value");
            },

            checked: function () {
                return this.property("checked");
            },

            check: function () {
                var
                    self = this;

                if (!self.checked()) {
                    self.property("checked", true);
                }

                return self;
            },

            uncheck: function () {
                var
                    self = this;

                return self.property("checked", false);
            },

            data: function (attrName, value) {
                return this.attr("data-" + attrName, value);
            },

            params: function () {
                var
                    self = this,
                    resolvedParams = {},
                    index,
                    name,
                    param,
                    key,
                    merged,
                    attr,

                    resolveParam = function (name, value) {
                        value = value || "";

                        var
                            structure = name,
                            parsed;

                        if (/.+\[.+\]\[\]\[.+\]/.test(name)) {
                            structure = "{\"" + structure
                                .replace(/\]\[\]\[/, "\":[{\"")
                                .replace(/\[(?![\{])/g, "\":{\"")
                                .replace(/\]$/g, "\":\"" + value + "\"}]}}");
                        } else if (/.+\[.+\]\[[0-9]+\]\[.+\]/.test(name)) {
                            index = name.split("][")[1];

                            structure = "{\"" + structure
                                .replace(/\[(?![0-9]+])/g, "\":{\"")
                                .replace(/\]\[[0-9]+\]/g, "\":{\"" + i)
                                .replace(/\]$/g, "\":\"" + value + "\"}}}}");
                        } else if (/.+\[.+\]/.test(name)) {
                            structure = "{\"" + structure
                                .replace(/\[/g, "\":{\"")
                                .replace(/\]$/g, "\":\"" + value + "\"}}");
                        } else {
                            structure = "{\"" + name + "\":\"" + value + "\"}";
                        }

                        if (parsed = JSON.parse(structure)) {
                            return parsed;
                        }
                        return false;
                    };

                self.each(function (form) {
                    if (form instanceof HTMLFormElement) {
                        $.each(form.elements, function (e, i) {
                            if (name = e.name) {
                                if (param = resolveParam(e.name, e.value)) {
                                    key = Object.keys(param)[0];
                                    if (resolvedParams[key]) {
                                        attr = Object.keys(param[key])[0];
                                        if (resolvedParams[key][attr]
                                            instanceof Array) {
                                            param[key][attr] = resolvedParams[key][attr]
                                               .concat(param[key][attr]);
                                        }
                                        // else if (param[key][attr] instanceof Object) {

                                        // }
                                        // else {
                                        //     param[key] = $.merge(resolvedParams[key], param[key]);
                                        // }
                                        param[key] = $.merge(resolvedParams[key], param[key]);
                                    }
                                    resolvedParams = $.merge(resolvedParams, param);
                                }
                            }
                        });
                    }
                });

                debugger
                return resolvedParams;
            },

        }

    });

}(esPhinx));
<commit_msg>improves<commit_after>//= require ./main

"use strict";

var
    esPhinx;

(function ($) {

    $.extend({
        prototype: {
            removeAttr: function (attrName) {
                var
                    self = this;

                self.each(function (node) {
                    node.removeAttribute(attrName);
                });

                return self;
            },

            attr: function (attrName, value) {
                var
                    self = this,
                    first = self.first();

                if (self.length === 0) {
                    return self;
                }

                if (typeof value === "boolean" || value || value === "") {
                    self.each(function (node) {
                        node.setAttribute(attrName, value);
                    });

                    return self;
                } else {
                    if (first.attributes[attrName]) {
                        return first.attributes[attrName].value;
                    }
                }

                return undefined;
            },

            property: function (propertyName, value) {
                var
                    self = this,
                    first = self.first();

                if (self.length === 0) {
                    return self;
                }

                if (typeof value === "boolean" || value || value === "") {
                    self.each(function (node) {
                        node[propertyName] = value;
                    });

                    return self;
                } else {
                    if (first[propertyName] ||
                        typeof first[propertyName] === "boolean") {
                        return first[propertyName];
                    }
                }

                return undefined;
            },

            value: function (value) {
                var
                    self = this;

                if (value || value === "") {
                    self.property("value", value);
                    return self;
                }

                return self.property("value");
            },

            checked: function () {
                return this.property("checked");
            },

            check: function () {
                var
                    self = this;

                if (!self.checked()) {
                    self.property("checked", true);
                }

                return self;
            },

            uncheck: function () {
                var
                    self = this;

                return self.property("checked", false);
            },

            data: function (attrName, value) {
                return this.attr("data-" + attrName, value);
            },

            params: function () {
                var
                    self = this,
                    resolvedParams = {},
                    index,
                    name,
                    param,
                    key,
                    merged,
                    attr,

                    resolveParam = function (name, value) {
                        value = value || "";

                        var
                            structure = name,
                            parsed;

                        // improves
                        if (/.+\[.+\]\[\]\[.+\]/.test(name)) {
                            structure = "{\"" + structure
                                .replace(/\]\[\]\[/, "\":[{\"")
                                .replace(/\[(?![\{])/g, "\":{\"")
                                .replace(/\]$/g, "\":\"" + value + "\"}]}}");
                        } else if (/.+\[.+\]\[[0-9]+\]\[.+\]/.test(name)) {
                            index = name.split("][")[1];

                            structure = "{\"" + structure
                                .replace(/\[(?![0-9]+])/g, "\":{\"")
                                .replace(/\]\[[0-9]+\]/g, "\":{\"" + index)
                                .replace(/\]$/g, "\":\"" + value + "\"}}}}");
                        } else if (/.+\[.+\]/.test(name)) {
                            structure = "{\"" + structure
                                .replace(/\[/g, "\":{\"")
                                .replace(/\]$/g, "\":\"" + value + "\"}}");
                        } else {
                            structure = "{\"" + name + "\":\"" + value + "\"}";
                        }

                        if (parsed = JSON.parse(structure)) {
                            return parsed;
                        }
                        return false;
                    };

                self.each(function (form) {
                    if (form instanceof HTMLFormElement) {
                        $.each(form.elements, function (e, i) {
                            if (name = e.name) {
                                if (param = resolveParam(e.name, e.value)) {
                                    key = Object.keys(param)[0];
                                    if (resolvedParams[key]) {
                                        attr = Object.keys(param[key])[0];
                                        if (resolvedParams[key][attr]
                                            instanceof Array) {
                                            param[key][attr] = resolvedParams[key][attr]
                                               .concat(param[key][attr]);
                                        } else if (resolvedParams[key][attr]
                                            instanceof Object) {
                                            i = Object.keys(resolvedParams[key][attr])
                                                .last();
                                            param[key][attr][i] = $.merge(resolvedParams[key][attr][i], param[key][attr][i]);
                                            param[key][attr] = $.merge(resolvedParams[key][attr], param[key][attr]);
                                        }

                                        param[key] = $.merge(resolvedParams[key], param[key]);
                                    }
                                    resolvedParams = $.merge(resolvedParams, param);
                                }
                            }
                        });
                    }
                });

                debugger
                return resolvedParams;
            },

        }

    });

}(esPhinx));
<|endoftext|>


<commit_before>'use strict';

require('should');

var tesseract = require('../lib/');

var testTesseract = function(path, done) {
  var document = {
    metadatas: {
      path: "osef",
    }
  };

  tesseract(path, document, function(err, document) {
    if (err) {
      throw err;
    }

    document.should.have.property('document_type', "image");
    document.should.have.property('metadatas');
    document.metadatas.should.have.property('text', "Tesseract sample image. The quick brown fox jumps over the lazy dog.\n\n");

    done();
  });
};

describe('Test tesseract results', function() {
  it('returns the correct informations for png image', function(done) {
    testTesseract(__dirname + '/samples/sample.png', done);
  });

  it('returns the correct informations for gif image', function(done) {
    var initDocument = {
      metadatas: {
        path: "/samples/sample.gif",
      }
    };
    tesseract(__dirname + '/samples/sample.gif', initDocument, function(err, document){
      if(err) {
        throw err;
      }
      document.should.have.property("hydration_errored", true);
      document.should.have.property("hydration_error");

      done();

    });
  });

  it('returns the correct informations for gif content-type', function(done) {
    var initDocument = {
      metadatas: {
        path: "/samples/bugged",
        'content-type': 'image/gif'
      },
    };
    tesseract(__dirname + '/samples/bugged', initDocument, function(err, document){
      if(err) {
        throw err;
      }
      document.should.have.property("hydration_errored", true);
      document.should.have.property("hydration_error");

      done();

    });
  });

  it('returns the correct informations for jpg image', function(done) {
    testTesseract(__dirname + '/samples/sample.jpg', done);
  });

  it('returns the correct informations for tif image', function(done) {
    testTesseract(__dirname + '/samples/sample.tif', done);
  });

  it('returns an errored document for non image', function(done) {
    var document = {
      metadatas: {
        path: "osef",
      }
    };
    tesseract(__filename, document, function(err, document) {
      if(err) {
        throw err;
      }
      document.should.have.property("hydration_errored", true);
      document.should.have.property("hydration_error");

      done();
    });
  });

  it('should return an errored document', function(done) {
    var document = {
      metadatas: {
        path: "/samples/errored.psd",
      }
    };

    tesseract(__dirname + "/samples/errored.psd", document, function(err, document) {
      if(err) {
        throw err;
      }
      document.should.have.property("hydration_errored", true);
      document.should.have.property("hydration_error");
      done();
    });
  });

});
<commit_msg>update test<commit_after>'use strict';

require('should');

var tesseract = require('../lib/');

var testTesseract = function(path, done) {
  var document = {
    metadatas: {
      path: "osef",
    }
  };

  tesseract(path, document, function(err, document) {
    if (err) {
      throw err;
    }

    document.should.have.property('document_type', "image");
    document.should.have.property('metadatas');
    document.metadatas.should.have.property('text', "Tesseract sample image. The quick brown fox jumps over the lazy dog.\n\n");

    done();
  });
};

describe('Test tesseract results', function() {
  it('returns the correct informations for png image', function(done) {
    testTesseract(__dirname + '/samples/sample.png', done);
  });

  it('returns the correct informations for gif image', function(done) {
    var initDocument = {
      metadatas: {
        path: "/samples/sample.gif",
      }
    };
    tesseract(__dirname + '/samples/sample.gif', initDocument, function(err, document){
      if(err) {
        throw err;
      }
      document.should.be.eql(initDocument);

      done();

    });
  });

  it('returns the correct informations for gif content-type', function(done) {
    var initDocument = {
      metadatas: {
        path: "/samples/bugged",
        'content-type': 'image/gif'
      },
    };
    tesseract(__dirname + '/samples/bugged', initDocument, function(err, document){
      if(err) {
        throw err;
      }
      document.should.be.eql(initDocument);

      done();

    });
  });

  it('returns the correct informations for jpg image', function(done) {
    testTesseract(__dirname + '/samples/sample.jpg', done);
  });

  it('returns the correct informations for tif image', function(done) {
    testTesseract(__dirname + '/samples/sample.tif', done);
  });

  it('returns an errored document for non image', function(done) {
    var document = {
      metadatas: {
        path: "osef",
      }
    };
    tesseract(__filename, document, function(err, document) {
      if(err) {
        throw err;
      }
      document.should.have.property("hydration_errored", true);
      document.should.have.property("hydration_error");

      done();
    });
  });

  it('should return an errored document', function(done) {
    var document = {
      metadatas: {
        path: "/samples/errored.psd",
      }
    };

    tesseract(__dirname + "/samples/errored.psd", document, function(err, document) {
      if(err) {
        throw err;
      }
      document.should.have.property("hydration_errored", true);
      document.should.have.property("hydration_error");
      done();
    });
  });

});
<|endoftext|>


<commit_before>'use strict';

var EpicEditor = EpicEditor || {};

angular
    .module('Yellr')
    .controller('writeArticleContentCtrl',
    ['$scope', '$rootScope', '$location', 'collectionApiService',
        'userApiService', 'storyApiService',
    function ($scope, $rootScope, $location, collectionApiService,
              userApiService, storyApiService) {
        var editor = new EpicEditor().load(),

        _getLanguages = function () {
            userApiService.getLanguages($rootScope.user.token)
            .success(function (data) {
                console.log(data);
                $scope.languages = data.languages;
            });
        },

        _getImagesFromPost = function (post) {
            var images = [];

            post.media_objects.forEach(function (mediaObject) {
                if (mediaObject.media_type_name == 'image') {
                    mediaObject.markdownLink = '![' + mediaObject.media_text +
                        '](/media/' + mediaObject.file_name + ')';
                    images.push(mediaObject);
                }
            });

            return images;
        };

        $scope.article = $scope.$parent.article;
        if (angular.isDefined($scope.$parent.languages)) {
            $scope.languages = $scope.$parent.languages;
        } else {
            _getLanguages();
        }

        $rootScope.$on('$stateChangeStart',
        function (event, toState, toParams, fromState, fromParams) {
            if (fromState.url == '/write') {
                $scope.$parent.article = $scope.article;
                $scope.$parent.languages = $scope.languages;
                $scope.$parent.article.collection = $scope.article.collection;
            }
        });

        /**
         * Gets all images for the current collection
         *
         * @return void
         */
        $scope.getImages = function () {
            $scope.images = [];

            collectionApiService.getPosts($rootScope.user.token,
                $scope.article.collection.collection_id)
            .success(function (data) {
                $scope.$parent.collectionId = $scope.article.collection
                    .collection_id;

                data.posts.forEach(function (post) {
                    var postImages = _getImagesFromPost(post);
                    $scope.images = $scope.images.concat(postImages);
                });
            });
        };

        /**
         * Publishes the story to the database
         *
         * @return void
         */
        $scope.save = function () {
            var content = editor.exportFile(),
                tags = $scope.article.tags.map(function (tag) {
                    return tag.text;
                })
                    .join(',');

            storyApiService.publishStory(
                $rootScope.user.token,
                $scope.article.title,
                tags,
                '',
                '',
                content,
                $scope.article.language.code,
                43.5,
                78,
                43,
                77
            )
            .success(function (data) {
                console.log(data);
            });
        };

        /**
         * Gets all collections to populate form with
         *
         * @return void
         */
        collectionApiService.getAllCollections($rootScope.user.token)
        .success(function (data) {
            $scope.collections = data.collections;
        });

    }]);
<commit_msg>changed default lat/lng to correct map area until we get geofence implemented<commit_after>'use strict';

var EpicEditor = EpicEditor || {};

angular
    .module('Yellr')
    .controller('writeArticleContentCtrl',
    ['$scope', '$rootScope', '$location', 'collectionApiService',
        'userApiService', 'storyApiService',
    function ($scope, $rootScope, $location, collectionApiService,
              userApiService, storyApiService) {
        var editor = new EpicEditor().load(),

        _getLanguages = function () {
            userApiService.getLanguages($rootScope.user.token)
            .success(function (data) {
                console.log(data);
                $scope.languages = data.languages;
            });
        },

        _getImagesFromPost = function (post) {
            var images = [];

            post.media_objects.forEach(function (mediaObject) {
                if (mediaObject.media_type_name == 'image') {
                    mediaObject.markdownLink = '![' + mediaObject.media_text +
                        '](/media/' + mediaObject.file_name + ')';
                    images.push(mediaObject);
                }
            });

            return images;
        };

        $scope.article = $scope.$parent.article;
        if (angular.isDefined($scope.$parent.languages)) {
            $scope.languages = $scope.$parent.languages;
        } else {
            _getLanguages();
        }

        $rootScope.$on('$stateChangeStart',
        function (event, toState, toParams, fromState, fromParams) {
            if (fromState.url == '/write') {
                $scope.$parent.article = $scope.article;
                $scope.$parent.languages = $scope.languages;
                $scope.$parent.article.collection = $scope.article.collection;
            }
        });

        /**
         * Gets all images for the current collection
         *
         * @return void
         */
        $scope.getImages = function () {
            $scope.images = [];

            collectionApiService.getPosts($rootScope.user.token,
                $scope.article.collection.collection_id)
            .success(function (data) {
                $scope.$parent.collectionId = $scope.article.collection
                    .collection_id;

                data.posts.forEach(function (post) {
                    var postImages = _getImagesFromPost(post);
                    $scope.images = $scope.images.concat(postImages);
                });
            });
        };

        /**
         * Publishes the story to the database
         *
         * @return void
         */
        $scope.save = function () {
            var content = editor.exportFile(),
                tags = $scope.article.tags.map(function (tag) {
                    return tag.text;
                })
                    .join(',');

            storyApiService.publishStory(
                $rootScope.user.token,
                $scope.article.title,
                tags,
                '',
                '',
                content,
                $scope.article.language.code,
                43.5,
                -78,
                43,
                -77
            )
            .success(function (data) {
                console.log(data);
            });
        };

        /**
         * Gets all collections to populate form with
         *
         * @return void
         */
        collectionApiService.getAllCollections($rootScope.user.token)
        .success(function (data) {
            $scope.collections = data.collections;
        });

    }]);
<|endoftext|>


<commit_before>//= require ./main

"use strict";

var
    esPhinx;

(function ($) {

    $.extend({
        prototype: {
            removeAttr: function (attrName) {
                var
                    self = this;

                self.each(function (node) {
                    node.removeAttribute(attrName);
                });

                return self;
            },

            attr: function (attrName, value) {
                var
                    self = this,
                    first = self.first();

                if (self.length === 0) {
                    return self;
                }

                if (typeof value === "boolean" || value || value === "") {
                    self.each(function (node) {
                        node.setAttribute(attrName, value);
                    });

                    return self;
                } else {
                    if (first.attributes[attrName]) {
                        return first.attributes[attrName].value;
                    }
                }

                return undefined;
            },

            property: function (propertyName, value) {
                var
                    self = this,
                    first = self.first();

                if (self.length === 0) {
                    return self;
                }

                if (typeof value === "boolean" || value || value === "") {
                    self.each(function (node) {
                        node[propertyName] = value;
                    });

                    return self;
                } else {
                    if (first[propertyName] ||
                        typeof first[propertyName] === "boolean") {
                        return first[propertyName];
                    }
                }

                return undefined;
            },

            value: function (value) {
                var
                    self = this;

                if (value || value === "") {
                    self.property("value", value);
                    return self;
                }

                return self.property("value");
            },

            checked: function () {
                return this.property("checked");
            },

            check: function () {
                var
                    self = this;

                if (!self.checked()) {
                    self.property("checked", true);
                }

                return self;
            },

            uncheck: function () {
                var
                    self = this;

                return self.property("checked", false);
            },

            data: function (attrName, value) {
                return this.attr("data-" + attrName, value);
            },

            params: function () {
                var
                    self = this,
                    resolvedParams = {},
                    index,
                    name,
                    param,
                    key,
                    merged,

                    resolveParam = function (name, value) {
                        value = value || "";

                        var
                            structure = name,
                            parsed;

                        if (/.+\[.+\]\[\]\[.+\]/.test(name)) {
                            structure = "{\"" + structure
                                .replace(/\]\[\]\[/, "\":[{\"")
                                .replace(/\[(?![\{])/g, "\":{\"")
                                .replace(/\]$/g, "\":\"" + value + "\"}]}}");
                        } else if (/.+\[.+\]\[[0-9]+\]\[.+\]/.test(name)) {
                            index = name.split("][")[1];

                            structure = "{\"" + structure
                                .replace(/\[(?![0-9]+])/g, "\":{\"")
                                .replace(/\]\[[0-9]+\]/g, "\":{\"" + i)
                                .replace(/\]$/g, "\":\"" + value + "\"}}}}");
                        } else if (/.+\[.+\]/.test(name)) {
                            structure = "{\"" + structure
                                .replace(/\[/g, "\":{\"")
                                .replace(/\]$/g, "\":\"" + value + "\"}}");
                        } else {
                            structure = "{\"" + name + "\":\"" + value + "\"}";
                        }

                        if (parsed = JSON.parse(structure)) {
                            return parsed;
                        }
                        return false;
                    };

                self.each(function (form) {
                    if (form instanceof HTMLFormElement) {
                        $.each(form.elements, function (e, i) {
                            if (name = e.name) {
                                if (param = resolveParam(e.name, e.value)) {
                                    key = Object.keys(param)[0];
                                    if (resolvedParams[key]) {
                                        param[key] = $.merge(resolvedParams[key], param[key]);
                                    }
                                    resolvedParams = $.merge(resolvedParams, param);
                                }
                            }
                        });
                    }
                });

                return resolvedParams;
            },

        }

    });

}(esPhinx));
<commit_msg>improves params<commit_after>//= require ./main

"use strict";

var
    esPhinx;

(function ($) {

    $.extend({
        prototype: {
            removeAttr: function (attrName) {
                var
                    self = this;

                self.each(function (node) {
                    node.removeAttribute(attrName);
                });

                return self;
            },

            attr: function (attrName, value) {
                var
                    self = this,
                    first = self.first();

                if (self.length === 0) {
                    return self;
                }

                if (typeof value === "boolean" || value || value === "") {
                    self.each(function (node) {
                        node.setAttribute(attrName, value);
                    });

                    return self;
                } else {
                    if (first.attributes[attrName]) {
                        return first.attributes[attrName].value;
                    }
                }

                return undefined;
            },

            property: function (propertyName, value) {
                var
                    self = this,
                    first = self.first();

                if (self.length === 0) {
                    return self;
                }

                if (typeof value === "boolean" || value || value === "") {
                    self.each(function (node) {
                        node[propertyName] = value;
                    });

                    return self;
                } else {
                    if (first[propertyName] ||
                        typeof first[propertyName] === "boolean") {
                        return first[propertyName];
                    }
                }

                return undefined;
            },

            value: function (value) {
                var
                    self = this;

                if (value || value === "") {
                    self.property("value", value);
                    return self;
                }

                return self.property("value");
            },

            checked: function () {
                return this.property("checked");
            },

            check: function () {
                var
                    self = this;

                if (!self.checked()) {
                    self.property("checked", true);
                }

                return self;
            },

            uncheck: function () {
                var
                    self = this;

                return self.property("checked", false);
            },

            data: function (attrName, value) {
                return this.attr("data-" + attrName, value);
            },

            params: function () {
                var
                    self = this,
                    resolvedParams = {},
                    index,
                    name,
                    param,
                    key,
                    merged,
                    attr,

                    resolveParam = function (name, value) {
                        value = value || "";

                        var
                            structure = name,
                            parsed;

                        if (/.+\[.+\]\[\]\[.+\]/.test(name)) {
                            structure = "{\"" + structure
                                .replace(/\]\[\]\[/, "\":[{\"")
                                .replace(/\[(?![\{])/g, "\":{\"")
                                .replace(/\]$/g, "\":\"" + value + "\"}]}}");
                        } else if (/.+\[.+\]\[[0-9]+\]\[.+\]/.test(name)) {
                            index = name.split("][")[1];

                            structure = "{\"" + structure
                                .replace(/\[(?![0-9]+])/g, "\":{\"")
                                .replace(/\]\[[0-9]+\]/g, "\":{\"" + i)
                                .replace(/\]$/g, "\":\"" + value + "\"}}}}");
                        } else if (/.+\[.+\]/.test(name)) {
                            structure = "{\"" + structure
                                .replace(/\[/g, "\":{\"")
                                .replace(/\]$/g, "\":\"" + value + "\"}}");
                        } else {
                            structure = "{\"" + name + "\":\"" + value + "\"}";
                        }

                        if (parsed = JSON.parse(structure)) {
                            return parsed;
                        }
                        return false;
                    };

                self.each(function (form) {
                    if (form instanceof HTMLFormElement) {
                        $.each(form.elements, function (e, i) {
                            if (name = e.name) {
                                if (param = resolveParam(e.name, e.value)) {
                                    key = Object.keys(param)[0];
                                    if (resolvedParams[key]) {
                                        attr = Object.keys(param[key])[0];
                                        if (resolvedParams[key][attr]
                                            instanceof Array) {
                                            param[key][attr] = resolvedParams[key][attr]
                                               .concat(param[key][attr]);
                                        }
                                        // else if (param[key][attr] instanceof Object) {

                                        // }
                                        // else {
                                        //     param[key] = $.merge(resolvedParams[key], param[key]);
                                        // }
                                        param[key] = $.merge(resolvedParams[key], param[key]);
                                    }
                                    resolvedParams = $.merge(resolvedParams, param);
                                }
                            }
                        });
                    }
                });

                debugger
                return resolvedParams;
            },

        }

    });

}(esPhinx));
<|endoftext|>


<commit_before>var path = require('path');
var viewPath = path.join( __dirname + "/");

var fs = require('fs');
var Feedback = require('./feedbackSetup');

var Logger = require( __configs + "loggingConfig");
var _ = require('lodash');

module.exports = function( app ) {

/**************************************************************  Values Controller *************************/
    /*
        Read the feedback information file
        and process and highlight
    */
    app.get('/feedback', function(req,res, next ){

        var page = { title: 'Feedback page' };
        var feedbackFile = req.session.allFeedbackFile;
        var feedback = Feedback.setupFeedback(feedbackFile);
        var result = _.assign(page, feedback);
        res.render( viewPath + "feedback", result );
    });

    app.post('/feedback', function(req,res,next){

        // Would really like to reuse the previously send information.
        // Get and Post are the essentially the same until ...I figure out resuse of feedbackObject
        // As this could essecially just be a filter  with the new tool name.

        var opt = { 'tool': req.body.toolSelector };
        req.session.activeTool = req.body.toolSelector;

        var page = { title: 'Feedback Test page' };
        var feedbackFile = req.session.allFeedbackFile
        var feedback = Feedback.setupFeedback(feedbackFile, opt);
        var result = _.assign(page,feedback);
        res.render( viewPath + "feedback", result );

    });

    app.get('/feedback/data', function( req,res, next ){
        var supportedToolsFile = req.session.allFeedbackFile;
        fs.readFile( supportedToolsFile, 'utf-8'  , function( err, data ) {
            if( err ) {
                //Unable to get support tools file, larger problem here.
                Logger.error("Error unable to load feedbackFiles");
            }
            else {
                //Load JSON tool file and send back to UI to create inputs
                var opt = {};
                if( req.session.activeTool ) {
                    opt['tool'] = req.session.activeTool;
                }
                var result = Feedback.readFeedbackFormat( data, opt );
                res.json( result );
            }
        });
    });
}<commit_msg>Quick fix for selected tool not resetting<commit_after>var path = require('path');
var viewPath = path.join( __dirname + "/");

var fs = require('fs');
var Feedback = require('./feedbackSetup');

var Logger = require( __configs + "loggingConfig");
var _ = require('lodash');

module.exports = function( app ) {

/**************************************************************  Values Controller *************************/
    /*
        Read the feedback information file
        and process and highlight
    */
    app.get('/feedback', function(req,res, next ){

        req.session.activeTool = undefined;
        var page = { title: 'Feedback page' };
        var feedbackFile = req.session.allFeedbackFile;
        var feedback = Feedback.setupFeedback(feedbackFile);
        var result = _.assign(page, feedback);
        res.render( viewPath + "feedback", result );
    });

    app.post('/feedback', function(req,res,next){

        // Would really like to reuse the previously send information.
        // Get and Post are the essentially the same until ...I figure out resuse of feedbackObject
        // As this could essecially just be a filter  with the new tool name.

        var opt = { 'tool': req.body.toolSelector };
        req.session.activeTool = req.body.toolSelector;

        var page = { title: 'Feedback Test page' };
        var feedbackFile = req.session.allFeedbackFile
        var feedback = Feedback.setupFeedback(feedbackFile, opt);
        var result = _.assign(page,feedback);
        res.render( viewPath + "feedback", result );

    });

    app.get('/feedback/data', function( req,res, next ){
        var supportedToolsFile = req.session.allFeedbackFile;
        fs.readFile( supportedToolsFile, 'utf-8'  , function( err, data ) {
            if( err ) {
                //Unable to get support tools file, larger problem here.
                Logger.error("Error unable to load feedbackFiles");
            }
            else {
                //Load JSON tool file and send back to UI to create inputs
                var opt = {};
                if( req.session.activeTool ) {
                    opt['tool'] = req.session.activeTool;
                }
                var result = Feedback.readFeedbackFormat( data, opt );
                res.json( result );
            }
        });
    });
}<|endoftext|>


<commit_before>import RNTest from './react-native-testkit/'
import React from 'react'
import RNFetchBlob from 'react-native-fetch-blob'

import {
  StyleSheet,
  Text,
  View,
  ScrollView,
  Dimensions,
  Platform,
  Dimension,
  Image,
} from 'react-native';

const { Assert, Comparer, Info, prop } = RNTest

// test environment variables

prop('FILENAME', `${Platform.OS}-0.8.0-${Date.now()}.png`)
prop('TEST_SERVER_URL', 'http://192.168.0.11:8123')
prop('TEST_SERVER_URL_SSL', 'https://192.168.0.11:8124')
prop('DROPBOX_TOKEN', 'fsXcpmKPrHgAAAAAAAAAoXZhcXYWdgLpQMan6Tb_bzJ237DXhgQSev12hA-gUXt4')
prop('styles', {
  image : {
    width: Dimensions.get('window').width*0.9,
    height : Dimensions.get('window').width*0.9,
    margin : 16,
    flex : 1
  }
})

const { TEST_SERVER_URL, FILENAME, DROPBOX_TOKEN, styles, image } = prop()

const describe = RNTest.config({
  run : true,
  expand : true,
  timeout : 5000,
})

// init

describe('GET image from server', (report, done) => {

  RNFetchBlob
    .fetch('GET', `${TEST_SERVER_URL}/public/github.png`, {
      Authorization : 'Bearer abde123eqweje'
    })
    .then((resp) => {
      RNTest.prop('image', resp.base64())
      report(
        <Info key="Response image">
          <Image
            style={styles.image}
            source={{uri : `data:image/png;base64, ${prop('image')}`}}/>
        </Info>)
        done()
    })
})

require('./test-0.1.x-0.4.x')
require('./test-0.5.1')
require('./test-0.5.2')
require('./test-0.6.0')
require('./test-0.6.2')
require('./test-0.7.0')
require('./test-0.8.0')
require('./test-0.9.0')
require('./test-0.9.2')
require('./test-0.9.4')
require('./test-fetch')
require('./test-fs')
require('./test-xmlhttp')
require('./test-blob')
require('./test-firebase')
require('./test-android')
// require('./test-stress')
// require('./benchmark')
<commit_msg>Change test config<commit_after>import RNTest from './react-native-testkit/'
import React from 'react'
import RNFetchBlob from 'react-native-fetch-blob'

import {
  StyleSheet,
  Text,
  View,
  ScrollView,
  Dimensions,
  Platform,
  Dimension,
  Image,
} from 'react-native';

const { Assert, Comparer, Info, prop } = RNTest

// test environment variables

prop('FILENAME', `${Platform.OS}-0.8.0-${Date.now()}.png`)
prop('TEST_SERVER_URL', 'http://192.168.16.70:8123')
prop('TEST_SERVER_URL_SSL', 'https://192.168.16.70:8124')
prop('DROPBOX_TOKEN', 'fsXcpmKPrHgAAAAAAAAAoXZhcXYWdgLpQMan6Tb_bzJ237DXhgQSev12hA-gUXt4')
prop('styles', {
  image : {
    width: Dimensions.get('window').width*0.9,
    height : Dimensions.get('window').width*0.9,
    margin : 16,
    flex : 1
  }
})

const { TEST_SERVER_URL, FILENAME, DROPBOX_TOKEN, styles, image } = prop()

const describe = RNTest.config({
  run : true,
  expand : true,
  timeout : 5000,
})

// init

describe('GET image from server', (report, done) => {

  RNFetchBlob
    .fetch('GET', `${TEST_SERVER_URL}/public/github.png`, {
      Authorization : 'Bearer abde123eqweje'
    })
    .then((resp) => {
      RNTest.prop('image', resp.base64())
      report(
        <Info key="Response image">
          <Image
            style={styles.image}
            source={{uri : `data:image/png;base64, ${prop('image')}`}}/>
        </Info>)
        done()
    })
})

require('./test-0.1.x-0.4.x')
require('./test-0.5.1')
require('./test-0.5.2')
require('./test-0.6.0')
require('./test-0.6.2')
require('./test-0.7.0')
require('./test-0.8.0')
require('./test-0.9.0')
require('./test-0.9.2')
require('./test-0.9.4')
require('./test-fetch')
require('./test-fs')
require('./test-xmlhttp')
require('./test-blob')
require('./test-firebase')
require('./test-android')
// require('./test-stress')
// require('./benchmark')
<|endoftext|>


<commit_before>'use strict';

var mongoose = require('mongoose'),
	Database = mongoose.model('Database'),
	_ = require('lodash'),
	redis=require('redis');

var getErrorMessage = function(err) {
	var message = '';

	if (err.code) {
		switch (err.code) {
			case 11000:
			case 11001:
				message = 'Database already exists';
				break;
			default:
				message = 'Something went wrong';
		}
	} else {
		for (var errName in err.errors) {
			if (err.errors[errName].message) message = err.errors[errName].message;
		}
	}
	return message;
};

exports.create = function(req, res) {
	var database = new Database(req.body);
	database.user = req.user;

	database.save(function(err) {
		if (err) {
			return res.send(400, {
				message: getErrorMessage(err)
			});
		} else {
			res.jsonp(database);
		}
	});
};

/**
 * Show the current Database
 */
exports.read = function(req, res) {
	res.jsonp(req.database);
};

//Getting Redis Info
exports.info = function(req,res){
	var database = req.database;
	var redis_client=redis.createClient(database.port, database.host);
	redis_client.info(function(err,reply) {
		if (err) {
			return res.send(400, {
				message: getErrorMessage(err)
			});
		} else {
			console.log('reply from redis info: ' + reply);
//FIXME:		res.jsonp(reply);
		}
	});
};

exports.update = function(req, res) {
	var database = req.database ;

	database = _.extend(database , req.body);

	database.save(function(err) {
		if (err) {
			return res.send(400, {
				message: getErrorMessage(err)
			});
		} else {
			res.jsonp(database);
		}
	});
};

exports.delete = function(req, res) {
	var database = req.database ;

	database.remove(function(err) {
		if (err) {
			return res.send(400, {
				message: getErrorMessage(err)
			});
		} else {
			res.jsonp(database);
		}
	});
};

exports.list = function(req, res) { Database.find({user: req.user.id}).sort('-created').populate('user', 'displayName').exec(function(err, databases) {
		if (err) {
			return res.send(400, {
				message: getErrorMessage(err)
			});
		} else {
			res.jsonp(databases);
		}
	});
};

exports.databaseByID = function(req, res, next, id) { Database.findById(id).populate('user', 'displayName').exec(function(err, database) {
		if (err) return next(err);
		if (! database) return next(new Error('Failed to load Database ' + id));
		req.database = database ;
		next();
	});
};

exports.hasAuthorization = function(req, res, next) {
	if (req.database.user.id !== req.user.id) {
		return res.send(403, 'User is not authorized');
	}
	next();
};
<commit_msg>[Hari]resolves issue#10, correct backend info method<commit_after>'use strict';

var mongoose = require('mongoose'),
	Database = mongoose.model('Database'),
	_ = require('lodash'),
	redis=require('redis');

var getErrorMessage = function(err) {
	var message = '';

	if (err.code) {
		switch (err.code) {
			case 11000:
			case 11001:
				message = 'Database already exists';
				break;
			default:
				message = 'Something went wrong';
		}
	} else {
		for (var errName in err.errors) {
			if (err.errors[errName].message) message = err.errors[errName].message;
		}
	}
	return message;
};

exports.create = function(req, res) {
	var database = new Database(req.body);
	database.user = req.user;

	database.save(function(err) {
		if (err) {
			return res.send(400, {
				message: getErrorMessage(err)
			});
		} else {
			res.jsonp(database);
		}
	});
};

/**
 * Show the current Database
 */
exports.read = function(req, res) {
	res.jsonp(req.database);
};

//Getting Redis Info
exports.info = function(req,res){
	var database = req.database;
	var redis_client=redis.createClient(database.port, database.host);
	redis_client.info(function(err,reply) {
		if (err) {
			return res.send(400, {
				message: getErrorMessage(err)
			});
		} else {
			console.log('reply from redis info: ' + reply);
			res.jsonp(reply);
		}
	});
};

exports.update = function(req, res) {
	var database = req.database ;

	database = _.extend(database , req.body);

	database.save(function(err) {
		if (err) {
			return res.send(400, {
				message: getErrorMessage(err)
			});
		} else {
			res.jsonp(database);
		}
	});
};

exports.delete = function(req, res) {
	var database = req.database ;

	database.remove(function(err) {
		if (err) {
			return res.send(400, {
				message: getErrorMessage(err)
			});
		} else {
			res.jsonp(database);
		}
	});
};

exports.list = function(req, res) { Database.find({user: req.user.id}).sort('-created').populate('user', 'displayName').exec(function(err, databases) {
		if (err) {
			return res.send(400, {
				message: getErrorMessage(err)
			});
		} else {
			res.jsonp(databases);
		}
	});
};

exports.databaseByID = function(req, res, next, id) { Database.findById(id).populate('user', 'displayName').exec(function(err, database) {
		if (err) return next(err);
		if (! database) return next(new Error('Failed to load Database ' + id));
		req.database = database ;
		next();
	});
};

exports.hasAuthorization = function(req, res, next) {
	if (req.database.user.id !== req.user.id) {
		return res.send(403, 'User is not authorized');
	}
	next();
};
<|endoftext|>


<commit_before>/*jshint esversion: 6 */

import { Template } from 'meteor/templating';
import './afFormGroup.html';

Template.afFormGroup_materialize.helpers({
    addInputField: function() {
        var result, skipInputType, type;
        skipInputType = [
            'checkbox',
            'checkbox-group',
            'boolean-checkbox',
            'flowtext',
            'select-radio',
            'select-checkbox-inline',
            'select-radio-inline',
            'boolean-radios',
            'toggle',
            'switch'
        ];
        type = AutoForm.getInputType(this);
        result = !_.contains(skipInputType, type);
        return result;
    },
    skipLabel: function() {
        var result, skipLabelTypes, type;
        skipLabelTypes = [
            'medium',
            'checkbox',
            'checkbox-group',
            'boolean-checkbox',
            'flowtext',
            'select-radio',
            'select-checkbox-inline',
            'select-radio-inline',
            'boolean-radio',
            'toggle',
            'switch'
        ];
        type = AutoForm.getInputType(this);
        result = this.skipLabel || _.contains(skipLabelTypes, type);
        return result;
    }
});

Template.afFormGroup_materialize.rendered = function() {
    var formId;
    formId = AutoForm.getFormId();
    this.autorun((function(_this) {
        return function() {
            var value = AutoForm.getFieldValue(_this.data.name, formId);
            var inputValue = AutoForm.getInputValue(_this.find('input'));
            var type = AutoForm.getInputType(_this.data);
            var placeholder = _this.data.afFieldInputAtts.placeholder;

            // do not auto activate labels for the following types
            var skipActiveLabelTypes = [
                'autocomplete',
                'checkbox',
                'checkbox-group',
                'boolean-checkbox',
                'flowtext',
                'select',
                'select-multiple',
                'select-radio',
                'select-checkbox-inline',
                'select-radio-inline',
                'boolean-radio',
                'toggle',
                'switch'
            ];

            // always activate labels for the following types
            var alwaysActiveLabelTypes = [
              'noUiSlider2',
              'file',
              'fileUpload'
            ];

            // if the input always has an active label
            if (_.contains(alwaysActiveLabelTypes, type)) {

              // activate the label
              return _this.$('.input-field > label:not(:focus)').addClass('active');
            }

            // else, if the input is an active type
            else if (!_.contains(skipActiveLabelTypes, type)) {

              // if value or inputValue number 0 or placeholder
              if (!!value || !!inputValue || inputValue === 0 || !!placeholder)
              {

                // activate the label
                return _this.$('.input-field > label:not(:focus)').addClass('active');

              // else
              } else {

                // deactivate the label
                return _this.$('.input-field > label:not(:focus)').removeClass('active');
              }
            }
        };
    })(this));
};
<commit_msg>fixed #31<commit_after>/*jshint esversion: 6 */

import { Template } from 'meteor/templating';
import './afFormGroup.html';

Template.afFormGroup_materialize.helpers({
    addInputField: function() {
        var result, skipInputType, type;
        skipInputType = [
            'checkbox',
            'checkbox-group',
            'boolean-checkbox',
            'flowtext',
            'select-radio',
            'select-checkbox-inline',
            'select-radio-inline',
            'boolean-radios',
            'toggle',
            'switch'
        ];
        type = AutoForm.getInputType(this);
        result = !_.contains(skipInputType, type);
        return result;
    },
    skipLabel: function() {
        var result, skipLabelTypes, type;
        skipLabelTypes = [
            'medium',
            'checkbox',
            'checkbox-group',
            'boolean-checkbox',
            'flowtext',
            'select-radio',
            'select-checkbox-inline',
            'select-radio-inline',
            'boolean-radio',
            'toggle',
            'switch'
        ];
        type = AutoForm.getInputType(this);
        result = this.skipLabel || _.contains(skipLabelTypes, type);
        return result;
    }
});

Template.afFormGroup_materialize.rendered = function() {
    var formId;
    formId = AutoForm.getFormId();
    this.autorun((function(_this) {
        return function() {
            var value = AutoForm.getFieldValue(_this.data.name, formId);
            var inputValue = AutoForm.getInputValue(_this.find('input'));
            var type = AutoForm.getInputType(_this.data);
            var placeholder = _this.data.afFieldInputAtts.placeholder;

            // do not auto activate labels for the following types
            var skipActiveLabelTypes = [
                'autocomplete',
                'checkbox',
                'checkbox-group',
                'boolean-checkbox',
                'flowtext',
                'select',
                'select-multiple',
                'select-radio',
                'select-checkbox-inline',
                'select-radio-inline',
                'boolean-radio',
                'toggle',
                'switch'
            ];

            // always activate labels for the following types
            var alwaysActiveLabelTypes = [
              'noUiSlider2',
              'file',
              'fileUpload',
              'date'
            ];

            // if the input always has an active label
            if (_.contains(alwaysActiveLabelTypes, type)) {

              // activate the label
              return _this.$('.input-field > label:not(:focus)').addClass('active');
            }

            // else, if the input is an active type
            else if (!_.contains(skipActiveLabelTypes, type)) {

              // if value or inputValue number 0 or placeholder
              if (!!value || !!inputValue || inputValue === 0 || !!placeholder)
              {

                // activate the label
                return _this.$('.input-field > label:not(:focus)').addClass('active');

              // else
              } else {

                // deactivate the label
                return _this.$('.input-field > label:not(:focus)').removeClass('active');
              }
            }
        };
    })(this));
};
<|endoftext|>


<commit_before>
var sandbox = require("sandboxed-module");

exports["util.has_joined: true"] = function(test){

	var util = require("../lib/util");
	var rcpts_arr = [{push_id:"123", push_type:"web"},{push_id:"456",push_type:"gcm"},{push_id:"789",push_type:"gcm"}];
	test.ok(util.has_joined(rcpts_arr,"123"));
	test.done();

}

exports["util.has_joined: false"] = function(test){

	var util = require("../lib/util");
	var rcpts_arr = [{push_id:"123", push_type:"web"},{push_id:"456",push_type:"gcm"},{push_id:"789",push_type:"gcm"}];
	test.equal( false, util.has_joined(rcpts_arr,"124"));
	test.done();

}

exports["util.is_array: true"] = function(test){

	var util = require("../lib/util");
	var obj = [1,2,3];
	test.ok( util.is_array(obj) );
	test.done();

}

exports["util.is_array: false"] = function(test){

	var util = require("../lib/util");
	var obj = {};
	test.equal( false, util.is_array(obj) );
	obj = "";
	test.equal( false, util.is_array(obj) );
	obj = 5;
	test.equal( false, util.is_array(obj) );
	obj = function(){}
	test.equal( false, util.is_array(obj) );
	test.done();

}

exports["util.get_field:existing field-path"] = function(test){

	var util = require("../lib/util");
	var doc = {x:{y:{z:1}}};
	test.equal(util.get_field(doc,"x.y.z"), 1);
	test.done()
}

exports["util.get_field:existing single field"] = function(test){

	var util = require("../lib/util");
	var doc = {x:1};
	test.equal(util.get_field(doc,"x"), 1);
	test.done();
}

exports["util.get_field:non existing field-path"] = function(test){

	var util = require("../lib/util");
	var doc = {x:{y:{z:1}}};
	test.equal(util.get_field(doc,"x.nonexisting.z"), undefined);
	test.done()
}

exports["util.get_field:existing array index"] = function(test){

	var util = require("../lib/util");
	var doc = {x:{y:{z:[1,2,3]}}};
	test.equal(util.get_field(doc,"x.y.z.2"), 3);
	test.done();
}

exports["util.get_field:non existing array index"] = function(test){

	var util = require("../lib/util");
	var doc = {x:{y:{z:[1,2,3]}}};
	test.equal(util.get_field(doc,"x.y.z.10"), undefined);
	test.done();
}

exports["util.get_field:existing subarray"] = function(test){

	var util = require("../lib/util");
	var doc = {x:{y:{z:[1,2,3,4,5,6,7]}}};
	test.deepEqual(util.get_field(doc,"x.y.z.2-5"), [3,4,5,6]);
	test.done();
}

exports["util.get_field:existing subarray, no second index"] = function(test){

	var util = require("../lib/util");
	var doc = {x:{y:{z:[1,2,3,4,5,6,7]}}};
	test.deepEqual(util.get_field(doc,"x.y.z.1-"), [2,3,4,5,6,7]);
	test.done();
}

exports["util.set_field:existing field-path"] = function(test){

	var util = require("../lib/util");
	var doc = {x:{y:{z:1}}};

	util.set_field(doc,"x.y.z",5);

	test.equal( doc.x.y.z, 5);
	test.done();
}

exports["util.set_field:existing field-path array"] = function(test){

	var util = require("../lib/util");
	var doc = {x:{y:{z:[4,5,6]}}};

	util.set_field(doc,"x.y.z.3",7);

	test.deepEqual( doc.x.y.z, [4,5,6,7]);
	test.done();
}

exports["util.set_field:non existing field-path array"] = function(test){

	var util = require("../lib/util");
	var doc = {x:{y:{z:1}}};

	util.set_field(doc,"x.y.z.3",7)
	test.equal(doc.x.y.z,1);
	test.done();
}

exports["util.set_field:existing single field"] = function(test){

	var util = require("../lib/util");
	var doc = {x:1};

	util.set_field(doc,"x",5);

	test.equal( doc.x, 5);
	test.done();
}

exports["util.set_field:non existing field-path"] = function(test){

	var util = require("../lib/util");
	var doc = {x:{y:{z:1}}};

	util.set_field(doc,"x.nonexisting.z",5);

	test.equal( doc.x.y.z,1 );
	test.equal(doc.x.nonexisting.z,5)

	test.done();
}

exports["util.del_field:existing field-path"] = function(test){

	var util = require("../lib/util");
	var doc = {x:{y:{z:1}}};

	util.del_field(doc,"x.y.z");

	test.equal( doc.x.y.z, undefined );
	test.deepEqual(doc,{x:{y:{}}});

	test.done();
}

exports["util.del_field:existing field-path array"] = function(test){

	var util = require("../lib/util");
	var doc = {x:{y:{z:[4,5,6]}}};

	util.del_field(doc,"x.y.z.1");
	test.deepEqual( doc.x.y.z, [4,6] );

	test.done();
}

exports["util.del_field:non existing field-path array"] = function(test){

	var util = require("../lib/util");
	var doc = {x:{y:{z:1}}};

	util.del_field(doc,"x.y.z.1");
	test.done();
}

exports["util.del_field:existing single field"] = function(test){

	var util = require("../lib/util");
	var doc = {x:1};

	util.del_field(doc,"x");

	test.equal(doc.x, undefined );
	test.deepEqual( doc, {} );

	test.done();
}

exports["util.del_field:non existing field-path"] = function(test){

	var util = require("../lib/util");
	var doc = {x:{y:{z:1}}};

	util.del_field(doc,"x.nonexisting.z");

	test.equal( doc.x.y.z, 1 );
	test.done();
}

<commit_msg>Added test "util.has_joined:undefined".<commit_after>
var sandbox = require("sandboxed-module");

exports["util.has_joined: true"] = function(test){

	var util = require("../lib/util");
	var rcpts_arr = [{push_id:"123", push_type:"web"},{push_id:"456",push_type:"gcm"},{push_id:"789",push_type:"gcm"}];
	test.ok(util.has_joined(rcpts_arr,"123"));
	test.done();

}

exports["util.has_joined: false"] = function(test){

	var util = require("../lib/util");
	var rcpts_arr = [{push_id:"123", push_type:"web"},{push_id:"456",push_type:"gcm"},{push_id:"789",push_type:"gcm"}];
	test.equal( false, util.has_joined(rcpts_arr,"124"));
	test.done();

}

exports["util.has_joined: undefined"] = function(test){

	var util = require("../lib/util");
	var rcpts_arr = [{push_id:"123", push_type:"web"},{push_id:"456",push_type:"gcm"},{push_id:"789",push_type:"gcm"}];
	test.equal( false, util.has_joined(rcpts_arr,undefined));
	test.done();

}

exports["util.is_array: true"] = function(test){

	var util = require("../lib/util");
	var obj = [1,2,3];
	test.ok( util.is_array(obj) );
	test.done();

}

exports["util.is_array: false"] = function(test){

	var util = require("../lib/util");
	var obj = {};
	test.equal( false, util.is_array(obj) );
	obj = "";
	test.equal( false, util.is_array(obj) );
	obj = 5;
	test.equal( false, util.is_array(obj) );
	obj = function(){}
	test.equal( false, util.is_array(obj) );
	test.done();

}

exports["util.get_field:existing field-path"] = function(test){

	var util = require("../lib/util");
	var doc = {x:{y:{z:1}}};
	test.equal(util.get_field(doc,"x.y.z"), 1);
	test.done()
}

exports["util.get_field:existing single field"] = function(test){

	var util = require("../lib/util");
	var doc = {x:1};
	test.equal(util.get_field(doc,"x"), 1);
	test.done();
}

exports["util.get_field:non existing field-path"] = function(test){

	var util = require("../lib/util");
	var doc = {x:{y:{z:1}}};
	test.equal(util.get_field(doc,"x.nonexisting.z"), undefined);
	test.done()
}

exports["util.get_field:existing array index"] = function(test){

	var util = require("../lib/util");
	var doc = {x:{y:{z:[1,2,3]}}};
	test.equal(util.get_field(doc,"x.y.z.2"), 3);
	test.done();
}

exports["util.get_field:non existing array index"] = function(test){

	var util = require("../lib/util");
	var doc = {x:{y:{z:[1,2,3]}}};
	test.equal(util.get_field(doc,"x.y.z.10"), undefined);
	test.done();
}

exports["util.get_field:existing subarray"] = function(test){

	var util = require("../lib/util");
	var doc = {x:{y:{z:[1,2,3,4,5,6,7]}}};
	test.deepEqual(util.get_field(doc,"x.y.z.2-5"), [3,4,5,6]);
	test.done();
}

exports["util.get_field:existing subarray, no second index"] = function(test){

	var util = require("../lib/util");
	var doc = {x:{y:{z:[1,2,3,4,5,6,7]}}};
	test.deepEqual(util.get_field(doc,"x.y.z.1-"), [2,3,4,5,6,7]);
	test.done();
}

exports["util.set_field:existing field-path"] = function(test){

	var util = require("../lib/util");
	var doc = {x:{y:{z:1}}};

	util.set_field(doc,"x.y.z",5);

	test.equal( doc.x.y.z, 5);
	test.done();
}

exports["util.set_field:existing field-path array"] = function(test){

	var util = require("../lib/util");
	var doc = {x:{y:{z:[4,5,6]}}};

	util.set_field(doc,"x.y.z.3",7);

	test.deepEqual( doc.x.y.z, [4,5,6,7]);
	test.done();
}

exports["util.set_field:non existing field-path array"] = function(test){

	var util = require("../lib/util");
	var doc = {x:{y:{z:1}}};

	util.set_field(doc,"x.y.z.3",7)
	test.equal(doc.x.y.z,1);
	test.done();
}

exports["util.set_field:existing single field"] = function(test){

	var util = require("../lib/util");
	var doc = {x:1};

	util.set_field(doc,"x",5);

	test.equal( doc.x, 5);
	test.done();
}

exports["util.set_field:non existing field-path"] = function(test){

	var util = require("../lib/util");
	var doc = {x:{y:{z:1}}};

	util.set_field(doc,"x.nonexisting.z",5);

	test.equal( doc.x.y.z,1 );
	test.equal(doc.x.nonexisting.z,5)

	test.done();
}

exports["util.del_field:existing field-path"] = function(test){

	var util = require("../lib/util");
	var doc = {x:{y:{z:1}}};

	util.del_field(doc,"x.y.z");

	test.equal( doc.x.y.z, undefined );
	test.deepEqual(doc,{x:{y:{}}});

	test.done();
}

exports["util.del_field:existing field-path array"] = function(test){

	var util = require("../lib/util");
	var doc = {x:{y:{z:[4,5,6]}}};

	util.del_field(doc,"x.y.z.1");
	test.deepEqual( doc.x.y.z, [4,6] );

	test.done();
}

exports["util.del_field:non existing field-path array"] = function(test){

	var util = require("../lib/util");
	var doc = {x:{y:{z:1}}};

	util.del_field(doc,"x.y.z.1");
	test.done();
}

exports["util.del_field:existing single field"] = function(test){

	var util = require("../lib/util");
	var doc = {x:1};

	util.del_field(doc,"x");

	test.equal(doc.x, undefined );
	test.deepEqual( doc, {} );

	test.done();
}

exports["util.del_field:non existing field-path"] = function(test){

	var util = require("../lib/util");
	var doc = {x:{y:{z:1}}};

	util.del_field(doc,"x.nonexisting.z");

	test.equal( doc.x.y.z, 1 );
	test.done();
}

<|endoftext|>


<commit_before>'use strict';

/* global CodeMirror */
/*eslint no-script-url:0 */

import React from 'react';
import createReactClass from 'create-react-class';
import ReactDOM from 'react-dom';
import cx from 'classnames';

import TagTranslator from './tag-translator';
import _ from '../../undash';
import {keyCodes, ref} from '../../utils';
import HelperMixin from '../../mixins/helper';

var toString = function (value) {
  if (_.isUndefined(value) || _.isNull(value)) {
    return '';
  }
  return String(value);
};

/*
   Editor for tagged text. Renders text like "hello {{firstName}}"
   with replacement labels rendered in a pill box. Designed to load
   quickly when many separate instances of it are on the same
   page.

   Uses CodeMirror to edit text. To save memory the CodeMirror node is
   instantiated when the user moves the mouse into the edit area.
   Initially a read-only view using a simple div is shown.
 */
export default createReactClass({

  displayName: 'PrettyTextInput',

  mixins: [HelperMixin],

  componentDidMount: function() {
    this.createEditor();
  },

  componentDidUpdate: function(prevProps, prevState) {
    const hasReplaceChoicesChanged = !_.isEqual(prevProps.replaceChoices, this.props.replaceChoices);
    const hasCodeMirrorModeChanged = prevState.codeMirrorMode !== this.state.codeMirrorMode;
    if (hasCodeMirrorModeChanged || hasReplaceChoicesChanged) {
      // Changed from code mirror mode to read only mode or vice versa,
      // so setup the other editor.
      this.createEditor();
    }
    this.updateEditor();
  },

  componentWillUnmount: function() {
    if (this.state.codeMirrorMode) {
      this.removeCodeMirrorEditor();
    }
  },

  getInitialState: function() {
    var selectedChoices = this.props.selectedChoices;
    var replaceChoices = this.props.replaceChoices;
    var translator = TagTranslator(selectedChoices.concat(replaceChoices), this.props.config.humanize);

    return {
      // With number values, onFocus never fires, which means it stays read-only. So convert to string.
      value: toString(this.props.value),
      codeMirrorMode: false,
      isChoicesOpen: false,
      replaceChoices: replaceChoices,
      translator: translator,
      hasChanged: false
    };
  },

  componentWillReceiveProps: function(nextProps) {
    // If we're debouncing a change, then we should just ignore this props change,
    // because there will be another when we hit the trailing edge of the debounce.
    if (this.isDebouncingCodeMirrorChange) {
      return;
    }

    var selectedChoices = nextProps.selectedChoices;
    var replaceChoices = nextProps.replaceChoices;
    var nextState = {
      replaceChoices: replaceChoices,
      translator: TagTranslator(selectedChoices.concat(replaceChoices), this.props.config.humanize)
    };

    // Not sure what the null/undefined checks are here for, but changed from falsey which was breaking.
    if (this.state.value !== nextProps.value && !_.isUndefined(nextProps.value) && nextProps.value !== null) {
      nextState.value = toString(nextProps.value);
      if (this.state.hasChanged === false) {
        nextState.hasChanged = true;
      }
    }

    this.setState(nextState);
  },

  onChange: function (newValue) {
    this.props.onChange(newValue);
  },

  handleChoiceSelection: function (key, event) {
    const selectChoice = () => {
      var pos = this.state.selectedTagPos;
      var tag = '{{' + key + '}}';

      this.isInserting = true;
      if (pos) {
        this.codeMirror.replaceRange(tag, {line: pos.line, ch: pos.start}, {line: pos.line, ch: pos.stop});
      } else {
        this.codeMirror.replaceSelection(tag, 'end');
      }
      this.isInserting = false;
      this.codeMirror.focus();

      this.setState({ isChoicesOpen: false, selectedTagPos: null });
    };
    if (this.state.codeMirrorMode) {
      selectChoice();
    } else if (this.props.readOnly) {
      // hackety hack to stop dropdown choices from toggling
      event.stopPropagation();
      this.isInserting = true;
      this.onChange('{{' + key + '}}');
      this.isInserting = false;
      this.setState({ isChoicesOpen: false });
    } else {
      this.switchToCodeMirror(selectChoice);
    }
  },

  onFocusClick: function () {
    this.onFocusWrapper(true);
  },

  onFocusWrapper: function (isFromClick) {
    this.switchToCodeMirror(() => {
      this.codeMirror.focus();
      this.codeMirror.setCursor(this.codeMirror.lineCount(), 0);
    }, () => {
      // If this is from a click, we lose focus, so force it focused!
      if (isFromClick) {
        setTimeout(() => {
          if (this.codeMirror && !this.codeMirror.state.focused) {
            this.codeMirror.focus();
            this.codeMirror.setCursor(this.codeMirror.lineCount(), 0);
          }
        }, 0);
      }
    });
  },

  focus() {
    if (this.codeMirror) {
      this.focusCodeMirror();
    } else {
      this.switchToCodeMirror(() => {
        this.focusCodeMirror();
      });
    }
  },

  focusCodeMirror() {
    if (this.codeMirror) {
      this.codeMirror.focus();
    }
  },

  onFocusCodeMirror() {
    this.setState({ hasFocus: true });
    this.props.onFocus();
  },

  onBlur() {
    if (this.isDebouncingCodeMirrorChange) {
      this.onChangeAndTagCodeMirror();
      this.isDebouncingCodeMirrorChange = false;
      this.setState({ hasFocus: false }, this.props.onBlur);
    } else {
      this.setState({ hasFocus: false });
      this.props.onBlur();
    }
  },

  insertBtn: function () {
    if (this.isReadOnly() && !this.hasReadOnlyControls()) {
      return null;
    }
    var onInsertClick = function () {
      this.setState({selectedTagPos: null});
      this.onToggleChoices();
    };

    const props = {
      ref: ref(this, 'toggle'),
      onClick: onInsertClick.bind(this),
      readOnly: this.isReadOnly(),
      field: this.props.field
    };
    return this.props.config.createElement('insert-button', props, 'Insert...');
  },

  choices: function () {
    if (this.isReadOnly()) {
      return null;
    }

    return this.props.config.createElement('choices', {
      ref: ref(this, 'choices'),
      onFocusSelect: this.focusCodeMirror,
      choices: this.state.replaceChoices,
      open: this.state.isChoicesOpen,
      ignoreCloseNodes: this.getCloseIgnoreNodes,
      onSelect: this.handleChoiceSelection,
      onClose: this.onCloseChoices,
      isAccordion: this.props.isAccordion,
      field: this.props.field,
      onChoiceAction: this.onChoiceAction
    });
  },

  onChoiceAction: function (choice) {
    this.setState({
      isChoicesOpen: !!choice.isOpen
    });
    this.onStartAction(choice.action, choice);
  },

  wrapperTabIndex() {
    if (this.props.readOnly || this.state.codeMirrorMode) {
      return null;
    }
    return this.props.tabIndex || 0;
  },

  onKeyDown(event) {
    if (!this.isReadOnly()) {
      if (event.keyCode === keyCodes.ESC) {
        event.preventDefault();
        event.stopPropagation();
        if (this.state.isChoicesOpen) {
          this.onToggleChoices();
          this.focusCodeMirror();
        }
      } else if (!this.state.isChoicesOpen) {
        // TODO: sane shortcut for opening choices
        // Below does not work yet. Ends up dumping { into search input.
        // if (this.codeMirror) {
        //   if (event.keyCode === keyCodes['['] && event.shiftKey) {
        //     const cursor = this.codeMirror.getCursor();
        //     const value = this.codeMirror.getValue();
        //     const lines = value.split('\n');
        //     const line = lines[cursor.line];
        //     if (line) {
        //       const prevChar = line[cursor.ch - 1];
        //       if (prevChar === '{') {
        //         this.onToggleChoices();
        //       }
        //     }
        //   }
        // }
      } else {
        if (this.choicesRef && this.choicesRef.onKeyDown) {
          this.choicesRef.onKeyDown(event);
        }
      }
    }
  },

  render: function() {
    return this.renderWithConfig();
  },

  renderDefault: function () {
    var textBoxClasses = cx(_.extend({}, this.props.classes, {
      'pretty-text-box': true,
      placeholder: this.hasPlaceholder(),
      'has-focus': this.state.hasFocus
    }));

    // Render read-only version.
    return (

        {this.insertBtn()}
        {this.choices()}

    );
  },

  getCloseIgnoreNodes: function () {
    return this.toggleRef;
  },

  onToggleChoices: function () {
    this.setChoicesOpen(!this.state.isChoicesOpen);
  },

  setChoicesOpen: function (isOpen) {
    var action = isOpen ? 'open-replacements' : 'close-replacements';
    this.onStartAction(action);
    this.setState({ isChoicesOpen: isOpen });
  },

  onCloseChoices: function () {
    if (this.state.isChoicesOpen) {
      this.setChoicesOpen(false);
    }
  },

  createEditor: function () {
    if (this.state.codeMirrorMode) {
      this.createCodeMirrorEditor();
    } else {
      this.createReadonlyEditor();
    }
  },

  updateEditor: function () {
    if (this.state.codeMirrorMode) {
      var codeMirrorValue = this.codeMirror.getValue();
      if (!this.hasPlaceholder() && codeMirrorValue !== this.state.value) {
        // switch back to read-only mode to make it easier to render
        this.removeCodeMirrorEditor();
        this.createReadonlyEditor();
        this.setState({
          codeMirrorMode: false
        });
      }
    } else {
      this.createReadonlyEditor();
    }
  },

  maybeSetCursorPosition(position) {
    if (position && this.codeMirror) {
      this.codeMirror.setCursor(position);
    }
  },

  createCodeMirrorEditor: function () {
    var options = {
      tabindex: this.props.tabIndex || 0,
      lineWrapping: true,
      placeholder: toString(this.props.config.fieldPlaceholder(this.props.field)),
      value: toString(this.state.value),
      readOnly: false,
      mode: null,
      extraKeys: {
        Tab: false,
        'Shift-Tab': false
      }
    };

    var textBox = this.textBoxRef;
    textBox.innerHTML = ''; // release any previous read-only content so it can be GC'ed
    const pos = this.codeMirror ? this.codeMirror.getCursor() : null;
    this.codeMirror = CodeMirror(textBox, options);
    this.codeMirror.on('change', this.onCodeMirrorChange);
    this.codeMirror.on('focus', this.onFocusCodeMirror);

    this.tagCodeMirror(pos);
  },

  tagCodeMirror: function (cursorPosition) {
    var positions = this.state.translator.getTagPositions(this.codeMirror.getValue());
    var self = this;

    var tagOps = function () {
      positions.forEach(function (pos) {
        var node = self.createTagNode(pos);
        self.codeMirror.markText({line: pos.line, ch: pos.start},
          {line: pos.line, ch: pos.stop},
          {replacedWith: node, handleMouseEvents: true});
      });
    };

    // Make sure we apply those operations after React has made its rendering pass.
    // As React 16 is asynchronous and uses rAF, it's safe to assume that this will
    // be called after React has patched the DOM.
    //
    // But if we are calling this function from CodeMirror itself, we want to stay
    // in sync with it's internal state.
    if (this.isDebouncingCodeMirrorChange) {
      this.codeMirror.operation(tagOps);
      this.maybeSetCursorPosition(cursorPosition);
    }
    else {
      requestAnimationFrame(() => {
        this.codeMirror.operation(tagOps);
        this.maybeSetCursorPosition(cursorPosition);
      });
    }
  },

  onChangeAndTagCodeMirror() {
    if (!this.codeMirror) {
      // We might have erased our codemirror instance before hitting the trailing
      // end of the debounce. If so, get the value out of state.
      if (this.props.value !== this.state.value) {
        this.onChange(this.state.value);
      }
      return;
    }
    this.onChange(this.codeMirror.getValue());
    this.tagCodeMirror();
  },

  onCodeMirrorChange: function () {
    var newValue = this.codeMirror.getValue();
    this.setState({value: newValue});

    // Immediately change and tag if inserting.
    if (this.isInserting) {
      this.onChangeAndTagCodeMirror();
      return;
    }

    // Otherwise, debounce so CodeMirror doesn't die.
    if (!this.debounceCodeMirrorChange) {
      this.debounceCodeMirrorChange = _.debounce(() => {
        if (this.isDebouncingCodeMirrorChange) {
          this.onChangeAndTagCodeMirror();
          this.isDebouncingCodeMirrorChange = false;
        }
      }, 200);
    }
    this.isDebouncingCodeMirrorChange = true;
    this.debounceCodeMirrorChange();
  },

  /* Return true if we should render the placeholder */
  hasPlaceholder: function () {
    return !this.state.value;
  },

  createReadonlyEditor: function () {
    var textBoxNode = this.textBoxRef;

    if (this.hasPlaceholder()) {
      return ReactDOM.render({this.props.field.placeholder}, textBoxNode);
    }

    var tokens = this.props.config.tokenize(this.state.value);
    var self = this;
    var nodes = tokens.map(function (part, i) {
      if (part.type === 'tag') {
        var label = self.state.translator.getLabel(part.value);
        var props = {key: i, tag: part.value, replaceChoices: self.state.replaceChoices, field: self.props.field};
        return self.props.config.createElement('pretty-tag', props, label);
      }
      return {part.value};
    });

    return ReactDOM.render({nodes}, textBoxNode);
  },

  removeCodeMirrorEditor: function () {
    var textBoxNode = this.textBoxRef;
    var cmNode = textBoxNode.firstChild;
    textBoxNode.removeChild(cmNode);
    this.codeMirror.off('change', this.onCodeMirrorChange);
    this.codeMirror.off('focus', this.onFocusCodeMirror);
    this.codeMirror = null;
  },

  switchToCodeMirror: function (cb, alreadySwitchedCb) {
    if (this.isReadOnly()) {
      return; // never render in code mirror if read-only
    }

    if (!this.props.readOnly) {
      if (!this.state.codeMirrorMode) {
        this.setState({codeMirrorMode: true}, () => {
          if (this.codeMirror && _.isFunction(cb)) {
            cb();
          }
        });
      } else {
        if (_.isFunction(alreadySwitchedCb)) {
          alreadySwitchedCb();
        }
      }
    }
  },

  onTagClick: function () {
    const cursor = this.codeMirror.getCursor();
    const pos = this.state.translator.getTrueTagPosition(this.state.value, cursor);

    this.setState({selectedTagPos: pos});
    this.onToggleChoices();
  },

  createTagNode: function (pos) {
    var node = document.createElement('span');
    var label = this.state.translator.getLabel(pos.tag);
    var config = this.props.config;

    var props = {onClick: this.onTagClick, field: this.props.field, tag: pos.tag};

    ReactDOM.render(
      config.createElement('pretty-tag', props, label),
      node
    );

    return node;
  }
});
<commit_msg>add onFocus event listener to pretty text<commit_after>'use strict';

/* global CodeMirror */
/*eslint no-script-url:0 */

import React from 'react';
import createReactClass from 'create-react-class';
import ReactDOM from 'react-dom';
import cx from 'classnames';

import TagTranslator from './tag-translator';
import _ from '../../undash';
import {keyCodes, ref} from '../../utils';
import HelperMixin from '../../mixins/helper';

var toString = function (value) {
  if (_.isUndefined(value) || _.isNull(value)) {
    return '';
  }
  return String(value);
};

/*
   Editor for tagged text. Renders text like "hello {{firstName}}"
   with replacement labels rendered in a pill box. Designed to load
   quickly when many separate instances of it are on the same
   page.

   Uses CodeMirror to edit text. To save memory the CodeMirror node is
   instantiated when the user moves the mouse into the edit area.
   Initially a read-only view using a simple div is shown.
 */
export default createReactClass({

  displayName: 'PrettyTextInput',

  mixins: [HelperMixin],

  componentDidMount: function() {
    this.createEditor();
  },

  componentDidUpdate: function(prevProps, prevState) {
    const hasReplaceChoicesChanged = !_.isEqual(prevProps.replaceChoices, this.props.replaceChoices);
    const hasCodeMirrorModeChanged = prevState.codeMirrorMode !== this.state.codeMirrorMode;
    if (hasCodeMirrorModeChanged || hasReplaceChoicesChanged) {
      // Changed from code mirror mode to read only mode or vice versa,
      // so setup the other editor.
      this.createEditor();
    }
    this.updateEditor();
  },

  componentWillUnmount: function() {
    if (this.state.codeMirrorMode) {
      this.removeCodeMirrorEditor();
    }
  },

  getInitialState: function() {
    var selectedChoices = this.props.selectedChoices;
    var replaceChoices = this.props.replaceChoices;
    var translator = TagTranslator(selectedChoices.concat(replaceChoices), this.props.config.humanize);

    return {
      // With number values, onFocus never fires, which means it stays read-only. So convert to string.
      value: toString(this.props.value),
      codeMirrorMode: false,
      isChoicesOpen: false,
      replaceChoices: replaceChoices,
      translator: translator,
      hasChanged: false
    };
  },

  componentWillReceiveProps: function(nextProps) {
    // If we're debouncing a change, then we should just ignore this props change,
    // because there will be another when we hit the trailing edge of the debounce.
    if (this.isDebouncingCodeMirrorChange) {
      return;
    }

    var selectedChoices = nextProps.selectedChoices;
    var replaceChoices = nextProps.replaceChoices;
    var nextState = {
      replaceChoices: replaceChoices,
      translator: TagTranslator(selectedChoices.concat(replaceChoices), this.props.config.humanize)
    };

    // Not sure what the null/undefined checks are here for, but changed from falsey which was breaking.
    if (this.state.value !== nextProps.value && !_.isUndefined(nextProps.value) && nextProps.value !== null) {
      nextState.value = toString(nextProps.value);
      if (this.state.hasChanged === false) {
        nextState.hasChanged = true;
      }
    }

    this.setState(nextState);
  },

  onChange: function (newValue) {
    this.props.onChange(newValue);
  },

  handleChoiceSelection: function (key, event) {
    const selectChoice = () => {
      var pos = this.state.selectedTagPos;
      var tag = '{{' + key + '}}';

      this.isInserting = true;
      if (pos) {
        this.codeMirror.replaceRange(tag, {line: pos.line, ch: pos.start}, {line: pos.line, ch: pos.stop});
      } else {
        this.codeMirror.replaceSelection(tag, 'end');
      }
      this.isInserting = false;
      this.codeMirror.focus();

      this.setState({ isChoicesOpen: false, selectedTagPos: null });
    };
    if (this.state.codeMirrorMode) {
      selectChoice();
    } else if (this.props.readOnly) {
      // hackety hack to stop dropdown choices from toggling
      event.stopPropagation();
      this.isInserting = true;
      this.onChange('{{' + key + '}}');
      this.isInserting = false;
      this.setState({ isChoicesOpen: false });
    } else {
      this.switchToCodeMirror(selectChoice);
    }
  },

  onFocusClick: function () {
    this.onFocusWrapper(true);
  },

  onFocusWrapper: function (isFromClick) {
    this.switchToCodeMirror(() => {
      this.codeMirror.focus();
      this.codeMirror.setCursor(this.codeMirror.lineCount(), 0);
    }, () => {
      // If this is from a click, we lose focus, so force it focused!
      if (isFromClick) {
        setTimeout(() => {
          if (this.codeMirror && !this.codeMirror.state.focused) {
            this.codeMirror.focus();
            this.codeMirror.setCursor(this.codeMirror.lineCount(), 0);
          }
        }, 0);
      }
    });
  },

  focus() {
    if (this.codeMirror) {
      this.focusCodeMirror();
    } else {
      this.switchToCodeMirror(() => {
        this.focusCodeMirror();
      });
    }
  },

  focusCodeMirror() {
    if (this.codeMirror) {
      this.codeMirror.focus();
    }
  },

  onFocusCodeMirror() {
    this.setState({ hasFocus: true });
    this.props.onFocus();
  },

  onBlur() {
    if (this.isDebouncingCodeMirrorChange) {
      this.onChangeAndTagCodeMirror();
      this.isDebouncingCodeMirrorChange = false;
      this.setState({ hasFocus: false }, this.props.onBlur);
    } else {
      this.setState({ hasFocus: false });
      this.props.onBlur();
    }
  },

  insertBtn: function () {
    if (this.isReadOnly() && !this.hasReadOnlyControls()) {
      return null;
    }
    var onInsertClick = function () {
      this.setState({selectedTagPos: null});
      this.onToggleChoices();
    };

    const props = {
      ref: ref(this, 'toggle'),
      onClick: onInsertClick.bind(this),
      readOnly: this.isReadOnly(),
      field: this.props.field
    };
    return this.props.config.createElement('insert-button', props, 'Insert...');
  },

  choices: function () {
    if (this.isReadOnly()) {
      return null;
    }

    return this.props.config.createElement('choices', {
      ref: ref(this, 'choices'),
      onFocusSelect: this.focusCodeMirror,
      choices: this.state.replaceChoices,
      open: this.state.isChoicesOpen,
      ignoreCloseNodes: this.getCloseIgnoreNodes,
      onSelect: this.handleChoiceSelection,
      onClose: this.onCloseChoices,
      isAccordion: this.props.isAccordion,
      field: this.props.field,
      onChoiceAction: this.onChoiceAction
    });
  },

  onChoiceAction: function (choice) {
    this.setState({
      isChoicesOpen: !!choice.isOpen
    });
    this.onStartAction(choice.action, choice);
  },

  wrapperTabIndex() {
    if (this.props.readOnly || this.state.codeMirrorMode) {
      return null;
    }
    return this.props.tabIndex || 0;
  },

  onKeyDown(event) {
    if (!this.isReadOnly()) {
      if (event.keyCode === keyCodes.ESC) {
        event.preventDefault();
        event.stopPropagation();
        if (this.state.isChoicesOpen) {
          this.onToggleChoices();
          this.focusCodeMirror();
        }
      } else if (!this.state.isChoicesOpen) {
        // TODO: sane shortcut for opening choices
        // Below does not work yet. Ends up dumping { into search input.
        // if (this.codeMirror) {
        //   if (event.keyCode === keyCodes['['] && event.shiftKey) {
        //     const cursor = this.codeMirror.getCursor();
        //     const value = this.codeMirror.getValue();
        //     const lines = value.split('\n');
        //     const line = lines[cursor.line];
        //     if (line) {
        //       const prevChar = line[cursor.ch - 1];
        //       if (prevChar === '{') {
        //         this.onToggleChoices();
        //       }
        //     }
        //   }
        // }
      } else {
        if (this.choicesRef && this.choicesRef.onKeyDown) {
          this.choicesRef.onKeyDown(event);
        }
      }
    }
  },

  render: function() {
    return this.renderWithConfig();
  },

  renderDefault: function () {
    var textBoxClasses = cx(_.extend({}, this.props.classes, {
      'pretty-text-box': true,
      placeholder: this.hasPlaceholder(),
      'has-focus': this.state.hasFocus
    }));

    // Render read-only version.
    return (

        {this.insertBtn()}
        {this.choices()}

    );
  },

  getCloseIgnoreNodes: function () {
    return this.toggleRef;
  },

  onToggleChoices: function () {
    this.setChoicesOpen(!this.state.isChoicesOpen);
  },

  setChoicesOpen: function (isOpen) {
    var action = isOpen ? 'open-replacements' : 'close-replacements';
    this.onStartAction(action);
    this.setState({ isChoicesOpen: isOpen });
  },

  onCloseChoices: function () {
    if (this.state.isChoicesOpen) {
      this.setChoicesOpen(false);
    }
  },

  createEditor: function () {
    if (this.state.codeMirrorMode) {
      this.createCodeMirrorEditor();
    } else {
      this.createReadonlyEditor();
    }
  },

  updateEditor: function () {
    if (this.state.codeMirrorMode) {
      var codeMirrorValue = this.codeMirror.getValue();
      if (!this.hasPlaceholder() && codeMirrorValue !== this.state.value) {
        // switch back to read-only mode to make it easier to render
        this.removeCodeMirrorEditor();
        this.createReadonlyEditor();
        this.setState({
          codeMirrorMode: false
        });
      }
    } else {
      this.createReadonlyEditor();
    }
  },

  maybeSetCursorPosition(position) {
    if (position && this.codeMirror) {
      this.codeMirror.setCursor(position);
    }
  },

  createCodeMirrorEditor: function () {
    var options = {
      tabindex: this.props.tabIndex || 0,
      lineWrapping: true,
      placeholder: toString(this.props.config.fieldPlaceholder(this.props.field)),
      value: toString(this.state.value),
      readOnly: false,
      mode: null,
      extraKeys: {
        Tab: false,
        'Shift-Tab': false
      }
    };

    var textBox = this.textBoxRef;
    textBox.innerHTML = ''; // release any previous read-only content so it can be GC'ed
    const pos = this.codeMirror ? this.codeMirror.getCursor() : null;
    this.codeMirror = CodeMirror(textBox, options);
    this.codeMirror.on('change', this.onCodeMirrorChange);
    this.codeMirror.on('focus', this.onFocusCodeMirror);

    this.tagCodeMirror(pos);
  },

  tagCodeMirror: function (cursorPosition) {
    var positions = this.state.translator.getTagPositions(this.codeMirror.getValue());
    var self = this;

    var tagOps = function () {
      positions.forEach(function (pos) {
        var node = self.createTagNode(pos);
        self.codeMirror.markText({line: pos.line, ch: pos.start},
          {line: pos.line, ch: pos.stop},
          {replacedWith: node, handleMouseEvents: true});
      });
    };

    // Make sure we apply those operations after React has made its rendering pass.
    // As React 16 is asynchronous and uses rAF, it's safe to assume that this will
    // be called after React has patched the DOM.
    //
    // But if we are calling this function from CodeMirror itself, we want to stay
    // in sync with it's internal state.
    if (this.isDebouncingCodeMirrorChange) {
      this.codeMirror.operation(tagOps);
      this.maybeSetCursorPosition(cursorPosition);
    }
    else {
      requestAnimationFrame(() => {
        this.codeMirror.operation(tagOps);
        this.maybeSetCursorPosition(cursorPosition);
      });
    }
  },

  onChangeAndTagCodeMirror() {
    if (!this.codeMirror) {
      // We might have erased our codemirror instance before hitting the trailing
      // end of the debounce. If so, get the value out of state.
      if (this.props.value !== this.state.value) {
        this.onChange(this.state.value);
      }
      return;
    }
    this.onChange(this.codeMirror.getValue());
    this.tagCodeMirror();
  },

  onCodeMirrorChange: function () {
    var newValue = this.codeMirror.getValue();
    this.setState({value: newValue});

    // Immediately change and tag if inserting.
    if (this.isInserting) {
      this.onChangeAndTagCodeMirror();
      return;
    }

    // Otherwise, debounce so CodeMirror doesn't die.
    if (!this.debounceCodeMirrorChange) {
      this.debounceCodeMirrorChange = _.debounce(() => {
        if (this.isDebouncingCodeMirrorChange) {
          this.onChangeAndTagCodeMirror();
          this.isDebouncingCodeMirrorChange = false;
        }
      }, 200);
    }
    this.isDebouncingCodeMirrorChange = true;
    this.debounceCodeMirrorChange();
  },

  /* Return true if we should render the placeholder */
  hasPlaceholder: function () {
    return !this.state.value;
  },

  createReadonlyEditor: function () {
    var textBoxNode = this.textBoxRef;

    if (this.hasPlaceholder()) {
      return ReactDOM.render({this.props.field.placeholder}, textBoxNode);
    }

    var tokens = this.props.config.tokenize(this.state.value);
    var self = this;
    var nodes = tokens.map(function (part, i) {
      if (part.type === 'tag') {
        var label = self.state.translator.getLabel(part.value);
        var props = {key: i, tag: part.value, replaceChoices: self.state.replaceChoices, field: self.props.field};
        return self.props.config.createElement('pretty-tag', props, label);
      }
      return {part.value};
    });

    return ReactDOM.render({nodes}, textBoxNode);
  },

  removeCodeMirrorEditor: function () {
    var textBoxNode = this.textBoxRef;
    var cmNode = textBoxNode.firstChild;
    textBoxNode.removeChild(cmNode);
    this.codeMirror.off('change', this.onCodeMirrorChange);
    this.codeMirror.off('focus', this.onFocusCodeMirror);
    this.codeMirror = null;
  },

  switchToCodeMirror: function (cb, alreadySwitchedCb) {
    if (this.isReadOnly()) {
      return; // never render in code mirror if read-only
    }

    if (!this.props.readOnly) {
      if (!this.state.codeMirrorMode) {
        this.setState({codeMirrorMode: true}, () => {
          if (this.codeMirror && _.isFunction(cb)) {
            cb();
          }
        });
      } else {
        if (_.isFunction(alreadySwitchedCb)) {
          alreadySwitchedCb();
        }
      }
    }
  },

  onTagClick: function () {
    const cursor = this.codeMirror.getCursor();
    const pos = this.state.translator.getTrueTagPosition(this.state.value, cursor);

    this.setState({selectedTagPos: pos});
    this.onToggleChoices();
  },

  createTagNode: function (pos) {
    var node = document.createElement('span');
    var label = this.state.translator.getLabel(pos.tag);
    var config = this.props.config;

    var props = {onClick: this.onTagClick, field: this.props.field, tag: pos.tag};

    ReactDOM.render(
      config.createElement('pretty-tag', props, label),
      node
    );

    return node;
  }
});
<|endoftext|>