<commit_before>/**
 * Controller 基类
 * @return {[type]} [description]
 */
var fs = require("fs");
var path = require("path");
var url = require("url");

module.exports = Class(function() {
    "use strict";
    //callback正则
    var callbackReg = /[^\w\.]/g;

    return {
        /**
         * 初始化执行方法
         * @param  {[type]} http [description]
         * @return {[type]}      [description]
         */
        init: function(http) {
            this.http = http;
            this.view = null;
            //将http数据打到模版里
            this.assign("http", this.http);
            //将配置信息打到模版里
            this.assign("config", C());
            //设置变量别名
            this.set = this.assign;
        },
        /**
         * 获取客户端的ip
         * @return {[type]} [description]
         */
        ip: function() {
            return this.http.ip();
        },
        /**
         * 实例化View类
         * @return {[type]} [description]
         */
        initView: function() {
            if (!this.view) {
                this.view = thinkRequire("View")(this.http);
            }
            return this.view;
        },
        /**
         * 是否是GET请求
         * @return {Boolean} [description]
         */
        isGet: function() {
            return this.http.method === 'get';
        },
        /**
         * 是否是POST请求
         * @return {Boolean} [description]
         */
        isPost: function() {
            return this.http.method === 'post';
        },
        /**
         * 是否是特定METHOD请求
         * @param  {[type]}  method [description]
         * @return {Boolean}        [description]
         */
        isMethod: function(method) {
            return this.http.method === method;
        },
        /**
         * 是否是AJAX请求
         * @return {Boolean} [description]
         */
        isAjax: function(method) {
            //请求类型判断
            if (method && this.http.method !== method) {
                return false;
            }
            return this.header("x-requested-with") === "XMLHttpRequest";
        },
        /**
         * 是否是websocket请求
         * @return {Boolean} [description]
         */
        isWebSocket: function(){
            return !!this.http.websocket;
        },
        /**
         * 是否是jsonp接口
         * @return {Boolean} [description]
         */
        isJsonp: function(name){
            name = name || C('url_callback_name');
            return !!this.http.get(name);
        },
        /**
         * 获取QUERY参数
         * @param  {[type]} name [description]
         * @return {[type]}      [description]
         */
        get: function(name) {
            if (name === undefined) {
                return this.http.get;
            }
            return this.http.get[name] || "";
        },
        /**
         * 获取POST参数
         * @param  {[type]} name [description]
         * @return {[type]}      [description]
         */
        post: function(name) {
            var http = this.http;
            if (http.postPromise) {
                return http.postPromise.then(function(data){
                    return name ? (data[name] || "") : data;
                })
            }
            return name ? (http.post[name] || "") : http.post;
        },
        /**
         * 获取参数
         * @param  {[type]} name [description]
         * @return {[type]}      [description]
         */
        param: function(name) {
            return this.post(name) || this.get(name);
        },
        /**
         * 获取上传的文件
         * @param  {[type]} name [description]
         * @return {[type]}      [description]
         */
        file: function(name) {
            var http = this.http;
            if (http.postPromise) {
                return http.postPromise.then(function(){
                    return name ? (http.file[name] || "") : http.file;
                })
            }
            return name ? (http.file[name] || "") : http.file;
        },
        /**
         * header操作
         * @param  {[type]} name  [description]
         * @param  {[type]} value [description]
         * @return {[type]}       [description]
         */
        header: function(name, value) {
            if (isObject(name)) {
                for (var key in name) {
                    this.header(key, name[key]);
                }
                return this;
            }
            if (value !== undefined) {
                //对是否发送了Content-Type头信息进行标记
                if (name.toLowerCase() === 'content-type') {
                    if (!this.http.cthIsSend) {
                        if (value.toLowerCase().indexOf("charset=") === -1) {
                            value += "; charset=" + C("encoding");
                        }
                        //Content-Type Header is Send
                        this.http.cthIsSend = true;
                        this.http.setHeader(name, value);
                    }
                }else{
                    this.http.setHeader(name, value);
                }
                return this;
            }
            if (name === undefined) {
                return this.http.headers;
            }
            return this.http.getHeader(name);
        },
        /**
         * 获取userAgent
         * @return {[type]} [description]
         */
        userAgent: function(){
            return this.http.headers['user-agent'] || "";
        },
        /**
         * 获取referrer
         * @return {[type]} [description]
         */
        referer: function(host){
            var referer = this.http.headers.referer || this.http.headers.referfer || "";
            if (!referer || !host) {
                return referer;
            }
            var info = url.parse(referer);
            return info.hostname;
        },
        /**
         * cookie操作
         * @param  {[type]} name    [description]
         * @param  {[type]} value   [description]
         * @param  {[type]} options [description]
         * @return {[type]}         [description]
         */
        cookie: function(name, value, options) {
            if (value !== undefined) {
                this.http.setCookie(name, value, options);
                return this;
            }
            return name === undefined ? this.http.cookie : (this.http.cookie[name] || "");
        },
        /**
         * session
         * 如果是get操作，则返回一个promise
         * @param  {[type]} name  [description]
         * @param  {[type]} value [description]
         * @return {[type]}       [description]
         */
        session: function(name, value) {
            thinkRequire('Session').start(this.http);
            var instance = this.http.session;
            if (name === undefined) {
                return instance.rm();
            }
            if (value !== undefined) {
                return instance.set(name, value);
            }
            return instance.get(name);
        },
        /**
         * 跳转，返回一个pendding promise阻止后面继续执行
         * @param  {[type]} url  [description]
         * @param  {[type]} code [description]
         * @return {[type]}      [description]
         */
        redirect: function(url, code) {
            this.http.redirect(url, code);
            return getDefer().promise;
        },
        /**
         * 赋值变量到模版
         * @param  {[type]} name  [description]
         * @param  {[type]} value [description]
         * @return {[type]}       [description]
         */
        assign: function(name, value) {
            if (arguments.length === 1) {
                return this.initView().assign(name);
            }
            return this.initView().assign(name, value);
        },
        /**
         * 获取解析后的模版内容
         * @param  {[type]} templateFile [description]
         * @param  {[type]} content      [description]
         * @return {[type]}              [description]
         */
        fetch: function(templateFile, content) {
            return this.initView().fetch(templateFile, content);
        },
        /**
         * 输出模版内容
         * @param  {[type]} templateFile [description]
         * @param  {[type]} charset      [description]
         * @param  {[type]} contentType  [description]
         * @param  {[type]} content      [description]
         * @return {[type]}              [description]
         */
        display: function(templateFile, charset, contentType, content) {
            return this.initView().display(templateFile, charset, contentType, content);
        },
        /**
         * 调用另一个controll里的aciton
         * 可以跨分组
         * A("Admin/Test/index")
         * @param  {[type]} action [description]
         * @return {[type]}        [description]
         */
        action: function(action, data) {
            //自动补group
            if (action.split(":").length === 2) {
                action = this.http.group + ':' + action;
            }
            return A(action, this.http, data);
        },
        /**
         * jsonp格式输出
         * @param  {[type]} data  [description]
         * @param  {[type]} jsonp [description]
         * @return {[type]}       [description]
         */
        jsonp: function(data) {
            this.type(C("json_content_type"));
            var callback = this.get(C("url_callback_name"));
            //过滤callback值里的非法字符
            callback = callback.replace(callbackReg, "");
            if (callback) {
                this.echo(callback + "(");
                this.echo(data);
                this.end(")");
            } else {
                this.end(data);
            }
        },
        /**
         * json格式输出
         * @param  {[type]} data [description]
         * @return {[type]}      [description]
         */
        json: function(data){
            this.type(C("json_content_type"));
            return this.end(data);
        },
        /**
         * 设置http响应状态码
         * @param  {[type]} status [description]
         * @return {[type]}        [description]
         */
        status: function(status) {
            var res = this.http.res;
            if (!res.headersSent) {
                res.statusCode = status || 404;
            }
        },
        /**
         * 输出内容
         * 自动JSON.stringify
         * 自定将数字等转化为字符串
         * @param  {[type]} obj [description]
         * @return {[type]}     [description]
         */
        echo: function(obj, encoding) {
            //自动发送Content-Type的header
            if (C('auto_send_content_type')) {
                this.type(C("tpl_content_type"));
            }
            return this.http.echo(obj, encoding);
        },
        /**
         * 结束输出，输出完成时一定要调用这个方法
         * @param  {[type]} obj [description]
         * @return {[type]}     [description]
         */
        end: function(obj, encoding) {
            if (obj) {
                this.echo(obj, encoding);
            }
            this.http.end();
        },
        /**
         * 发送Content-Type
         * @param  {[type]} type [description]
         * @return {[type]}      [description]
         */
        type: function(ext){
            if (ext.indexOf('/') === -1) {
                ext = require('mime').lookup(ext);
            }
            this.header("Content-Type", ext);
        },
        /**
         * 下载文件
         * @return {[type]} [description]
         */
        download: function(file, contentType, callback) {
            if (isFunction(contentType)) {
                callback = contentType;
                contentType = "";
            }
            if (!contentType || contentType.indexOf('/') === -1) {
                contentType = require('mime').lookup(contentType || file);
            }
            var http = this.http;
            var fileStream = fs.createReadStream(file);
            this.type(contentType);
            http.setHeader("Content-Disposition", 'attachment; filename="' + path.basename(file) + '"');
            fileStream.pipe(http.res);
            fileStream.on("end", function() {
                http.end();
                return callback && callback();
            });
        },
        /**
         * 正常json数据输出
         * @param  {[type]} data [description]
         * @return {[type]}      [description]
         */
        success: function(data){
            var obj = getObject([C('error_no_key'), C('error_msg_key')], [0, ""]);
            if (data !== undefined) {
                obj.data = data;
            }
            this.type(C('json_content_type'));
            this.end(obj);
            return getDefer().promise;
        },
        /**
         * 异常json数据数据
         * @param  {[type]} errno  [description]
         * @param  {[type]} errmsg [description]
         * @param  {[type]} extra  [description]
         * @return {[type]}        [description]
         */
        error: function(errno, errmsg, data){
            var obj;
            if (isObject(errno)) {
                data = errmsg;
                obj = extend({}, errno);
            }else{
                if (!isNumber(errno)) {
                    data = errmsg;
                    errmsg = errno;
                    errno = C('error_no_default_value');
                }
                obj = getObject([C('error_no_key'), C('error_msg_key')], [errno, errmsg]);
            }
            if (data !== undefined) {
                obj.data = data;
            }
            this.type(C('json_content_type'));
            this.end(obj);
            return getDefer().promise;
        },
        sendTime: function(name){
            return this.http.sendTime(name);
        },
        /**
         * 对数据进行过滤
         * @param  {[type]} data [description]
         * @param  {[type]} type [description]
         * @return {[type]}      [description]
         */
        filter: function() {
            var filter = thinkRequire("Filter").filter;
            return filter.apply(null, arguments);
        },
        /**
         * 校验一个值是否合法
         * @param  {[type]} data      [description]
         * @param  {[type]} validType [description]
         * @return {[type]}           [description]
         */
        valid: function(data, validType) {
            //单个值检测，只返回是否正常
            if (validType !== undefined) {
                data = [{
                    value: data,
                    valid: validType
                }];
                var result = thinkRequire("Valid").check(data);
                return result.length === 0;
            }
            return thinkRequire("Valid").check(data);
        }
    };
});<commit_msg>修复Controller里的type方法没有发送charset #74<commit_after>/**
 * Controller 基类
 * @return {[type]} [description]
 */
var fs = require("fs");
var path = require("path");
var url = require("url");

module.exports = Class(function() {
    "use strict";
    //callback正则
    var callbackReg = /[^\w\.]/g;

    return {
        /**
         * 初始化执行方法
         * @param  {[type]} http [description]
         * @return {[type]}      [description]
         */
        init: function(http) {
            this.http = http;
            this.view = null;
            //将http数据打到模版里
            this.assign("http", this.http);
            //将配置信息打到模版里
            this.assign("config", C());
            //设置变量别名
            this.set = this.assign;
        },
        /**
         * 获取客户端的ip
         * @return {[type]} [description]
         */
        ip: function() {
            return this.http.ip();
        },
        /**
         * 实例化View类
         * @return {[type]} [description]
         */
        initView: function() {
            if (!this.view) {
                this.view = thinkRequire("View")(this.http);
            }
            return this.view;
        },
        /**
         * 是否是GET请求
         * @return {Boolean} [description]
         */
        isGet: function() {
            return this.http.method === 'get';
        },
        /**
         * 是否是POST请求
         * @return {Boolean} [description]
         */
        isPost: function() {
            return this.http.method === 'post';
        },
        /**
         * 是否是特定METHOD请求
         * @param  {[type]}  method [description]
         * @return {Boolean}        [description]
         */
        isMethod: function(method) {
            return this.http.method === method;
        },
        /**
         * 是否是AJAX请求
         * @return {Boolean} [description]
         */
        isAjax: function(method) {
            //请求类型判断
            if (method && this.http.method !== method) {
                return false;
            }
            return this.header("x-requested-with") === "XMLHttpRequest";
        },
        /**
         * 是否是websocket请求
         * @return {Boolean} [description]
         */
        isWebSocket: function(){
            return !!this.http.websocket;
        },
        /**
         * 是否是jsonp接口
         * @return {Boolean} [description]
         */
        isJsonp: function(name){
            name = name || C('url_callback_name');
            return !!this.http.get(name);
        },
        /**
         * 获取QUERY参数
         * @param  {[type]} name [description]
         * @return {[type]}      [description]
         */
        get: function(name) {
            if (name === undefined) {
                return this.http.get;
            }
            return this.http.get[name] || "";
        },
        /**
         * 获取POST参数
         * @param  {[type]} name [description]
         * @return {[type]}      [description]
         */
        post: function(name) {
            var http = this.http;
            if (http.postPromise) {
                return http.postPromise.then(function(data){
                    return name ? (data[name] || "") : data;
                })
            }
            return name ? (http.post[name] || "") : http.post;
        },
        /**
         * 获取参数
         * @param  {[type]} name [description]
         * @return {[type]}      [description]
         */
        param: function(name) {
            return this.post(name) || this.get(name);
        },
        /**
         * 获取上传的文件
         * @param  {[type]} name [description]
         * @return {[type]}      [description]
         */
        file: function(name) {
            var http = this.http;
            if (http.postPromise) {
                return http.postPromise.then(function(){
                    return name ? (http.file[name] || "") : http.file;
                })
            }
            return name ? (http.file[name] || "") : http.file;
        },
        /**
         * header操作
         * @param  {[type]} name  [description]
         * @param  {[type]} value [description]
         * @return {[type]}       [description]
         */
        header: function(name, value) {
            if (name === undefined) {
                return this.http.headers;
            }else if (isObject(name)) {
                for (var key in name) {
                    this.header(key, name[key]);
                }
                return this;
            }else if (value !== undefined) {
                this.http.setHeader(name, value);
                return this;
            }else{
                return this.http.getHeader(name);
            }
        },
        /**
         * 获取userAgent
         * @return {[type]} [description]
         */
        userAgent: function(){
            return this.http.headers['user-agent'] || "";
        },
        /**
         * 获取referrer
         * @return {[type]} [description]
         */
        referer: function(host){
            var referer = this.http.headers.referer || this.http.headers.referfer || "";
            if (!referer || !host) {
                return referer;
            }
            var info = url.parse(referer);
            return info.hostname;
        },
        /**
         * cookie操作
         * @param  {[type]} name    [description]
         * @param  {[type]} value   [description]
         * @param  {[type]} options [description]
         * @return {[type]}         [description]
         */
        cookie: function(name, value, options) {
            if (value !== undefined) {
                this.http.setCookie(name, value, options);
                return this;
            }
            return name === undefined ? this.http.cookie : (this.http.cookie[name] || "");
        },
        /**
         * session
         * 如果是get操作，则返回一个promise
         * @param  {[type]} name  [description]
         * @param  {[type]} value [description]
         * @return {[type]}       [description]
         */
        session: function(name, value) {
            thinkRequire('Session').start(this.http);
            var instance = this.http.session;
            if (name === undefined) {
                return instance.rm();
            }
            if (value !== undefined) {
                return instance.set(name, value);
            }
            return instance.get(name);
        },
        /**
         * 跳转，返回一个pendding promise阻止后面继续执行
         * @param  {[type]} url  [description]
         * @param  {[type]} code [description]
         * @return {[type]}      [description]
         */
        redirect: function(url, code) {
            this.http.redirect(url, code);
            return getDefer().promise;
        },
        /**
         * 赋值变量到模版
         * @param  {[type]} name  [description]
         * @param  {[type]} value [description]
         * @return {[type]}       [description]
         */
        assign: function(name, value) {
            if (arguments.length === 1) {
                return this.initView().assign(name);
            }
            return this.initView().assign(name, value);
        },
        /**
         * 获取解析后的模版内容
         * @param  {[type]} templateFile [description]
         * @param  {[type]} content      [description]
         * @return {[type]}              [description]
         */
        fetch: function(templateFile, content) {
            return this.initView().fetch(templateFile, content);
        },
        /**
         * 输出模版内容
         * @param  {[type]} templateFile [description]
         * @param  {[type]} charset      [description]
         * @param  {[type]} contentType  [description]
         * @param  {[type]} content      [description]
         * @return {[type]}              [description]
         */
        display: function(templateFile, charset, contentType, content) {
            return this.initView().display(templateFile, charset, contentType, content);
        },
        /**
         * 调用另一个controll里的aciton
         * 可以跨分组
         * A("Admin/Test/index")
         * @param  {[type]} action [description]
         * @return {[type]}        [description]
         */
        action: function(action, data) {
            //自动补group
            if (action.split(":").length === 2) {
                action = this.http.group + ':' + action;
            }
            return A(action, this.http, data);
        },
        /**
         * jsonp格式输出
         * @param  {[type]} data  [description]
         * @param  {[type]} jsonp [description]
         * @return {[type]}       [description]
         */
        jsonp: function(data) {
            this.type(C("json_content_type"));
            var callback = this.get(C("url_callback_name"));
            //过滤callback值里的非法字符
            callback = callback.replace(callbackReg, "");
            if (callback) {
                this.echo(callback + "(");
                this.echo(data);
                this.end(")");
            } else {
                this.end(data);
            }
        },
        /**
         * json格式输出
         * @param  {[type]} data [description]
         * @return {[type]}      [description]
         */
        json: function(data){
            this.type(C("json_content_type"));
            return this.end(data);
        },
        /**
         * 设置http响应状态码
         * @param  {[type]} status [description]
         * @return {[type]}        [description]
         */
        status: function(status) {
            var res = this.http.res;
            if (!res.headersSent) {
                res.statusCode = status || 404;
            }
        },
        /**
         * 输出内容
         * 自动JSON.stringify
         * 自定将数字等转化为字符串
         * @param  {[type]} obj [description]
         * @return {[type]}     [description]
         */
        echo: function(obj, encoding) {
            //自动发送Content-Type的header
            if (C('auto_send_content_type')) {
                this.type(C("tpl_content_type"));
            }
            return this.http.echo(obj, encoding);
        },
        /**
         * 结束输出，输出完成时一定要调用这个方法
         * @param  {[type]} obj [description]
         * @return {[type]}     [description]
         */
        end: function(obj, encoding) {
            if (obj) {
                this.echo(obj, encoding);
            }
            this.http.end();
        },
        /**
         * 发送Content-Type
         * @param  {[type]} type [description]
         * @return {[type]}      [description]
         */
        type: function(ext){
            if (ext.indexOf('/') === -1) {
                ext = require('mime').lookup(ext);
            }
            if (!this.http.cthIsSend) {
                if (ext.toLowerCase().indexOf("charset=") === -1) {
                    ext += "; charset=" + C("encoding");
                }
                //Content-Type Header has been Send
                this.http.cthIsSend = true;
                this.http.setHeader("Content-Type", ext);
            }else{
                console.log("Content-Type has been send");
            }
        },
        /**
         * 下载文件
         * @return {[type]} [description]
         */
        download: function(file, contentType, callback) {
            if (isFunction(contentType)) {
                callback = contentType;
                contentType = "";
            }
            if (!contentType || contentType.indexOf('/') === -1) {
                contentType = require('mime').lookup(contentType || file);
            }
            var http = this.http;
            var fileStream = fs.createReadStream(file);
            this.type(contentType);
            http.setHeader("Content-Disposition", 'attachment; filename="' + path.basename(file) + '"');
            fileStream.pipe(http.res);
            fileStream.on("end", function() {
                http.end();
                return callback && callback();
            });
        },
        /**
         * 正常json数据输出
         * @param  {[type]} data [description]
         * @return {[type]}      [description]
         */
        success: function(data){
            var obj = getObject([C('error_no_key'), C('error_msg_key')], [0, ""]);
            if (data !== undefined) {
                obj.data = data;
            }
            this.type(C('json_content_type'));
            this.end(obj);
            return getDefer().promise;
        },
        /**
         * 异常json数据数据
         * @param  {[type]} errno  [description]
         * @param  {[type]} errmsg [description]
         * @param  {[type]} extra  [description]
         * @return {[type]}        [description]
         */
        error: function(errno, errmsg, data){
            var obj;
            if (isObject(errno)) {
                data = errmsg;
                obj = extend({}, errno);
            }else{
                if (!isNumber(errno)) {
                    data = errmsg;
                    errmsg = errno;
                    errno = C('error_no_default_value');
                }
                obj = getObject([C('error_no_key'), C('error_msg_key')], [errno, errmsg]);
            }
            if (data !== undefined) {
                obj.data = data;
            }
            this.type(C('json_content_type'));
            this.end(obj);
            return getDefer().promise;
        },
        /**
         * 发送执行时间
         * @param  {[type]} name [description]
         * @return {[type]}      [description]
         */
        sendTime: function(name){
            return this.http.sendTime(name);
        },
        /**
         * 对数据进行过滤
         * @param  {[type]} data [description]
         * @param  {[type]} type [description]
         * @return {[type]}      [description]
         */
        filter: function() {
            var filter = thinkRequire("Filter").filter;
            return filter.apply(null, arguments);
        },
        /**
         * 校验一个值是否合法
         * @param  {[type]} data      [description]
         * @param  {[type]} validType [description]
         * @return {[type]}           [description]
         */
        valid: function(data, validType) {
            //单个值检测，只返回是否正常
            if (validType !== undefined) {
                data = [{
                    value: data,
                    valid: validType
                }];
                var result = thinkRequire("Valid").check(data);
                return result.length === 0;
            }
            return thinkRequire("Valid").check(data);
        }
    };
});<|endoftext|>


<commit_before>/**
 * TextBox
 *
 * @author rumax
 * @license MIT
 */

/* eslint-disable no-console */

L.Editable.TextBoxEditor = L.Editable.RectangleEditor.extend({

  options: {
    textareaPadding: 1
  },

  /**
   * @param  {L.Map}     map
   * @param  {L.Textbox} feature
   * @param  {Object=}   options
   */
  initialize: function(map, feature, options) {

    /**
     * @type {HTMLTextAreaElement}
     */
    this._textArea = null;

    /**
     * @type {String}
     */
    this._text     = null;

    L.Editable.RectangleEditor.prototype.initialize.call(this, map, feature, options);
  },

  updateStyle: function() {
    if (null !== this._textArea) {
      var style   = this._textArea.style;
      var options = this.feature.options;

      style.fontSize   = options.fontSize + 'px';
      style.color      = options.fontColor;
      style.fontFamily = options.fontFamily;
    }
  },

  enable: function() {
    L.Editable.RectangleEditor.prototype.enable.call(this);
    this.map
        .on('dragend', this._focus, this)
        .on('zoomanim', this._animateZoom, this)
        .on('zoomend', this._updateTextAreaBounds, this);

    if (null === this._textArea) {
      this._textArea = L.DomUtil.create('textarea',
        'leaflet-zoom-animated leaflet-textbox');
      var style = this._textArea.style;
      style.resize          = 'none';
      style.border          = 'none';
      style.padding         = this.options.textareaPadding + 'px';
      style.backgroundColor = 'transparent';

      this.updateStyle();
      this.map.getPane('markerPane').appendChild(this._textArea);

      this._text = this.feature._text;
      if (this._text) {
        this._textArea.innerHTML = this._text;
      }

      L.DomEvent
        .addListener(this._textArea, 'mousedown', this._mouseEvents, this)
        .addListener(this._textArea, 'click', this._mouseEvents, this);
      this._updateTextAreaBounds();
    }

    if (this.feature._textNode) {
      this.feature._textNode.parentNode.removeChild(this.feature._textNode);
      this.feature._textNode = null;
    }

    return this;
  },

  setText: function(text) {
    this._text = text;

    if (null !== this._textArea) {
      this._textArea.value = text;
    }
  },

  getText: function() {
    this._text = this._textArea.value;
    return this._text;
  },

  disable: function() {
    if (this._enabled) {
      this.map
        .off('dragend',  this._focus, this)
        .off('zoomanim', this._animateZoom, this)
        .off('zoomend',  this._updateTextAreaBounds, this);

      if (null !== this.textArea) {
        this.getText();
        L.DomEvent
          .removeListener(this._textArea, 'mousedown', this._mouseEvents, this)
          .removeListener(this._textArea, 'click', this._mouseEvents, this);
        this._textArea.parentNode.removeChild(this._textArea);
        this._textArea = null;
      }
      this.feature._text = this._text;
      this.feature._renderText();
    }

    L.Editable.RectangleEditor.prototype.disable.call(this);

    return this;
  },

  updateBounds: function (bounds) {
    L.Editable.RectangleEditor.prototype.updateBounds.call(this, bounds);
    return this._updateTextAreaBounds();
  },

  _focus: function() {
    if (null !== this._textArea) {
      L.Util.requestAnimFrame(function() {
        this._textArea.focus();
      }, this);
    }
  },

  /**
   * Animated resize
   * @param  {Event} evt
   */
  _animateZoom: function(evt) {
    var bounds = this.feature._bounds;
    var scale  = this.feature._getScale(evt.zoom);
    var offset = this.map._latLngToNewLayerPoint(
      bounds.getNorthWest(), evt.zoom, evt.center);

    L.DomUtil.setTransform(this._textArea, offset, scale.toFixed(3));
  },

  /**
   * Resize, reposition on zoom end or resize
   */
  _updateTextAreaBounds: function() {
    var scale, latlngs, pos, size;
    var feature  = this.feature;
    var bounds   = feature._bounds;
    var textArea = this._textArea;
    var map      = this.map;

    if (null !== textArea) {
      if (null !== bounds) {
        scale = feature._getScale(map.getZoom());
        latlngs = feature._boundsToLatLngs(bounds);
        pos = map.latLngToLayerPoint(latlngs[1]);
        size = map.latLngToLayerPoint(latlngs[3]).subtract(pos);
        L.DomUtil
           .setSize(textArea, size.divideBy(scale).round())
           .setTransform(textArea, pos, scale.toFixed(3));

        textArea.style.display  = '';
        textArea.style.position = 'absolute';
        textArea.setAttribute('spellcheck', false);

        this._focus();
      } else {
        textArea.style.display = 'none';
      }
    }

    return this;
  },

  /**
   * Prevents map from drag on selection and hadles click inside element
   */
  _mouseEvents: function(evt) {
    L.DomEvent.stopPropagation(evt);
  }

});

L.TextBox.include({

  enableEdit: function(map) {
    if (!this.editor) {
      this.createEditor(map);
    }
    return L.Rectangle.prototype.enableEdit.call(this, map);
  },

  disableEdit: function() {
    if (this.editor) {
      this._text = this.editor.getText();
    }

    L.Rectangle.prototype.disableEdit.call(this);

    return this;
  },

  getEditorClass: function() {
    return L.Editable.TextBoxEditor;
  }

});

/**
 * @param  {Array.<LatLng>=} latlng
 * @param  {Object=} options
 * @return {L.TextBox}
 */
L.Editable.prototype.startTextBox = function(latlng, options) {
  return this.startRectangle(null, L.extend({
    rectangleClass: L.TextBox
  }, options));
};
<commit_msg>overflow hidden for textArea (scale & small font size issue)<commit_after>/**
 * TextBox
 *
 * @author rumax
 * @license MIT
 */

/* eslint-disable no-console */

L.Editable.TextBoxEditor = L.Editable.RectangleEditor.extend({

  options: {
    textareaPadding: 1
  },

  /**
   * @param  {L.Map}     map
   * @param  {L.Textbox} feature
   * @param  {Object=}   options
   */
  initialize: function(map, feature, options) {

    /**
     * @type {HTMLTextAreaElement}
     */
    this._textArea = null;

    /**
     * @type {String}
     */
    this._text     = null;

    L.Editable.RectangleEditor.prototype.initialize.call(this, map, feature, options);
  },

  updateStyle: function() {
    if (null !== this._textArea) {
      var style   = this._textArea.style;
      var options = this.feature.options;

      style.fontSize   = options.fontSize + 'px';
      style.color      = options.fontColor;
      style.fontFamily = options.fontFamily;
    }
  },

  enable: function() {
    L.Editable.RectangleEditor.prototype.enable.call(this);
    this.map
        .on('dragend', this._focus, this)
        .on('zoomanim', this._animateZoom, this)
        .on('zoomend', this._updateTextAreaBounds, this);

    if (null === this._textArea) {
      this._textArea = L.DomUtil.create('textarea',
        'leaflet-zoom-animated leaflet-textbox');
      var style = this._textArea.style; //TODO: Use css
      style.resize          = 'none';
      style.border          = 'none';
      style.padding         = this.options.textareaPadding + 'px';
      style.backgroundColor = 'transparent';
      style.overflow = 'hidden';

      this.updateStyle();
      this.map.getPane('markerPane').appendChild(this._textArea);

      this._text = this.feature._text;
      if (this._text) {
        this._textArea.innerHTML = this._text;
      }

      L.DomEvent
        .addListener(this._textArea, 'mousedown', this._mouseEvents, this)
        .addListener(this._textArea, 'click', this._mouseEvents, this);
      this._updateTextAreaBounds();
    }

    if (this.feature._textNode) {
      this.feature._textNode.parentNode.removeChild(this.feature._textNode);
      this.feature._textNode = null;
    }

    return this;
  },

  setText: function(text) {
    this._text = text;

    if (null !== this._textArea) {
      this._textArea.value = text;
    }
  },

  getText: function() {
    this._text = this._textArea.value;
    return this._text;
  },

  disable: function() {
    if (this._enabled) {
      this.map
        .off('dragend',  this._focus, this)
        .off('zoomanim', this._animateZoom, this)
        .off('zoomend',  this._updateTextAreaBounds, this);

      if (null !== this.textArea) {
        this.getText();
        L.DomEvent
          .removeListener(this._textArea, 'mousedown', this._mouseEvents, this)
          .removeListener(this._textArea, 'click', this._mouseEvents, this);
        this._textArea.parentNode.removeChild(this._textArea);
        this._textArea = null;
      }
      this.feature._text = this._text;
      this.feature._renderText();
    }

    L.Editable.RectangleEditor.prototype.disable.call(this);

    return this;
  },

  updateBounds: function (bounds) {
    L.Editable.RectangleEditor.prototype.updateBounds.call(this, bounds);
    return this._updateTextAreaBounds();
  },

  _focus: function() {
    if (null !== this._textArea) {
      L.Util.requestAnimFrame(function() {
        this._textArea.focus();
      }, this);
    }
  },

  /**
   * Animated resize
   * @param  {Event} evt
   */
  _animateZoom: function(evt) {
    var bounds = this.feature._bounds;
    var scale  = this.feature._getScale(evt.zoom);
    var offset = this.map._latLngToNewLayerPoint(
      bounds.getNorthWest(), evt.zoom, evt.center);

    L.DomUtil.setTransform(this._textArea, offset, scale.toFixed(3));
  },

  /**
   * Resize, reposition on zoom end or resize
   */
  _updateTextAreaBounds: function() {
    var scale, latlngs, pos, size;
    var feature  = this.feature;
    var bounds   = feature._bounds;
    var textArea = this._textArea;
    var map      = this.map;

    if (null !== textArea) {
      if (null !== bounds) {
        scale = feature._getScale(map.getZoom());
        latlngs = feature._boundsToLatLngs(bounds);
        pos = map.latLngToLayerPoint(latlngs[1]);
        size = map.latLngToLayerPoint(latlngs[3]).subtract(pos);
        L.DomUtil
           .setSize(textArea, size.divideBy(scale).round())
           .setTransform(textArea, pos, scale.toFixed(3));

        textArea.style.display  = '';
        textArea.style.position = 'absolute';
        textArea.setAttribute('spellcheck', false);

        this._focus();
      } else {
        textArea.style.display = 'none';
      }
    }

    return this;
  },

  /**
   * Prevents map from drag on selection and hadles click inside element
   */
  _mouseEvents: function(evt) {
    L.DomEvent.stopPropagation(evt);
  }

});

L.TextBox.include({

  enableEdit: function(map) {
    if (!this.editor) {
      this.createEditor(map);
    }
    return L.Rectangle.prototype.enableEdit.call(this, map);
  },

  disableEdit: function() {
    if (this.editor) {
      this._text = this.editor.getText();
    }

    L.Rectangle.prototype.disableEdit.call(this);

    return this;
  },

  getEditorClass: function() {
    return L.Editable.TextBoxEditor;
  }

});

/**
 * @param  {Array.<LatLng>=} latlng
 * @param  {Object=} options
 * @return {L.TextBox}
 */
L.Editable.prototype.startTextBox = function(latlng, options) {
  return this.startRectangle(null, L.extend({
    rectangleClass: L.TextBox
  }, options));
};
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 *  WSO2 Inc. licenses this file to you under the Apache License,
 *  Version 2.0 (the "License"); you may not use this file except
 *  in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing,
 *  software distributed under the License is distributed on an
 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *  KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations
 *  under the License.
 *
 */
var $radio = $('.auto-submit-star');
var $btn = $('#btn-post');
var $textArea = $('#com-body');
var $stream = $('#stream');
var $firstReview = $('.com-first-review');
var $alert = $('.com-alert');
var $sort = $('.com-sort');
var $lastReview = $('.load-more');
var $more = $('#more');
var $empty_list = $('#empty_list');
var windowProxy;

var publish = function (activity, onSuccess) {
    if (activity.target) {
        activity.context = {"id": target};
    } else {
        activity.target = {"id": target};
    }
    $.post('apis/comments.jag', {
        activity: JSON.stringify(activity)
    }, onSuccess)
};

var showAlert = function (msg) {
    $alert.html(msg).fadeIn("fast").css('display', 'inline-block');
};

var showLoading = function (status) {
    if (status) {
        $alert.html('').css('display', 'inline-block').addClass('com-alert-wait');
    } else {
        $alert.hide().removeClass('com-alert-wait');
    }
};

$radio.rating({
    callback: function (value) {
    }
});

$btn.click(function (e) {
    e.preventDefault();
    var rating = Number($('input.star-rating-applied:checked').val());
    var review = $textArea.val();

    if (!review && !rating) {
        showAlert("Please add your Review and Rating");
    } else if (!review) {
        showAlert("Please add your Review");
    } else if (!rating) {
        showAlert("Please add your Rating");
    } else {
        var activity = {"verb": "post",
            "object": {"objectType": "review", "content": review, rating: rating, "likes" : {"totalItems": 0}, "dislikes" : {"totalItems": 0}}
        };

        $btn.attr('disabled', 'disabled');
        showLoading(true);

        var pos = target.indexOf(':');
        var aid = target.substring(pos + 1);
        var type = target.substring(0, pos);

        var addAndRenderNew = function (successCallback) {
            $('#newest').addClass('selected');
                publish(activity, function (published) {
                    if ($firstReview.length) {
                        $firstReview.hide();
                        $sort.removeClass('com-sort-hidden');
                    }
                    $btn.removeAttr('disabled');

                    if (published.success) {
                        showLoading(false);
                        $radio.rating('select', null);
                        $textArea.val('');

                        activity.id = published.id;
                      //Remove carbon.super tenant domain from username
                        var pieces = user.split(/[\s@]+/);
                        if(pieces[pieces.length-1] == 'carbon.super'){
                            user= pieces[pieces.length-2];
                        }
                        activity.actor = {id: user};
                        usingTemplate(function (template) {
                            var newComment = template(activity);
                            $stream.prepend(newComment);
                            successCallback && successCallback();
                        });
                    }
                });
        };

        addAndRenderNew(function(){
            redrawReviews();
        });
    }
});

$stream.on('click', '.icon-thumbs-down', function (e) {
    e.preventDefault();
    var $likeBtn = $(e.target);
    var $review = $likeBtn.parents('.com-review');
    var id = $review.attr('data-target-id');
    var $likeCount = $review.find('.com-dislike-count');

    var activity = { target: {id: id}, object : {} };

    if ($likeBtn.hasClass('selected')) {
        activity.verb = 'undislike';
        publish(activity, function () {
            $likeCount.text((Number($likeCount.text()) - 1) || '');
        });
        $likeBtn.removeClass('selected');
    } else {
        activity.verb = 'dislike';
        publish(activity, function () {
            $likeCount.text(Number($likeCount.text()) + 1);
        });
        $likeBtn.addClass('selected');
    }
});

$stream.on('click', '.icon-thumbs-up', function (e) {
    e.preventDefault();
    var $likeBtn = $(e.target);
    var $review = $likeBtn.parents('.com-review');
    var id = $review.attr('data-target-id');
    var $likeCount = $review.find('.com-like-count');

        var activity = { target: {id: id}, object :{}};

    if ($likeBtn.hasClass('selected')) {
        activity.verb = 'unlike';
        publish(activity, function () {
            $likeCount.text((Number($likeCount.text()) - 1) || '');
        });
        $likeBtn.removeClass('selected');
    } else {
        activity.verb = 'like';
        publish(activity, function () {
            $likeCount.text(Number($likeCount.text()) + 1);
        });
        $likeBtn.addClass('selected');
    }

});

$more.on('click', '.load-more', function (e) {
    e.preventDefault();
    var offset = parseInt($('.load-more').attr("value"));
        $.get('apis/object.jag', {
            target: target,
            sortBy : $('.com-sort .selected').attr('id'),
            offset: offset,
            limit: 10
        }, function (obj) {
            var reviews = obj || [];

            if(jQuery.isEmptyObject(reviews) || reviews.length < 10){
                $more.hide();
                $empty_list.text("No more activities to retrieve.");
            }

            usingTemplate(function (template) {
                var str = "";
                for (var i = 0; i < reviews.length; i++) {
                    var review = reviews[i];
                    str += template(review);
                }
                $stream.append(str);
                //callback && callback();
                adjustHeight();
                $('.load-more').attr("value", parseInt(offset) + 10);
            });
        })

});

$stream.on('click', '.com-delete', function (e) {
    e.preventDefault();
    var $deleteBtn = $(e.target);
    var $review = $deleteBtn.parents('.com-review');
    var id = $review.attr('data-target-id');

    $.get('apis/comments.jag',{
        id:id
    }, function(obj){
        if(obj.success){
        $review.remove();
        }
    });
});<commit_msg>fixing social like activity issues<commit_after>/*
 *  Copyright (c) 2005-2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 *  WSO2 Inc. licenses this file to you under the Apache License,
 *  Version 2.0 (the "License"); you may not use this file except
 *  in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing,
 *  software distributed under the License is distributed on an
 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *  KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations
 *  under the License.
 *
 */
var $radio = $('.auto-submit-star');
var $btn = $('#btn-post');
var $textArea = $('#com-body');
var $stream = $('#stream');
var $firstReview = $('.com-first-review');
var $alert = $('.com-alert');
var $sort = $('.com-sort');
var $lastReview = $('.load-more');
var $more = $('#more');
var $empty_list = $('#empty_list');
var windowProxy;

var publish = function (activity, onSuccess) {
    if (activity.target) {
        activity.context = {"id": target};
    } else {
        activity.target = {"id": target};
    }
    $.post('apis/comments.jag', {
        activity: JSON.stringify(activity)
    }, onSuccess)
};

var showAlert = function (msg) {
    $alert.html(msg).fadeIn("fast").css('display', 'inline-block');
};

var showLoading = function (status) {
    if (status) {
        $alert.html('').css('display', 'inline-block').addClass('com-alert-wait');
    } else {
        $alert.hide().removeClass('com-alert-wait');
    }
};

$radio.rating({
    callback: function (value) {
    }
});

$btn.click(function (e) {
    e.preventDefault();
    var rating = Number($('input.star-rating-applied:checked').val());
    var review = $textArea.val();

    if (!review && !rating) {
        showAlert("Please add your Review and Rating");
    } else if (!review) {
        showAlert("Please add your Review");
    } else if (!rating) {
        showAlert("Please add your Rating");
    } else {
        var activity = {"verb": "post",
            "object": {"objectType": "review", "content": review, rating: rating, "likes" : {"totalItems": 0}, "dislikes" : {"totalItems": 0}}
        };

        $btn.attr('disabled', 'disabled');
        showLoading(true);

        var pos = target.indexOf(':');
        var aid = target.substring(pos + 1);
        var type = target.substring(0, pos);

        var addAndRenderNew = function (successCallback) {
            $('#newest').addClass('selected');
                publish(activity, function (published) {
                    if ($firstReview.length) {
                        $firstReview.hide();
                        $sort.removeClass('com-sort-hidden');
                    }
                    $btn.removeAttr('disabled');

                    if (published.success) {
                        showLoading(false);
                        $radio.rating('select', null);
                        $textArea.val('');

                        activity.id = published.id;
                      //Remove carbon.super tenant domain from username
                        var pieces = user.split(/[\s@]+/);
                        if(pieces[pieces.length-1] == 'carbon.super'){
                            user= pieces[pieces.length-2];
                        }
                        activity.actor = {id: user};
                        usingTemplate(function (template) {
                            var newComment = template(activity);
                            $stream.prepend(newComment);
                            successCallback && successCallback();
                        });
                    }
                });
        };

        addAndRenderNew(function(){
            redrawReviews();
        });
    }
});

$stream.on('click', '.icon-thumbs-down', function (e) {
    e.preventDefault();
    var $tDownBtn = $(e.target);
    var $review = $tDownBtn.parents('.com-review');
    var id = $review.attr('data-target-id');
    var $tDownCount = $review.find('.com-dislike-count');

    var activity = { target: {id: id}, object : {} };

    var $opposite = $review.find('.icon-thumbs-up');
    if($opposite.hasClass('selected')){
        var ulikeActivity = { target: {id: id}, object : {} };
        var $likeCount = $review.find('.com-like-count');
        ulikeActivity.verb = 'unlike';
        publish(ulikeActivity, function () {
            $likeCount.text((Number($likeCount.text()) - 1) || '');
        });
        $opposite.removeClass('selected');
    }

    if ($tDownBtn.hasClass('selected')) {
        activity.verb = 'undislike';
        publish(activity, function () {
            $tDownCount.text((Number($tDownCount.text()) - 1) || '');
        });
        $tDownBtn.removeClass('selected');
    } else {
        activity.verb = 'dislike';
        publish(activity, function () {
            $tDownCount.text(Number($tDownCount.text()) + 1);
        });
        $tDownBtn.addClass('selected');
    }
});

$stream.on('click', '.icon-thumbs-up', function (e) {
    e.preventDefault();
    var $tUpBtn = $(e.target);
    var $review = $tUpBtn.parents('.com-review');
    var id = $review.attr('data-target-id');
    var $likeCount = $review.find('.com-like-count');

    var activity = { target: {id: id}, object :{}};

    var $opposite = $review.find('.icon-thumbs-down');
    if($opposite.hasClass('selected')){
        var uDislikeActivity = { target: {id: id}, object : {} };
        var $uDislikeCount = $review.find('.com-dislike-count');
        uDislikeActivity.verb = 'undislike';
        publish(uDislikeActivity, function () {
            $uDislikeCount.text((Number($uDislikeCount.text()) - 1) || '');
        });
        $opposite.removeClass('selected');
    }

    if ($tUpBtn.hasClass('selected')) {
        activity.verb = 'unlike';
        publish(activity, function () {
            $likeCount.text((Number($likeCount.text()) - 1) || '');
        });
        $tUpBtn.removeClass('selected');
    } else {
        activity.verb = 'like';
        publish(activity, function () {
            $likeCount.text(Number($likeCount.text()) + 1);
        });
        $tUpBtn.addClass('selected');
    }

});

$more.on('click', '.load-more', function (e) {
    e.preventDefault();
    var offset = parseInt($('.load-more').attr("value"));
        $.get('apis/object.jag', {
            target: target,
            sortBy : $('.com-sort .selected').attr('id'),
            offset: offset,
            limit: 10
        }, function (obj) {
            var reviews = obj || [];

            if(jQuery.isEmptyObject(reviews) || reviews.length < 10){
                $more.hide();
                $empty_list.text("No more activities to retrieve.");
            }

            usingTemplate(function (template) {
                var str = "";
                for (var i = 0; i < reviews.length; i++) {
                    var review = reviews[i];
                    str += template(review);
                }
                $stream.append(str);
                //callback && callback();
                adjustHeight();
                $('.load-more').attr("value", parseInt(offset) + 10);
            });
        })

});

$stream.on('click', '.com-delete', function (e) {
    e.preventDefault();
    var $deleteBtn = $(e.target);
    var $review = $deleteBtn.parents('.com-review');
    var id = $review.attr('data-target-id');

    $.get('apis/comments.jag',{
        id:id
    }, function(obj){
        if(obj.success){
        $review.remove();
        }
    });
});<|endoftext|>


<commit_before>type JestMockFn = {
  (...args: Array<any>): any,
  /**
   * An object for introspecting mock calls
   */
  mock: {
    /**
     * An array that represents all calls that have been made into this mock
     * function. Each call is represented by an array of arguments that were
     * passed during the call.
     */
    calls: Array<Array<any>>,
    /**
     * An array that contains all the object instances that have been
     * instantiated from this mock function.
     */
    instances: mixed
  },
  /**
   * Resets all information stored in the mockFn.mock.calls and
   * mockFn.mock.instances arrays. Often this is useful when you want to clean
   * up a mock's usage data between two assertions.
   */
  mockClear(): Function,
  /**
   * Resets all information stored in the mock. This is useful when you want to
   * completely restore a mock back to its initial state.
   */
  mockReset(): Function,
  /**
   * Accepts a function that should be used as the implementation of the mock.
   * The mock itself will still record all calls that go into and instances
   * that come from itself -- the only difference is that the implementation
   * will also be executed when the mock is called.
   */
  mockImplementation(fn: Function): JestMockFn,
  /**
   * Accepts a function that will be used as an implementation of the mock for
   * one call to the mocked function. Can be chained so that multiple function
   * calls produce different results.
   */
  mockImplementationOnce(fn: Function): JestMockFn,
  /**
   * Just a simple sugar function for returning `this`
   */
  mockReturnThis(): void,
  /**
   * Deprecated: use jest.fn(() => value) instead
   */
  mockReturnValue(value: any): JestMockFn,
  /**
   * Sugar for only returning a value once inside your mock
   */
  mockReturnValueOnce(value: any): JestMockFn
};

type JestAsymmetricEqualityType = {
  /**
   * A custom Jasmine equality tester
   */
  asymmetricMatch(value: mixed): boolean
};

type JestCallsType = {
  allArgs(): mixed,
  all(): mixed,
  any(): boolean,
  count(): number,
  first(): mixed,
  mostRecent(): mixed,
  reset(): void
};

type JestClockType = {
  install(): void,
  mockDate(date: Date): void,
  tick(): void,
  uninstall(): void
};

type JestMatcherResult = {
  message?: string | (() => string),
  pass: boolean
};

type JestMatcher = (actual: any, expected: any) => JestMatcherResult;

type JestPromiseType = {
  /**
   * Use rejects to unwrap the reason of a rejected promise so any other
   * matcher can be chained. If the promise is fulfilled the assertion fails.
   */
  rejects(): JestExpectType,
  /**
   * Use resolves to unwrap the value of a fulfilled promise so any other
   * matcher can be chained. If the promise is rejected the assertion fails.
   */
  resolves(): JestExpectType
};

type JestExpectType = {
  not: JestExpectType,
  /**
   * If you have a mock function, you can use .lastCalledWith to test what
   * arguments it was last called with.
   */
  lastCalledWith(...args: Array<any>): void,
  /**
   * toBe just checks that a value is what you expect. It uses === to check
   * strict equality.
   */
  toBe(value: any): void,
  /**
   * Use .toHaveBeenCalled to ensure that a mock function got called.
   */
  toBeCalled(): void,
  /**
   * Use .toBeCalledWith to ensure that a mock function was called with
   * specific arguments.
   */
  toBeCalledWith(...args: Array<any>): void,
  /**
   * Using exact equality with floating point numbers is a bad idea. Rounding
   * means that intuitive things fail.
   */
  toBeCloseTo(num: number, delta: any): void,
  /**
   * Use .toBeDefined to check that a variable is not undefined.
   */
  toBeDefined(): void,
  /**
   * Use .toBeFalsy when you don't care what a value is, you just want to
   * ensure a value is false in a boolean context.
   */
  toBeFalsy(): void,
  /**
   * To compare floating point numbers, you can use toBeGreaterThan.
   */
  toBeGreaterThan(number: number): void,
  /**
   * To compare floating point numbers, you can use toBeGreaterThanOrEqual.
   */
  toBeGreaterThanOrEqual(number: number): void,
  /**
   * To compare floating point numbers, you can use toBeLessThan.
   */
  toBeLessThan(number: number): void,
  /**
   * To compare floating point numbers, you can use toBeLessThanOrEqual.
   */
  toBeLessThanOrEqual(number: number): void,
  /**
   * Use .toBeInstanceOf(Class) to check that an object is an instance of a
   * class.
   */
  toBeInstanceOf(cls: Class<*>): void,
  /**
   * .toBeNull() is the same as .toBe(null) but the error messages are a bit
   * nicer.
   */
  toBeNull(): void,
  /**
   * Use .toBeTruthy when you don't care what a value is, you just want to
   * ensure a value is true in a boolean context.
   */
  toBeTruthy(): void,
  /**
   * Use .toBeUndefined to check that a variable is undefined.
   */
  toBeUndefined(): void,
  /**
   * Use .toContain when you want to check that an item is in a list. For
   * testing the items in the list, this uses ===, a strict equality check.
   */
  toContain(item: any): void,
  /**
   * Use .toContainEqual when you want to check that an item is in a list. For
   * testing the items in the list, this matcher recursively checks the
   * equality of all fields, rather than checking for object identity.
   */
  toContainEqual(item: any): void,
  /**
   * Use .toEqual when you want to check that two objects have the same value.
   * This matcher recursively checks the equality of all fields, rather than
   * checking for object identity.
   */
  toEqual(value: any): void,
  /**
   * Use .toHaveBeenCalled to ensure that a mock function got called.
   */
  toHaveBeenCalled(): void,
  /**
   * Use .toHaveBeenCalledTimes to ensure that a mock function got called exact
   * number of times.
   */
  toHaveBeenCalledTimes(number: number): void,
  /**
   * Use .toHaveBeenCalledWith to ensure that a mock function was called with
   * specific arguments.
   */
  toHaveBeenCalledWith(...args: Array<any>): void,
  /**
   * Check that an object has a .length property and it is set to a certain
   * numeric value.
   */
  toHaveLength(number: number): void,
  /**
   *
   */
  toHaveProperty(propPath: string, value?: any): void,
  /**
   * Use .toMatch to check that a string matches a regular expression.
   */
  toMatch(regexp: RegExp): void,
  /**
   * Use .toMatchObject to check that a javascript object matches a subset of the properties of an object.
   */
  toMatchObject(object: Object): void,
  /**
   * This ensures that a React component matches the most recent snapshot.
   */
  toMatchSnapshot(name?: string): void,
  /**
   * Use .toThrow to test that a function throws when it is called.
   */
  toThrow(message?: string | Error): void,
  /**
   * Use .toThrowError to test that a function throws a specific error when it
   * is called. The argument can be a string for the error message, a class for
   * the error, or a regex that should match the error.
   */
  toThrowError(message?: string | Error | RegExp): void,
  /**
   * Use .toThrowErrorMatchingSnapshot to test that a function throws a error
   * matching the most recent snapshot when it is called.
   */
  toThrowErrorMatchingSnapshot(): void
};

type JestObjectType = {
  /**
   *  Disables automatic mocking in the module loader.
   *
   *  After this method is called, all `require()`s will return the real
   *  versions of each module (rather than a mocked version).
   */
  disableAutomock(): JestObjectType,
  /**
   * An un-hoisted version of disableAutomock
   */
  autoMockOff(): JestObjectType,
  /**
   * Enables automatic mocking in the module loader.
   */
  enableAutomock(): JestObjectType,
  /**
   * An un-hoisted version of enableAutomock
   */
  autoMockOn(): JestObjectType,
  /**
   * Clears the mock.calls and mock.instances properties of all mocks.
   * Equivalent to calling .mockClear() on every mocked function.
   */
  clearAllMocks(): JestObjectType,
  /**
   * Resets the state of all mocks. Equivalent to calling .mockReset() on every
   * mocked function.
   */
  resetAllMocks(): JestObjectType,
  /**
   * Removes any pending timers from the timer system.
   */
  clearAllTimers(): void,
  /**
   * The same as `mock` but not moved to the top of the expectation by
   * babel-jest.
   */
  doMock(moduleName: string, moduleFactory?: any): JestObjectType,
  /**
   * The same as `unmock` but not moved to the top of the expectation by
   * babel-jest.
   */
  dontMock(moduleName: string): JestObjectType,
  /**
   * Returns a new, unused mock function. Optionally takes a mock
   * implementation.
   */
  fn(implementation?: Function): JestMockFn,
  /**
   * Determines if the given function is a mocked function.
   */
  isMockFunction(fn: Function): boolean,
  /**
   * Given the name of a module, use the automatic mocking system to generate a
   * mocked version of the module for you.
   */
  genMockFromModule(moduleName: string): any,
  /**
   * Mocks a module with an auto-mocked version when it is being required.
   *
   * The second argument can be used to specify an explicit module factory that
   * is being run instead of using Jest's automocking feature.
   *
   * The third argument can be used to create virtual mocks -- mocks of modules
   * that don't exist anywhere in the system.
   */
  mock(moduleName: string, moduleFactory?: any): JestObjectType,
  /**
   * Resets the module registry - the cache of all required modules. This is
   * useful to isolate modules where local state might conflict between tests.
   */
  resetModules(): JestObjectType,
  /**
   * Exhausts the micro-task queue (usually interfaced in node via
   * process.nextTick).
   */
  runAllTicks(): void,
  /**
   * Exhausts the macro-task queue (i.e., all tasks queued by setTimeout(),
   * setInterval(), and setImmediate()).
   */
  runAllTimers(): void,
  /**
   * Exhausts all tasks queued by setImmediate().
   */
  runAllImmediates(): void,
  /**
   * Executes only the macro task queue (i.e. all tasks queued by setTimeout()
   * or setInterval() and setImmediate()).
   */
  runTimersToTime(msToRun: number): void,
  /**
   * Executes only the macro-tasks that are currently pending (i.e., only the
   * tasks that have been queued by setTimeout() or setInterval() up to this
   * point)
   */
  runOnlyPendingTimers(): void,
  /**
   * Explicitly supplies the mock object that the module system should return
   * for the specified module. Note: It is recommended to use jest.mock()
   * instead.
   */
  setMock(moduleName: string, moduleExports: any): JestObjectType,
  /**
   * Indicates that the module system should never return a mocked version of
   * the specified module from require() (e.g. that it should always return the
   * real module).
   */
  unmock(moduleName: string): JestObjectType,
  /**
   * Instructs Jest to use fake versions of the standard timer functions
   * (setTimeout, setInterval, clearTimeout, clearInterval, nextTick,
   * setImmediate and clearImmediate).
   */
  useFakeTimers(): JestObjectType,
  /**
   * Instructs Jest to use the real versions of the standard timer functions.
   */
  useRealTimers(): JestObjectType,
  /**
   * Creates a mock function similar to jest.fn but also tracks calls to
   * object[methodName].
   */
  spyOn(object: Object, methodName: string): JestMockFn
};

type JestSpyType = {
  calls: JestCallsType
};

/** Runs this function after every test inside this context */
declare function afterEach(fn: Function): void;
/** Runs this function before every test inside this context */
declare function beforeEach(fn: Function): void;
/** Runs this function after all tests have finished inside this context */
declare function afterAll(fn: Function): void;
/** Runs this function before any tests have started inside this context */
declare function beforeAll(fn: Function): void;
/** A context for grouping tests together */
declare function describe(name: string, fn: Function): void;

/** An individual test unit */
declare var it: {
  /**
   * An individual test unit
   *
   * @param {string} Name of Test
   * @param {Function} Test
   */
  (name: string, fn?: Function): ?Promise<void>,
  /**
   * Only run this test
   *
   * @param {string} Name of Test
   * @param {Function} Test
   */
  only(name: string, fn?: Function): ?Promise<void>,
  /**
   * Skip running this test
   *
   * @param {string} Name of Test
   * @param {Function} Test
   */
  skip(name: string, fn?: Function): ?Promise<void>,
  /**
   * Run the test concurrently
   *
   * @param {string} Name of Test
   * @param {Function} Test
   */
  concurrent(name: string, fn?: Function): ?Promise<void>
};
declare function fit(name: string, fn: Function): ?Promise<void>;
/** An individual test unit */
declare var test: typeof it;
/** A disabled group of tests */
declare var xdescribe: typeof describe;
/** A focused group of tests */
declare var fdescribe: typeof describe;
/** A disabled individual test */
declare var xit: typeof it;
/** A disabled individual test */
declare var xtest: typeof it;

/** The expect function is used every time you want to test a value */
declare var expect: {
  /** The object that you want to make assertions against */
  (value: any): JestExpectType & JestPromiseType,
  /** Add additional Jasmine matchers to Jest's roster */
  extend(matchers: { [name: string]: JestMatcher }): void,
  /** Add a module that formats application-specific data structures. */
  addSnapshotSerializer(serializer: (input: Object) => string): void,
  assertions(expectedAssertions: number): void,
  hasAssertions(): void,
  any(value: mixed): JestAsymmetricEqualityType,
  anything(): void,
  arrayContaining(value: Array<mixed>): void,
  objectContaining(value: Object): void,
  /** Matches any received string that contains the exact expected string. */
  stringContaining(value: string): void,
  stringMatching(value: string | RegExp): void
};

// TODO handle return type
// http://jasmine.github.io/2.4/introduction.html#section-Spies
declare function spyOn(value: mixed, method: string): Object;

/** Holds all functions related to manipulating test runner */
declare var jest: JestObjectType;

/**
 * The global Jamine object, this is generally not exposed as the public API,
 * using features inside here could break in later versions of Jest.
 */
declare var jasmine: {
  DEFAULT_TIMEOUT_INTERVAL: number,
  any(value: mixed): JestAsymmetricEqualityType,
  anything(): void,
  arrayContaining(value: Array<mixed>): void,
  clock(): JestClockType,
  createSpy(name: string): JestSpyType,
  createSpyObj(
    baseName: string,
    methodNames: Array<string>
  ): { [methodName: string]: JestSpyType },
  objectContaining(value: Object): void,
  stringMatching(value: string): void
};
<commit_msg>accidently made resolve/reject a function<commit_after>type JestMockFn = {
  (...args: Array<any>): any,
  /**
   * An object for introspecting mock calls
   */
  mock: {
    /**
     * An array that represents all calls that have been made into this mock
     * function. Each call is represented by an array of arguments that were
     * passed during the call.
     */
    calls: Array<Array<any>>,
    /**
     * An array that contains all the object instances that have been
     * instantiated from this mock function.
     */
    instances: mixed
  },
  /**
   * Resets all information stored in the mockFn.mock.calls and
   * mockFn.mock.instances arrays. Often this is useful when you want to clean
   * up a mock's usage data between two assertions.
   */
  mockClear(): Function,
  /**
   * Resets all information stored in the mock. This is useful when you want to
   * completely restore a mock back to its initial state.
   */
  mockReset(): Function,
  /**
   * Accepts a function that should be used as the implementation of the mock.
   * The mock itself will still record all calls that go into and instances
   * that come from itself -- the only difference is that the implementation
   * will also be executed when the mock is called.
   */
  mockImplementation(fn: Function): JestMockFn,
  /**
   * Accepts a function that will be used as an implementation of the mock for
   * one call to the mocked function. Can be chained so that multiple function
   * calls produce different results.
   */
  mockImplementationOnce(fn: Function): JestMockFn,
  /**
   * Just a simple sugar function for returning `this`
   */
  mockReturnThis(): void,
  /**
   * Deprecated: use jest.fn(() => value) instead
   */
  mockReturnValue(value: any): JestMockFn,
  /**
   * Sugar for only returning a value once inside your mock
   */
  mockReturnValueOnce(value: any): JestMockFn
};

type JestAsymmetricEqualityType = {
  /**
   * A custom Jasmine equality tester
   */
  asymmetricMatch(value: mixed): boolean
};

type JestCallsType = {
  allArgs(): mixed,
  all(): mixed,
  any(): boolean,
  count(): number,
  first(): mixed,
  mostRecent(): mixed,
  reset(): void
};

type JestClockType = {
  install(): void,
  mockDate(date: Date): void,
  tick(): void,
  uninstall(): void
};

type JestMatcherResult = {
  message?: string | (() => string),
  pass: boolean
};

type JestMatcher = (actual: any, expected: any) => JestMatcherResult;

type JestPromiseType = {
  /**
   * Use rejects to unwrap the reason of a rejected promise so any other
   * matcher can be chained. If the promise is fulfilled the assertion fails.
   */
  rejects: JestExpectType,
  /**
   * Use resolves to unwrap the value of a fulfilled promise so any other
   * matcher can be chained. If the promise is rejected the assertion fails.
   */
  resolves: JestExpectType
};

type JestExpectType = {
  not: JestExpectType,
  /**
   * If you have a mock function, you can use .lastCalledWith to test what
   * arguments it was last called with.
   */
  lastCalledWith(...args: Array<any>): void,
  /**
   * toBe just checks that a value is what you expect. It uses === to check
   * strict equality.
   */
  toBe(value: any): void,
  /**
   * Use .toHaveBeenCalled to ensure that a mock function got called.
   */
  toBeCalled(): void,
  /**
   * Use .toBeCalledWith to ensure that a mock function was called with
   * specific arguments.
   */
  toBeCalledWith(...args: Array<any>): void,
  /**
   * Using exact equality with floating point numbers is a bad idea. Rounding
   * means that intuitive things fail.
   */
  toBeCloseTo(num: number, delta: any): void,
  /**
   * Use .toBeDefined to check that a variable is not undefined.
   */
  toBeDefined(): void,
  /**
   * Use .toBeFalsy when you don't care what a value is, you just want to
   * ensure a value is false in a boolean context.
   */
  toBeFalsy(): void,
  /**
   * To compare floating point numbers, you can use toBeGreaterThan.
   */
  toBeGreaterThan(number: number): void,
  /**
   * To compare floating point numbers, you can use toBeGreaterThanOrEqual.
   */
  toBeGreaterThanOrEqual(number: number): void,
  /**
   * To compare floating point numbers, you can use toBeLessThan.
   */
  toBeLessThan(number: number): void,
  /**
   * To compare floating point numbers, you can use toBeLessThanOrEqual.
   */
  toBeLessThanOrEqual(number: number): void,
  /**
   * Use .toBeInstanceOf(Class) to check that an object is an instance of a
   * class.
   */
  toBeInstanceOf(cls: Class<*>): void,
  /**
   * .toBeNull() is the same as .toBe(null) but the error messages are a bit
   * nicer.
   */
  toBeNull(): void,
  /**
   * Use .toBeTruthy when you don't care what a value is, you just want to
   * ensure a value is true in a boolean context.
   */
  toBeTruthy(): void,
  /**
   * Use .toBeUndefined to check that a variable is undefined.
   */
  toBeUndefined(): void,
  /**
   * Use .toContain when you want to check that an item is in a list. For
   * testing the items in the list, this uses ===, a strict equality check.
   */
  toContain(item: any): void,
  /**
   * Use .toContainEqual when you want to check that an item is in a list. For
   * testing the items in the list, this matcher recursively checks the
   * equality of all fields, rather than checking for object identity.
   */
  toContainEqual(item: any): void,
  /**
   * Use .toEqual when you want to check that two objects have the same value.
   * This matcher recursively checks the equality of all fields, rather than
   * checking for object identity.
   */
  toEqual(value: any): void,
  /**
   * Use .toHaveBeenCalled to ensure that a mock function got called.
   */
  toHaveBeenCalled(): void,
  /**
   * Use .toHaveBeenCalledTimes to ensure that a mock function got called exact
   * number of times.
   */
  toHaveBeenCalledTimes(number: number): void,
  /**
   * Use .toHaveBeenCalledWith to ensure that a mock function was called with
   * specific arguments.
   */
  toHaveBeenCalledWith(...args: Array<any>): void,
  /**
   * Check that an object has a .length property and it is set to a certain
   * numeric value.
   */
  toHaveLength(number: number): void,
  /**
   *
   */
  toHaveProperty(propPath: string, value?: any): void,
  /**
   * Use .toMatch to check that a string matches a regular expression.
   */
  toMatch(regexp: RegExp): void,
  /**
   * Use .toMatchObject to check that a javascript object matches a subset of the properties of an object.
   */
  toMatchObject(object: Object): void,
  /**
   * This ensures that a React component matches the most recent snapshot.
   */
  toMatchSnapshot(name?: string): void,
  /**
   * Use .toThrow to test that a function throws when it is called.
   */
  toThrow(message?: string | Error): void,
  /**
   * Use .toThrowError to test that a function throws a specific error when it
   * is called. The argument can be a string for the error message, a class for
   * the error, or a regex that should match the error.
   */
  toThrowError(message?: string | Error | RegExp): void,
  /**
   * Use .toThrowErrorMatchingSnapshot to test that a function throws a error
   * matching the most recent snapshot when it is called.
   */
  toThrowErrorMatchingSnapshot(): void
};

type JestObjectType = {
  /**
   *  Disables automatic mocking in the module loader.
   *
   *  After this method is called, all `require()`s will return the real
   *  versions of each module (rather than a mocked version).
   */
  disableAutomock(): JestObjectType,
  /**
   * An un-hoisted version of disableAutomock
   */
  autoMockOff(): JestObjectType,
  /**
   * Enables automatic mocking in the module loader.
   */
  enableAutomock(): JestObjectType,
  /**
   * An un-hoisted version of enableAutomock
   */
  autoMockOn(): JestObjectType,
  /**
   * Clears the mock.calls and mock.instances properties of all mocks.
   * Equivalent to calling .mockClear() on every mocked function.
   */
  clearAllMocks(): JestObjectType,
  /**
   * Resets the state of all mocks. Equivalent to calling .mockReset() on every
   * mocked function.
   */
  resetAllMocks(): JestObjectType,
  /**
   * Removes any pending timers from the timer system.
   */
  clearAllTimers(): void,
  /**
   * The same as `mock` but not moved to the top of the expectation by
   * babel-jest.
   */
  doMock(moduleName: string, moduleFactory?: any): JestObjectType,
  /**
   * The same as `unmock` but not moved to the top of the expectation by
   * babel-jest.
   */
  dontMock(moduleName: string): JestObjectType,
  /**
   * Returns a new, unused mock function. Optionally takes a mock
   * implementation.
   */
  fn(implementation?: Function): JestMockFn,
  /**
   * Determines if the given function is a mocked function.
   */
  isMockFunction(fn: Function): boolean,
  /**
   * Given the name of a module, use the automatic mocking system to generate a
   * mocked version of the module for you.
   */
  genMockFromModule(moduleName: string): any,
  /**
   * Mocks a module with an auto-mocked version when it is being required.
   *
   * The second argument can be used to specify an explicit module factory that
   * is being run instead of using Jest's automocking feature.
   *
   * The third argument can be used to create virtual mocks -- mocks of modules
   * that don't exist anywhere in the system.
   */
  mock(moduleName: string, moduleFactory?: any): JestObjectType,
  /**
   * Resets the module registry - the cache of all required modules. This is
   * useful to isolate modules where local state might conflict between tests.
   */
  resetModules(): JestObjectType,
  /**
   * Exhausts the micro-task queue (usually interfaced in node via
   * process.nextTick).
   */
  runAllTicks(): void,
  /**
   * Exhausts the macro-task queue (i.e., all tasks queued by setTimeout(),
   * setInterval(), and setImmediate()).
   */
  runAllTimers(): void,
  /**
   * Exhausts all tasks queued by setImmediate().
   */
  runAllImmediates(): void,
  /**
   * Executes only the macro task queue (i.e. all tasks queued by setTimeout()
   * or setInterval() and setImmediate()).
   */
  runTimersToTime(msToRun: number): void,
  /**
   * Executes only the macro-tasks that are currently pending (i.e., only the
   * tasks that have been queued by setTimeout() or setInterval() up to this
   * point)
   */
  runOnlyPendingTimers(): void,
  /**
   * Explicitly supplies the mock object that the module system should return
   * for the specified module. Note: It is recommended to use jest.mock()
   * instead.
   */
  setMock(moduleName: string, moduleExports: any): JestObjectType,
  /**
   * Indicates that the module system should never return a mocked version of
   * the specified module from require() (e.g. that it should always return the
   * real module).
   */
  unmock(moduleName: string): JestObjectType,
  /**
   * Instructs Jest to use fake versions of the standard timer functions
   * (setTimeout, setInterval, clearTimeout, clearInterval, nextTick,
   * setImmediate and clearImmediate).
   */
  useFakeTimers(): JestObjectType,
  /**
   * Instructs Jest to use the real versions of the standard timer functions.
   */
  useRealTimers(): JestObjectType,
  /**
   * Creates a mock function similar to jest.fn but also tracks calls to
   * object[methodName].
   */
  spyOn(object: Object, methodName: string): JestMockFn
};

type JestSpyType = {
  calls: JestCallsType
};

/** Runs this function after every test inside this context */
declare function afterEach(fn: Function): void;
/** Runs this function before every test inside this context */
declare function beforeEach(fn: Function): void;
/** Runs this function after all tests have finished inside this context */
declare function afterAll(fn: Function): void;
/** Runs this function before any tests have started inside this context */
declare function beforeAll(fn: Function): void;
/** A context for grouping tests together */
declare function describe(name: string, fn: Function): void;

/** An individual test unit */
declare var it: {
  /**
   * An individual test unit
   *
   * @param {string} Name of Test
   * @param {Function} Test
   */
  (name: string, fn?: Function): ?Promise<void>,
  /**
   * Only run this test
   *
   * @param {string} Name of Test
   * @param {Function} Test
   */
  only(name: string, fn?: Function): ?Promise<void>,
  /**
   * Skip running this test
   *
   * @param {string} Name of Test
   * @param {Function} Test
   */
  skip(name: string, fn?: Function): ?Promise<void>,
  /**
   * Run the test concurrently
   *
   * @param {string} Name of Test
   * @param {Function} Test
   */
  concurrent(name: string, fn?: Function): ?Promise<void>
};
declare function fit(name: string, fn: Function): ?Promise<void>;
/** An individual test unit */
declare var test: typeof it;
/** A disabled group of tests */
declare var xdescribe: typeof describe;
/** A focused group of tests */
declare var fdescribe: typeof describe;
/** A disabled individual test */
declare var xit: typeof it;
/** A disabled individual test */
declare var xtest: typeof it;

/** The expect function is used every time you want to test a value */
declare var expect: {
  /** The object that you want to make assertions against */
  (value: any): JestExpectType & JestPromiseType,
  /** Add additional Jasmine matchers to Jest's roster */
  extend(matchers: { [name: string]: JestMatcher }): void,
  /** Add a module that formats application-specific data structures. */
  addSnapshotSerializer(serializer: (input: Object) => string): void,
  assertions(expectedAssertions: number): void,
  hasAssertions(): void,
  any(value: mixed): JestAsymmetricEqualityType,
  anything(): void,
  arrayContaining(value: Array<mixed>): void,
  objectContaining(value: Object): void,
  /** Matches any received string that contains the exact expected string. */
  stringContaining(value: string): void,
  stringMatching(value: string | RegExp): void
};

// TODO handle return type
// http://jasmine.github.io/2.4/introduction.html#section-Spies
declare function spyOn(value: mixed, method: string): Object;

/** Holds all functions related to manipulating test runner */
declare var jest: JestObjectType;

/**
 * The global Jamine object, this is generally not exposed as the public API,
 * using features inside here could break in later versions of Jest.
 */
declare var jasmine: {
  DEFAULT_TIMEOUT_INTERVAL: number,
  any(value: mixed): JestAsymmetricEqualityType,
  anything(): void,
  arrayContaining(value: Array<mixed>): void,
  clock(): JestClockType,
  createSpy(name: string): JestSpyType,
  createSpyObj(
    baseName: string,
    methodNames: Array<string>
  ): { [methodName: string]: JestSpyType },
  objectContaining(value: Object): void,
  stringMatching(value: string): void
};
<|endoftext|>


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

/**
 * External dependencies
 */
import PropTypes from 'prop-types';
import classnames from 'classnames';

/**
 * Internal dependencies
 */
import SettingsNoticeSingleRow from './SettingsNoticeSingleRow';
import SettingsNoticeMultiRow from './SettingsNoticeMultiRow';
import { TYPE_INFO } from './utils';

export default function SettingsNotice( props ) {
	const { children, type } = props;

	return (
		<div className={ classnames(
			'googlesitekit-settings-notice',
			`googlesitekit-settings-notice--${ type }`
		) } >
			{ !! children && <SettingsNoticeMultiRow { ...props } /> }
			{ ! children && (
				<SettingsNoticeSingleRow { ...props } /> ) }

	);
}

SettingsNotice.propTypes = {
	children: PropTypes.node,
	notice: PropTypes.node.isRequired,
	type: PropTypes.oneOf( [ 'warning', 'info', 'suggestion' ] ),
	Icon: PropTypes.elementType,
	LearnMore: PropTypes.elementType,
};

SettingsNotice.defaultProps = {
	type: TYPE_INFO,
};
<commit_msg>Fix as per CR.<commit_after>/**
 * Settings notice component.
 *
 * Site Kit by Google, Copyright 2021 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import PropTypes from 'prop-types';

/**
 * Internal dependencies
 */
import SettingsNoticeSingleRow from './SettingsNoticeSingleRow';
import SettingsNoticeMultiRow from './SettingsNoticeMultiRow';
import { TYPE_INFO } from './utils';

export default function SettingsNotice( props ) {
	const { children, type } = props;

	return (
		<div className={ `googlesitekit-settings-notice googlesitekit-settings-notice--${ type }` } >
			{ !! children && <SettingsNoticeMultiRow { ...props } /> }
			{ ! children && (
				<SettingsNoticeSingleRow { ...props } />
			) }

	);
}

SettingsNotice.propTypes = {
	children: PropTypes.node,
	notice: PropTypes.node.isRequired,
	type: PropTypes.oneOf( [ 'warning', 'info', 'suggestion' ] ),
	Icon: PropTypes.elementType,
	LearnMore: PropTypes.elementType,
};

SettingsNotice.defaultProps = {
	type: TYPE_INFO,
};
<|endoftext|>