<commit_before>const [xml2js, request, _, utils, crypto] = [require('xml2js'), require('request'), require('lodash'), require('./utils'), require('crypto')];
// Wechat url config
const config = require('./url-config.js');

// "menu", "assistant", "user", "qrcode", "template"
const _defaultModules = ["user", "qrcode", "template"];
const _defaultEvents = ["subscribe", "unsubscribe", "scan", "report", "click", "view", "text", "image", "voice", "video", "shortvideo", "location", "link", "error","all"];
const Wechat = function (options) {
    "use strict";
    if (!(this instanceof Wechat)) {
        return new Wechat(options);
    }
    this.appId = options.appId;
    this.appSecret = options.appSecret;
    this.token = options.appToken;
    this.encodingAESKey = options.encodingAESKey;
    this.appAccount = options.appAccount || options.appId;
    this.redis = options.redis;
    this.useEncrypt = _.isBoolean(options.encrypt) ? options.encrypt : false;
    this.tokenKey = "wechat.access_token:" + this.appId; // token 存储key
    this.jsTicketKey = "wechat.js_ticket:" + this.appId; //js Ticket
    var self = this;
    // 载入module
    (_defaultModules.concat(Array.isArray(options.modules) ? options.modules : [])).sort().filter((item, index, arr) => {
        if (index == 0)
            return true;
        return arr[index - 1] != item;
    }).forEach((clazz) => { //load clazz
        try {
            self[clazz] = require("./modules/" + clazz)(self);
        } catch (err) {// skip
            console.error(`load [$clazz] module error:`, err);
        }
    });
    this.handlers = { all: { invoke: function (msg) { return "" }, hold: false } };
};

Wechat.prototype.decrypt = function (msg, msgType) {
    try {
        let _encodingAESKey = new Buffer(this.encodingAESKey + "=", 'base64'); // 密钥base64解码
        let decipher = crypto.Decipheriv('aes-256-cbc', _encodingAESKey, _encodingAESKey.slice(0, 16)); // 创建aes-256-cbc 解密
        decipher.setAutoPadding(false); // 取消自动填充
        return decipher.update(msg, msgType, 'utf8') + decipher.final('utf8'); // 解密数据
    } catch (err) {
        console.error("数据解密失败", err);
        return msg;
    }
};
Wechat.prototype.htonl = function (n) { // 主机子节序 to 网络子节序
    var buf = new Buffer(4);
    buf[0] = (n & 0xFF000000) >> 24;
    buf[1] = (n & 0x00FF0000) >> 16;
    buf[2] = (n & 0x0000FF00) >> 8;
    buf[3] = (n & 0x000000FF) >> 0;
    return buf;
};
Wechat.prototype.ntohl = function (buf) { // 网络子节序 解析
    if (buf && buf.length) {
        var sourceNumber = 0;
        for (var i = 0; i < 4; i++) {
            sourceNumber <<= 8;
            sourceNumber |= buf[i] & 0xff;
        }
        return sourceNumber;
    } else {
        return 0;
    }
};
Wechat.prototype.padding = function (n) { // 计算padding
    var len = n % 32;
    if (len == 0) {
        len = 32;
    } else {
        len = 32 - len;
    }
    var buf = new Buffer(len);
    for (var i = 0; i < len; i++) {
        buf[i] = len;
    }
    return buf;
};
Wechat.prototype.formatDecryptMsg = function (msg, charset, output) {
    charset = charset || "utf-8";
    output = output || "utf-8";
    var self = this;
    var buf = new Buffer(msg, charset); // string to buf
    var paddingLength = msg.charCodeAt(msg.length - 1); // 获取padding块大小
    var netBuf = buf.slice(16, 20); // 网络子节序
    buf = buf.slice(20, buf.length - paddingLength); // 消息体 ＋  微信ID
    var msgLength = this.ntohl(netBuf); // 通过网络子节序，计算消息长度
    var wechatId = buf.slice(msgLength, buf.length).toString(output); // 获取微信ID
    var msg = buf.slice(0, msgLength).toString(output); // 截取微信消息长度
    return {
        msg: msg,
        length: msgLength,
        wechatId: wechatId
    };
};
Wechat.prototype.encrypt = function (msg) {
    try {
        var self = this,
            msgBuf = new Buffer(msg, "utf-8"), // msg to buffer
            msgBufLength = msgBuf.length, // msg length
            preBuf = self.randomPrefix(16), // 16位随机串
            netBuf = self.htonl(msgBufLength), // 网络子节序
            appBuf = new Buffer(self.appId, "utf-8"), // 微信号ID
            appBufLength = appBuf.length, // 微信号ID 长度
            paddingBuf = self.padding(20 + msgBufLength + appBufLength); // pading 块
        let _encodingAESKey = new Buffer(this.encodingAESKey + "=", 'base64'); // 密钥base64解码
        let cipher = crypto.createCipheriv('aes-256-cbc', _encodingAESKey, _encodingAESKey.slice(0, 16)); // 创建aes-256-cbc 解密
        cipher.setAutoPadding(false); // 取消自动填充
        return cipher.update(Buffer.concat([preBuf, netBuf, msgBuf, appBuf, paddingBuf]), "binary", 'base64') + cipher.final('base64'); // 解密数据
    } catch (err) {
        console.error("数据加密失败", err);
        return msg;
    }
};

Wechat.prototype.randomPrefix = function (n) {
    var _str = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
    var _tmp = [];
    for (var i = 0; i < n; i++) {
        _tmp.push(_str.charAt(Math.floor(Math.random() * _str.length)));
    }
    return new Buffer(_tmp);
};

Wechat.prototype.encryptMsg = function (msg) {
    let msg_encrypt = this.encrypt(new Buffer(this.toXML(msg), "utf-8"));
    let timestamp = Date.now();
    let nonce = (Math.random() * 100000).toString(16).replace('\.', '');
    let msg_signature = crypto.createHash('sha1').update([this.appToken, timestamp, nonce, msg_encrypt].sort().join('')).digest('hex');
    return '<xml><Encrypt><![CDATA[' + msg_encrypt + ']]></Encrypt><MsgSignature><![CDATA[' + msg_signature + ']]></MsgSignature><TimeStamp>' + timestamp + '</TimeStamp><Nonce><![CDATA[' + nonce + ']]></Nonce></xml>';
};

Wechat.prototype.handler = function (req, res) {
    "use strict";
    let _query = req.query;
    let _signature = crypto.createHash('sha1').update([this.token, _query.timestamp, _query.nonce].sort().join('')).digest('hex');
    if (_signature != _query.signature) // check error
        return res.status(200).end('');
    var self = this;
    if (req.method.toUpperCase() !== "GET") {
        utils.streamHelper(req, (err, buf) => {
            if (err)
                return self.dealMsg('error', { req: req, res: res, msg: err });
            if (this.useEncrypt) { // encrypt msg
                xml2js.parseString(buf.toString('utf-8'), (err2, xml) => {
                    if (err2)
                        return self.dealMsg('error', { req: req, res: res, msg: err2 });
                    var formatMsg = self.formatDecryptMsg(self.decrypt(xml.xml.Encrypt[0], 'base64'));
                    self.parseData({
                        req: req,
                        res: res,
                        xml: formatMsg.msg // 应用消息
                    });
                    return;
                });
            } else {
                self.parseData({
                    req: req,
                    res: res,
                    xml: buf
                });
            }
            return;
        });
        return;
    } else {
        return res.status(200).end(_query.echostr);
    }
};

Wechat.prototype.parseData = function (data) {
    "use strict";
    var parser = new xml2js.Parser({ explicitArray: false, trim: true });
    // 解析xml
    parser.parseString(data.xml, (err, result) => {
        let msgType = "error";
        if (err) {
            data.msg = err;
        } else {
            data.msg = result.xml;
            msgType = result.xml.MsgType.toLowerCase() === "event" ? (result.xml.Event.toLowerCase() === "location" ? "report" : result.xml.Event.toLowerCase()) : result.xml.MsgType.toLowerCase();
        }
        this.dealMsg(msgType, data);
        return;
    });
};

// 处理消息
Wechat.prototype.dealMsg = function (type, data) {
    let self = this;
    let __handler = this.handlers[type] || this.handlers.all;
    if (!_.isObject(__handler) || !_.isFunction(__handler.invoke))
        __handler = { invoke: function () { return ""; }, hold: false };
    if (__handler.hold) { // keep weeting
        __handler.invoke(data.msg, (msg) => {
            if (_.isPlainObject(msg))
                return self.send(data.req, data.res, _.extend({
                    ToUserName: data.msg.FromUserName,
                    FromUserName: data.msg.ToUserName
                }, msg));
            return self.send(data.req, data.res, "");
        });
    } else {
        self.send(data.req, data.res, "");
        __handler.invoke(data.msg); // 处理消息
    }
};

//将 js 组装成 xml
Wechat.prototype.toXML = function (data) {
    //自动检测 MsgType
    let _pkg = _.clone(data);
    _pkg.CreateTime = Date.now() / 100;
    let _xml = new xml2js.Builder({ "rootName": "xml" }).buildObject(_pkg);
    return _xml;
};
Wechat.prototype.send = function (req, res, msg) {
    if (msg == "") {
        res.status(200).send(msg);
    } else {
        msg = this.toXML(msg);
        if (this.useEncrypt)
            msg = this.encryptMsg(msg);
        res.type("xml").status(200).send(msg);
    }
};
// 自动刷新Token并存储到指定位置
Wechat.prototype._flushToken = function (callback) {
    if (!_.isFunction(callback))
        callback = dprint;
    request(config.token.access_token.format(this.appId, this.appSecret), (err, res) => {
        var _data = JSON.parse(res.body);
        if (_data && _data.access_token) {
            callback(_data.access_token);
        } else {
            callback(err);
        }
    });
};
// 自动刷新Token并存储到指定位置
Wechat.prototype._flushTicket = function (callback) {
    if (!_.isFunction(callback))
        callback = dprint;
    this.getToken((err, accessToken) => {
        if (err) return callback(err);
        request(config.token.js_ticket.format(accessToken), (err, res) => {
            if (err) return callback(err);
            var _data = JSON.parse(res.body);
            if (_data && _data.ticket) {
                callback(_data.ticket);
            }
        });
    });
};

Wechat.prototype.getToken = function (cb) {
    if (!_.isFunction(cb))
        cb = dprint;
    var self = this;
    self.redis.incrby(self.tokenKey + ":flush", 2, (err, flush) => {
        if (err)
            return cb(err);
        if (flush == 2) { // 获得刷新权，刷新token
            self.redis.del(self.tokenKey + ":token", dprint); // 删除已过期token
            self._flushToken((token) => {
                self.redis.multi()
                    .set(self.tokenKey + ":token", token) // 设置access token
                    .set(self.tokenKey + ":flush", 1) // 设置key 为 1
                    .expire(self.tokenKey + ":flush", 7000) // 设置key 过期时间为7000s
                    .exec(dprint);
                cb(null, token);
            });
        } else if (flush % 2 == 1) { // token 有效，直接获取
            self.redis.get(self.tokenKey + ":token", (err, token) => {
                if (err) {
                    return cb(err);
                }
                if (token) {
                    return cb(null, token); // access token 存在返回token
                }
                cb(new Error("获取access token失败"));
            });
        } else if (flush != 2 && flush % 2 == 0) { // 当前正在刷新数据，等待刷新
            setTimeout(() => { // 200ms 后再获取access token
                self.getToken(cb);
            }, 100);
        }
    });
};
Wechat.prototype.getTicket = function (cb) {
    if (!_.isFunction(cb))
        cb = dprint;
    var self = this;
    self.redis.incrby(self.jsTicketKey + ":flush", 2, (err, flush) => {
        if (err)
            return cb(err);
        if (flush == 2) { // 获得刷新权，刷新token
            self.redis.del(self.jsTicketKey + ":token", dprint); // 删除已过期token
            self._flushTicket((token) => {
                self.redis.multi()
                    .set(self.jsTicketKey + ":token", token) // 设置access token
                    .set(self.jsTicketKey + ":flush", 1) // 设置key 为 1
                    .expire(self.jsTicketKey + ":flush", 7000) // 设置key 过期时间为7000s
                    .exec(dprint);
                cb(null, token);
            });
        } else if (flush % 2 == 1) { // token 有效，直接获取
            self.redis.get(self.jsTicketKey + ":token", (err, token) => {
                if (err) {
                    return cb(err);
                }
                if (token) {
                    return cb(null, token); // access token 存在返回token
                }
                cb(new Error("获取JS ticket失败"));
            });
        } else if (flush != 2 && flush % 2 == 0) { // 当前正在刷新数据，等待刷新
            setTimeout(() => { // 200ms 后再获取access token
                self.getTicket(cb);
            }, 100);
        }
    });
};

// 处理事件保存
_defaultEvents.forEach((event) => {
    Wechat.prototype[event] = function (func, hold) {
        this.handlers[event] = { invoke: func, hold: _.isBoolean(hold) ? hold : true };
        return this;
    };
});
var dprint = function (err) {
    if (err) {
        return console.error(err);
    }
};

module.exports = Wechat;<commit_msg>1.加密签名设置<commit_after>const [xml2js, request, _, utils, crypto] = [require('xml2js'), require('request'), require('lodash'), require('./utils'), require('crypto')];
// Wechat url config
const config = require('./url-config.js');

// "menu", "assistant", "user", "qrcode", "template"
const _defaultModules = ["user", "qrcode", "template"];
const _defaultEvents = ["subscribe", "unsubscribe", "scan", "report", "click", "view", "text", "image", "voice", "video", "shortvideo", "location", "link", "error", "all"];
const Wechat = function (options) {
    "use strict";
    if (!(this instanceof Wechat)) {
        return new Wechat(options);
    }
    this.appId = options.appId;
    this.appSecret = options.appSecret;
    this.token = options.appToken;
    this.encodingAESKey = options.encodingAESKey;
    this.appAccount = options.appAccount || options.appId;
    this.redis = options.redis;
    this.useEncrypt = _.isBoolean(options.encrypt) ? options.encrypt : false;
    this.tokenKey = "wechat.access_token:" + this.appId; // token 存储key
    this.jsTicketKey = "wechat.js_ticket:" + this.appId; //js Ticket
    var self = this;
    // 载入module
    (_defaultModules.concat(Array.isArray(options.modules) ? options.modules : [])).sort().filter((item, index, arr) => {
        if (index == 0)
            return true;
        return arr[index - 1] != item;
    }).forEach((clazz) => { //load clazz
        try {
            self[clazz] = require("./modules/" + clazz)(self);
        } catch (err) {// skip
            console.error(`load [$clazz] module error:`, err);
        }
    });
    this.handlers = { all: { invoke: function (msg) { return "" }, hold: false } };
};

Wechat.prototype.decrypt = function (msg, msgType) {
    try {
        let _encodingAESKey = new Buffer(this.encodingAESKey + "=", 'base64'); // 密钥base64解码
        let decipher = crypto.Decipheriv('aes-256-cbc', _encodingAESKey, _encodingAESKey.slice(0, 16)); // 创建aes-256-cbc 解密
        decipher.setAutoPadding(false); // 取消自动填充
        return decipher.update(msg, msgType, 'utf8') + decipher.final('utf8'); // 解密数据
    } catch (err) {
        console.error("数据解密失败", err);
        return msg;
    }
};
Wechat.prototype.htonl = function (n) { // 主机子节序 to 网络子节序
    var buf = new Buffer(4);
    buf[0] = (n & 0xFF000000) >> 24;
    buf[1] = (n & 0x00FF0000) >> 16;
    buf[2] = (n & 0x0000FF00) >> 8;
    buf[3] = (n & 0x000000FF) >> 0;
    return buf;
};
Wechat.prototype.ntohl = function (buf) { // 网络子节序 解析
    if (buf && buf.length) {
        var sourceNumber = 0;
        for (var i = 0; i < 4; i++) {
            sourceNumber <<= 8;
            sourceNumber |= buf[i] & 0xff;
        }
        return sourceNumber;
    } else {
        return 0;
    }
};
Wechat.prototype.padding = function (n) { // 计算padding
    var len = n % 32;
    if (len == 0) {
        len = 32;
    } else {
        len = 32 - len;
    }
    var buf = new Buffer(len);
    for (var i = 0; i < len; i++) {
        buf[i] = len;
    }
    return buf;
};
Wechat.prototype.formatDecryptMsg = function (msg, charset, output) {
    charset = charset || "utf-8";
    output = output || "utf-8";
    var self = this;
    var buf = new Buffer(msg, charset); // string to buf
    var paddingLength = msg.charCodeAt(msg.length - 1); // 获取padding块大小
    var netBuf = buf.slice(16, 20); // 网络子节序
    buf = buf.slice(20, buf.length - paddingLength); // 消息体 ＋  微信ID
    var msgLength = this.ntohl(netBuf); // 通过网络子节序，计算消息长度
    var wechatId = buf.slice(msgLength, buf.length).toString(output); // 获取微信ID
    var msg = buf.slice(0, msgLength).toString(output); // 截取微信消息长度
    return {
        msg: msg,
        length: msgLength,
        wechatId: wechatId
    };
};
Wechat.prototype.encrypt = function (msg) {
    try {
        var self = this,
            msgBuf = new Buffer(msg, "utf-8"), // msg to buffer
            msgBufLength = msgBuf.length, // msg length
            preBuf = self.randomPrefix(16), // 16位随机串
            netBuf = self.htonl(msgBufLength), // 网络子节序
            appBuf = new Buffer(self.appId, "utf-8"), // 微信号ID
            appBufLength = appBuf.length, // 微信号ID 长度
            paddingBuf = self.padding(20 + msgBufLength + appBufLength); // pading 块
        let _encodingAESKey = new Buffer(this.encodingAESKey + "=", 'base64'); // 密钥base64解码
        let cipher = crypto.createCipheriv('aes-256-cbc', _encodingAESKey, _encodingAESKey.slice(0, 16)); // 创建aes-256-cbc 解密
        cipher.setAutoPadding(false); // 取消自动填充
        return cipher.update(Buffer.concat([preBuf, netBuf, msgBuf, appBuf, paddingBuf]), "binary", 'base64') + cipher.final('base64'); // 解密数据
    } catch (err) {
        console.error("数据加密失败", err);
        return msg;
    }
};

Wechat.prototype.randomPrefix = function (n) {
    var _str = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
    var _tmp = [];
    for (var i = 0; i < n; i++) {
        _tmp.push(_str.charAt(Math.floor(Math.random() * _str.length)));
    }
    return new Buffer(_tmp);
};

Wechat.prototype.encryptMsg = function (msg) {
    let msg_encrypt = this.encrypt(new Buffer(this.toXML(msg), "utf-8"));
    let timestamp = Math.floor(Date.now() / 1000);
    let nonce = (Math.random() * 100000).toString(16).replace('\.', '');
    let msg_signature = crypto.createHash('sha1').update([this.appToken, timestamp, nonce, msg_encrypt].sort().join('')).digest('hex');
    return '<xml><Encrypt><![CDATA[' + msg_encrypt + ']]></Encrypt><MsgSignature><![CDATA[' + msg_signature + ']]></MsgSignature><TimeStamp>' + timestamp + '</TimeStamp><Nonce><![CDATA[' + nonce + ']]></Nonce></xml>';
};

Wechat.prototype.handler = function (req, res) {
    "use strict";
    let _query = req.query;
    let _signature = crypto.createHash('sha1').update([this.token, _query.timestamp, _query.nonce].sort().join('')).digest('hex');
    if (_signature != _query.signature) // check error
        return res.status(200).end('');
    var self = this;
    if (req.method.toUpperCase() !== "GET") {
        utils.streamHelper(req, (err, buf) => {
            if (err)
                return self.dealMsg('error', { req: req, res: res, msg: err });
            if (this.useEncrypt) { // encrypt msg
                xml2js.parseString(buf.toString('utf-8'), (err2, xml) => {
                    if (err2)
                        return self.dealMsg('error', { req: req, res: res, msg: err2 });
                    var formatMsg = self.formatDecryptMsg(self.decrypt(xml.xml.Encrypt[0], 'base64'));
                    self.parseData({
                        req: req,
                        res: res,
                        xml: formatMsg.msg // 应用消息
                    });
                    return;
                });
            } else {
                self.parseData({
                    req: req,
                    res: res,
                    xml: buf
                });
            }
            return;
        });
        return;
    } else {
        return res.status(200).end(_query.echostr);
    }
};

Wechat.prototype.parseData = function (data) {
    "use strict";
    var parser = new xml2js.Parser({ explicitArray: false, trim: true });
    // 解析xml
    parser.parseString(data.xml, (err, result) => {
        let msgType = "error";
        if (err) {
            data.msg = err;
        } else {
            data.msg = result.xml;
            msgType = result.xml.MsgType.toLowerCase() === "event" ? (result.xml.Event.toLowerCase() === "location" ? "report" : result.xml.Event.toLowerCase()) : result.xml.MsgType.toLowerCase();
        }
        this.dealMsg(msgType, data);
        return;
    });
};

// 处理消息
Wechat.prototype.dealMsg = function (type, data) {
    let self = this;
    let __handler = this.handlers[type] || this.handlers.all;
    if (!_.isObject(__handler) || !_.isFunction(__handler.invoke))
        __handler = { invoke: function () { return ""; }, hold: false };
    if (__handler.hold) { // keep weeting
        __handler.invoke(data.msg, (msg) => {
            if (_.isPlainObject(msg))
                return self.send(data.req, data.res, _.extend({
                    ToUserName: data.msg.FromUserName,
                    FromUserName: data.msg.ToUserName
                }, msg));
            return self.send(data.req, data.res, "");
        });
    } else {
        self.send(data.req, data.res, "");
        __handler.invoke(data.msg); // 处理消息
    }
};

//将 js 组装成 xml
Wechat.prototype.toXML = function (data) {
    //自动检测 MsgType
    let _pkg = _.clone(data);
    _pkg.CreateTime = Math.floor(Date.now() / 1000);
    let _xml = new xml2js.Builder({ "rootName": "xml" }).buildObject(_pkg);
    return _xml;
};
Wechat.prototype.send = function (req, res, msg) {
    if (msg == "") {
        res.status(200).send(msg);
    } else {
        if (this.useEncrypt) {
            msg = this.encryptMsg(msg);
        } else {
            msg = this.toXML(msg);
        }
        res.type("xml").status(200).send(msg);
    }
};
// 自动刷新Token并存储到指定位置
Wechat.prototype._flushToken = function (callback) {
    if (!_.isFunction(callback))
        callback = dprint;
    request(config.token.access_token.format(this.appId, this.appSecret), (err, res) => {
        var _data = JSON.parse(res.body);
        if (_data && _data.access_token) {
            callback(_data.access_token);
        } else {
            callback(err);
        }
    });
};
// 自动刷新Token并存储到指定位置
Wechat.prototype._flushTicket = function (callback) {
    if (!_.isFunction(callback))
        callback = dprint;
    this.getToken((err, accessToken) => {
        if (err) return callback(err);
        request(config.token.js_ticket.format(accessToken), (err, res) => {
            if (err) return callback(err);
            var _data = JSON.parse(res.body);
            if (_data && _data.ticket) {
                callback(_data.ticket);
            }
        });
    });
};

Wechat.prototype.getToken = function (cb) {
    if (!_.isFunction(cb))
        cb = dprint;
    var self = this;
    self.redis.incrby(self.tokenKey + ":flush", 2, (err, flush) => {
        if (err)
            return cb(err);
        if (flush == 2) { // 获得刷新权，刷新token
            self.redis.del(self.tokenKey + ":token", dprint); // 删除已过期token
            self._flushToken((token) => {
                self.redis.multi()
                    .set(self.tokenKey + ":token", token) // 设置access token
                    .set(self.tokenKey + ":flush", 1) // 设置key 为 1
                    .expire(self.tokenKey + ":flush", 7000) // 设置key 过期时间为7000s
                    .exec(dprint);
                cb(null, token);
            });
        } else if (flush % 2 == 1) { // token 有效，直接获取
            self.redis.get(self.tokenKey + ":token", (err, token) => {
                if (err) {
                    return cb(err);
                }
                if (token) {
                    return cb(null, token); // access token 存在返回token
                }
                cb(new Error("获取access token失败"));
            });
        } else if (flush != 2 && flush % 2 == 0) { // 当前正在刷新数据，等待刷新
            setTimeout(() => { // 200ms 后再获取access token
                self.getToken(cb);
            }, 100);
        }
    });
};
Wechat.prototype.getTicket = function (cb) {
    if (!_.isFunction(cb))
        cb = dprint;
    var self = this;
    self.redis.incrby(self.jsTicketKey + ":flush", 2, (err, flush) => {
        if (err)
            return cb(err);
        if (flush == 2) { // 获得刷新权，刷新token
            self.redis.del(self.jsTicketKey + ":token", dprint); // 删除已过期token
            self._flushTicket((token) => {
                self.redis.multi()
                    .set(self.jsTicketKey + ":token", token) // 设置access token
                    .set(self.jsTicketKey + ":flush", 1) // 设置key 为 1
                    .expire(self.jsTicketKey + ":flush", 7000) // 设置key 过期时间为7000s
                    .exec(dprint);
                cb(null, token);
            });
        } else if (flush % 2 == 1) { // token 有效，直接获取
            self.redis.get(self.jsTicketKey + ":token", (err, token) => {
                if (err) {
                    return cb(err);
                }
                if (token) {
                    return cb(null, token); // access token 存在返回token
                }
                cb(new Error("获取JS ticket失败"));
            });
        } else if (flush != 2 && flush % 2 == 0) { // 当前正在刷新数据，等待刷新
            setTimeout(() => { // 200ms 后再获取access token
                self.getTicket(cb);
            }, 100);
        }
    });
};

// 处理事件保存
_defaultEvents.forEach((event) => {
    Wechat.prototype[event] = function (func, hold) {
        this.handlers[event] = { invoke: func, hold: _.isBoolean(hold) ? hold : true };
        return this;
    };
});
var dprint = function (err) {
    if (err) {
        return console.error(err);
    }
};

module.exports = Wechat;<|endoftext|>


<commit_before>/* global django */

const $ = require('jquery')
// const L = require('leaflet')
const FileSaver = require('file-saver')
const shp = require('shpjs')

function createMap (L, baseurl, attribution, e) {
  const basemap = baseurl + '{z}/{x}/{y}.png'
  const baselayer = L.tileLayer(basemap, { maxZoom: 18, attribution: attribution })
  const map = new L.Map(e, {scrollWheelZoom: false, zoomControl: true, minZoom: 2})
  baselayer.addTo(map)
  return map
}

function getBaseBounds (L, polygon, bbox) {
  if (polygon) {
    if (polygon.type === 'FeatureCollection' && polygon.features.length === 0) {
      return bbox
    }
    return L.geoJson(polygon).getBounds()
  } else {
    return bbox
  }
}

function loadShape (map, group, shape, $input, msg) {
  const isEmpty = group.getLayers().length === 0

  if (isEmpty || window.confirm(msg)) {
    group.clearLayers()
    shape.eachLayer(function (layer) {
      group.addLayer(layer)
    })
    map.fitBounds(group.getBounds())

    $input.val(JSON.stringify(group.toGeoJSON()))
    $input.trigger('change')
  }
}

(function (init) {
  $(init)
  $(document).on('a4.embed.ready', init)
})(function () {
  // Prevent from including leaflet in this bundle
  const L = window.L

  const ExportControl = L.Control.extend({
    // Options
    options: {
      position: 'topright',
      onImportFileChange: null,
      onExportLinkClick: null
    },

    onAdd: function () {
      const container = L.DomUtil.create('div', 'leaflet-bar leaflet-control leaflet-control-custom')

      const exportLink = L.DomUtil.create('a', '', container)
      const exportIcon = L.DomUtil.create('i', 'fa fa-download', exportLink)
      exportLink.setAttribute('title', django.gettext('Export as GeoJSON'))
      exportIcon.setAttribute('aria-label', django.gettext('Export as GeoJSON'))

      if (this.options.onExportLinkClick) {
        exportLink.onclick = this.options.onExportLinkClick
      }

      // FIXME: is this accessible doe we need a label or something?
      const importInput = L.DomUtil.create('input', 'sr-only', container)
      importInput.setAttribute('type', 'file')

      const importLink = L.DomUtil.create('a', '', container)
      const importIcon = L.DomUtil.create('i', 'fa fa-upload', importLink)
      importLink.setAttribute('title', django.gettext('Import shapefile or GeoJSON file'))
      importIcon.setAttribute('aria-label', django.gettext('Import shapefile or GeoJSON file'))

      importLink.onclick = function (e) {
        // FIXME: is preventing the default event required?
        e.preventDefault()
        e.stopPropagation()
        importInput.click()
      }

      if (this.options.onImportFileChange) {
        importInput.onchange = this.options.onImportFileChange
      }

      return container
    }
  })

  $('[data-map="choose_polygon"]').each(function (i, e) {
    const name = e.getAttribute('data-name')
    const polygon = JSON.parse(e.getAttribute('data-polygon'))
    const bbox = JSON.parse(e.getAttribute('data-bbox'))
    const baseurl = e.getAttribute('data-baseurl')
    const attribution = e.getAttribute('data-attribution')

    const map = createMap(L, baseurl, attribution, e)

    const polygonStyle = {
      'color': '#0076ae',
      'weight': 2,
      'opacity': 1,
      'fillOpacity': 0.2
    }

    let drawnItems
    if (polygon) {
      drawnItems = L.geoJson(polygon, {
        style: polygonStyle
      })
      if (drawnItems.getLayers().length > 0) {
        map.fitBounds(drawnItems.getBounds())
      } else {
        map.fitBounds(getBaseBounds(L, polygon, bbox))
      }
    } else {
      drawnItems = L.featureGroup()
      map.fitBounds(getBaseBounds(L, polygon, bbox))
    }
    drawnItems.addTo(map)

    map.addControl(new L.Control.Draw({
      edit: {
        featureGroup: drawnItems,
        edit: {
          selectedPathOptions: {
            maintainColor: true
          }
        }
      },
      draw: {
        polygon: {
          shapeOptions: polygonStyle
        },
        rectangle: {
          shapeOptions: polygonStyle
        },
        marker: false,
        circlemarker: false,
        polyline: false,
        circle: false
      }
    }))

    map.on(L.Draw.Event.CREATED, function (event) {
      const layer = event.layer
      drawnItems.addLayer(layer)
      const shape = drawnItems.toGeoJSON()
      $('#id_' + name).val(JSON.stringify(shape))
      $('#id_' + name).trigger('change')
    })

    map.on(L.Draw.Event.EDITED, function (event) {
      const shape = drawnItems.toGeoJSON()
      $('#id_' + name).val(JSON.stringify(shape))
      $('#id_' + name).trigger('change')
    })

    map.on(L.Draw.Event.DELETED, function (event) {
      const shape = drawnItems.toGeoJSON()
      $('#id_' + name).val(JSON.stringify(shape))
      $('#id_' + name).trigger('change')
    })

    $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
      map.invalidateSize().fitBounds(getBaseBounds(L, polygon, bbox))
    })

    $('#select_' + name).on('change', function (event) {
      const geoJson = event.target.value
      if (geoJson) {
        const shape = L.geoJson(JSON.parse(geoJson), {
          style: polygonStyle
        })

        loadShape(map, drawnItems, shape, $('#id_' + name),
          django.gettext('Do you want to load this preset and delete all the existing polygons?'))
      }
    })

    map.addControl(new ExportControl({
      onExportLinkClick: function (e) {
        const shape = drawnItems.toGeoJSON()
        const blob = new window.Blob([JSON.stringify(shape)], {type: 'application/json'})
        FileSaver.saveAs(blob, 'export.geojson')
      },

      onImportFileChange: function (e) {
        e.preventDefault()
        e.stopPropagation()

        if (e.target.files.length < 1) {
          return
        }
        const file = e.target.files[0]

        if (file.name.slice(-3) === 'zip') {
          const reader = new window.FileReader()
          reader.onload = function (e) {
            const buffer = e.target.result
            shp(buffer).then(function (geoJson) {
              let shape
              try {
                shape = L.geoJson(geoJson, {
                  style: polygonStyle
                })
              } catch (e) {
                window.alert(django.gettext('The uploaded file is not a valid shapefile.'))
                return
              }
              loadShape(map, drawnItems, shape, $('#id_' + name),
                django.gettext('Do you want to import this file and delete all the existing polygons?'))
            }, function (e) {
              window.alert(django.gettext('The uploaded file is not a valid shapefile.'))
            })
          }
          reader.readAsArrayBuffer(file)
        } else if (file.name.slice(-4) === 'json') {
          let reader = new window.FileReader()
          reader.onload = function (e) {
            const buffer = e.target.result
            const decodedString = String.fromCharCode.apply(null, new Uint8Array(buffer))

            let shape
            try {
              const geoJson = JSON.parse(decodedString)
              shape = L.geoJson(geoJson, {
                style: polygonStyle
              })
            } catch (e) {
              window.alert(django.gettext('The uploaded file is not a valid geojson file.'))
              return
            }
            loadShape(map, drawnItems, shape, $('#id_' + name),
              django.gettext('Do you want to import this file and delete all the existing polygons?'))
          }
          reader.readAsArrayBuffer(file)
        } else {
          window.alert(django.gettext('Invalid file format. Only shapefiles (.zip) and geojson (.geojson or .json) are supported.'))
        }
      }
    }))
  })
})
<commit_msg>Minor refactoring<commit_after>/* global django */

const $ = require('jquery')
// const L = require('leaflet')
const FileSaver = require('file-saver')
const shp = require('shpjs')

function createMap (L, baseurl, attribution, e) {
  const basemap = baseurl + '{z}/{x}/{y}.png'
  const baselayer = L.tileLayer(basemap, { maxZoom: 18, attribution: attribution })
  const map = new L.Map(e, {scrollWheelZoom: false, zoomControl: true, minZoom: 2})
  baselayer.addTo(map)
  return map
}

function getBaseBounds (L, polygon, bbox) {
  if (polygon) {
    if (polygon.type === 'FeatureCollection' && polygon.features.length === 0) {
      return bbox
    }
    return L.geoJson(polygon).getBounds()
  } else {
    return bbox
  }
}

function loadShape (map, group, shape, $input, msg) {
  const isEmpty = group.getLayers().length === 0

  if (isEmpty || window.confirm(msg)) {
    group.clearLayers()
    shape.eachLayer(function (layer) {
      group.addLayer(layer)
    })
    map.fitBounds(group.getBounds())

    $input.val(JSON.stringify(group.toGeoJSON()))
    $input.trigger('change')
  }
}

(function (init) {
  $(init)
  $(document).on('a4.embed.ready', init)
})(function () {
  // Prevent from including leaflet in this bundle
  const L = window.L

  const ExportControl = L.Control.extend({
    // Options
    options: {
      position: 'topright',
      onImport: null,
      onExport: null
    },

    onAdd: function (map) {
      const container = L.DomUtil.create('div', 'leaflet-bar leaflet-control leaflet-control-custom')

      const exportLink = L.DomUtil.create('a', '', container)
      const exportIcon = L.DomUtil.create('i', 'fa fa-download', exportLink)
      exportLink.setAttribute('title', django.gettext('Export as GeoJSON'))
      exportIcon.setAttribute('aria-label', django.gettext('Export as GeoJSON'))

      if (this.options.onExport) {
        exportLink.onclick = () => this.options.onExport(map)
      }

      // FIXME: is this accessible or do we need a label or something?
      const importInput = L.DomUtil.create('input', 'sr-only', container)
      importInput.setAttribute('type', 'file')

      const importLink = L.DomUtil.create('a', '', container)
      const importIcon = L.DomUtil.create('i', 'fa fa-upload', importLink)
      importLink.setAttribute('title', django.gettext('Import shapefile or GeoJSON file'))
      importIcon.setAttribute('aria-label', django.gettext('Import shapefile or GeoJSON file'))

      importLink.onclick = function (e) {
        // FIXME: is preventing the default event required?
        e.preventDefault()
        e.stopPropagation()
        importInput.click()
      }

      if (this.options.onImport) {
        importInput.onchange = (e) => {
          // FIXME: is preventing the default event required?
          e.preventDefault()
          e.stopPropagation()

          if (e.target.files.length < 1) {
            return
          }
          return this.options.onImport(map, e.target.files[0])
        }
      }

      return container
    }
  })

  $('[data-map="choose_polygon"]').each(function (i, e) {
    const name = e.getAttribute('data-name')
    const polygon = JSON.parse(e.getAttribute('data-polygon'))
    const bbox = JSON.parse(e.getAttribute('data-bbox'))
    const baseurl = e.getAttribute('data-baseurl')
    const attribution = e.getAttribute('data-attribution')

    const map = createMap(L, baseurl, attribution, e)

    const polygonStyle = {
      'color': '#0076ae',
      'weight': 2,
      'opacity': 1,
      'fillOpacity': 0.2
    }

    let drawnItems
    if (polygon) {
      drawnItems = L.geoJson(polygon, {
        style: polygonStyle
      })
      if (drawnItems.getLayers().length > 0) {
        map.fitBounds(drawnItems.getBounds())
      } else {
        map.fitBounds(getBaseBounds(L, polygon, bbox))
      }
    } else {
      drawnItems = L.featureGroup()
      map.fitBounds(getBaseBounds(L, polygon, bbox))
    }
    drawnItems.addTo(map)

    map.addControl(new L.Control.Draw({
      edit: {
        featureGroup: drawnItems,
        edit: {
          selectedPathOptions: {
            maintainColor: true
          }
        }
      },
      draw: {
        polygon: {
          shapeOptions: polygonStyle
        },
        rectangle: {
          shapeOptions: polygonStyle
        },
        marker: false,
        circlemarker: false,
        polyline: false,
        circle: false
      }
    }))

    map.on(L.Draw.Event.CREATED, function (event) {
      const layer = event.layer
      drawnItems.addLayer(layer)
      const shape = drawnItems.toGeoJSON()
      $('#id_' + name).val(JSON.stringify(shape))
      $('#id_' + name).trigger('change')
    })

    map.on(L.Draw.Event.EDITED, function (event) {
      const shape = drawnItems.toGeoJSON()
      $('#id_' + name).val(JSON.stringify(shape))
      $('#id_' + name).trigger('change')
    })

    map.on(L.Draw.Event.DELETED, function (event) {
      const shape = drawnItems.toGeoJSON()
      $('#id_' + name).val(JSON.stringify(shape))
      $('#id_' + name).trigger('change')
    })

    $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
      map.invalidateSize().fitBounds(getBaseBounds(L, polygon, bbox))
    })

    $('#select_' + name).on('change', function (event) {
      const geoJson = event.target.value
      if (geoJson) {
        const shape = L.geoJson(JSON.parse(geoJson), {
          style: polygonStyle
        })

        loadShape(map, drawnItems, shape, $('#id_' + name),
          django.gettext('Do you want to load this preset and delete all the existing polygons?'))
      }
    })

    map.addControl(new ExportControl({
      onExport: function (map) {
        const shape = drawnItems.toGeoJSON()
        const blob = new window.Blob([JSON.stringify(shape)], {type: 'application/json'})
        FileSaver.saveAs(blob, 'export.geojson')
      },

      onImport: function (map, file) {
        if (file.name.slice(-3) === 'zip') {
          const reader = new window.FileReader()
          reader.onload = function (e) {
            const buffer = e.target.result
            shp(buffer).then(function (geoJson) {
              let shape
              try {
                shape = L.geoJson(geoJson, {
                  style: polygonStyle
                })
              } catch (e) {
                window.alert(django.gettext('The uploaded file is not a valid shapefile.'))
                return
              }
              loadShape(map, drawnItems, shape, $('#id_' + name),
                django.gettext('Do you want to import this file and delete all the existing polygons?'))
            }, function (e) {
              window.alert(django.gettext('The uploaded file is not a valid shapefile.'))
            })
          }
          reader.readAsArrayBuffer(file)
        } else if (file.name.slice(-4) === 'json') {
          let reader = new window.FileReader()
          reader.onload = function (e) {
            const buffer = e.target.result
            const decodedString = String.fromCharCode.apply(null, new Uint8Array(buffer))

            let shape
            try {
              const geoJson = JSON.parse(decodedString)
              shape = L.geoJson(geoJson, {
                style: polygonStyle
              })
            } catch (e) {
              window.alert(django.gettext('The uploaded file is not a valid geojson file.'))
              return
            }
            loadShape(map, drawnItems, shape, $('#id_' + name),
              django.gettext('Do you want to import this file and delete all the existing polygons?'))
          }
          reader.readAsArrayBuffer(file)
        } else {
          window.alert(django.gettext('Invalid file format. Only shapefiles (.zip) and geojson (.geojson or .json) are supported.'))
        }
      }
    }))
  })
})
<|endoftext|>


<commit_before>'use strict';

var convertExpression = require('./convert-expression');

module.exports = ( function(){

  function removeStepValue(expression){
    var multiplePattern = /^((\d+(\,\d+){0,})|\*)\/(\d+)$/g;
    var match = multiplePattern.exec(expression);
    if(match !== null && match.length > 0 ) {
      expression = match[1];
    }
    return expression;
  }

  function isValidExpression(expression, min, max){
    expression = removeStepValue(expression);
    var options = expression.split(',');
    var regexValidation = /^\d+$|^\*$|^\*\/\d+$/;
    for(var i = 0; i < options.length; i++){
      var option = options[i];
      var optionAsInt = parseInt(options[i], 10);
      if(optionAsInt < min || optionAsInt > max || !regexValidation.test(option)) {
        return false;
      }
    }
    return true;
  }

  function isInvalidSecond(expression){
    return !isValidExpression(expression, 0, 59);
  }

  function isInvalidMinute(expression){
    return !isValidExpression(expression, 0, 59);
  }

  function isInvalidHour(expression){
    return !isValidExpression(expression, 0, 23);
  }

  function isInvalidDayOfMonth(expression){
    return !isValidExpression(expression, 1, 31);
  }

  function isInvalidMonth(expression){
    return !isValidExpression(expression, 1, 12);
  }

  function isInvalidWeekDay(expression){
    return !isValidExpression(expression, 0, 7);
  }

  function validate(pattern){
    var patterns = pattern.split(' ');
    var executablePattern = convertExpression(pattern);
    var executablePatterns = executablePattern.split(' ');

    if(patterns.length === 5){
      patterns = ['0'].concat(patterns);
    }

    if (isInvalidSecond(executablePatterns[0])) {
      throw patterns[0] + ' is a invalid expression for second';
    }

    if (isInvalidMinute(executablePatterns[1])) {
      throw patterns[1] + ' is a invalid expression for minute';
    }

    if (isInvalidHour(executablePatterns[2])) {
      throw patterns[2] + ' is a invalid expression for hour';
    }

    if (isInvalidDayOfMonth(executablePatterns[3])) {
      throw patterns[3] + ' is a invalid expression for day of month';
    }

    if (isInvalidMonth(executablePatterns[4])) {
      throw patterns[4] + ' is a invalid expression for month';
    }

    if (isInvalidWeekDay(executablePatterns[5])) {
      throw patterns[5] + ' is a invalid expression for week day';
    }
  }

  return validate;
}());
<commit_msg>removing unused step validation<commit_after>'use strict';

var convertExpression = require('./convert-expression');

module.exports = ( function(){
  function isValidExpression(expression, min, max){
    var options = expression.split(',');
    var regexValidation = /^\d+$|^\*$|^\*\/\d+$/;
    for(var i = 0; i < options.length; i++){
      var option = options[i];
      var optionAsInt = parseInt(options[i], 10);
      if(optionAsInt < min || optionAsInt > max || !regexValidation.test(option)) {
        return false;
      }
    }
    return true;
  }

  function isInvalidSecond(expression){
    return !isValidExpression(expression, 0, 59);
  }

  function isInvalidMinute(expression){
    return !isValidExpression(expression, 0, 59);
  }

  function isInvalidHour(expression){
    return !isValidExpression(expression, 0, 23);
  }

  function isInvalidDayOfMonth(expression){
    return !isValidExpression(expression, 1, 31);
  }

  function isInvalidMonth(expression){
    return !isValidExpression(expression, 1, 12);
  }

  function isInvalidWeekDay(expression){
    return !isValidExpression(expression, 0, 7);
  }

  function validate(pattern){
    var patterns = pattern.split(' ');
    var executablePattern = convertExpression(pattern);
    var executablePatterns = executablePattern.split(' ');

    if(patterns.length === 5){
      patterns = ['0'].concat(patterns);
    }

    if (isInvalidSecond(executablePatterns[0])) {
      throw patterns[0] + ' is a invalid expression for second';
    }

    if (isInvalidMinute(executablePatterns[1])) {
      throw patterns[1] + ' is a invalid expression for minute';
    }

    if (isInvalidHour(executablePatterns[2])) {
      throw patterns[2] + ' is a invalid expression for hour';
    }

    if (isInvalidDayOfMonth(executablePatterns[3])) {
      throw patterns[3] + ' is a invalid expression for day of month';
    }

    if (isInvalidMonth(executablePatterns[4])) {
      throw patterns[4] + ' is a invalid expression for month';
    }

    if (isInvalidWeekDay(executablePatterns[5])) {
      throw patterns[5] + ' is a invalid expression for week day';
    }
  }

  return validate;
}());
<|endoftext|>


<commit_before>/**
 * Multiremote example
 * To run this script you need to have Mocha installed globally on your system.
 * If not try to run: $ npm install -g mocha
 *
 * To execute it just run it as a spec with a fair amount of timeout:
 * $ mocha -t 9999999 examples/webdriverio.multiremote.chat.js
 */
var io = require('socket.io-client');
var ninjaSocket;
var WebdriverIO = require('webdriverio'),
    matrix = WebdriverIO.multiremote({
       browserB: { desiredCapabilities: { browserName: 'chrome' } },
       /* browserB: {
            desiredCapabilities:
            {
                browserName: 'phantomjs',
                //'phantomjs.binary.path': require('../node_modules/phantomjs').path,
                'phantomjs.cli.args': [
                '--ignore-ssl-errors=true',
                '--ssl-protocol=any', // tlsv1
                '--web-security=false',
                '--load-images=false',
          //'--debug=false',
          //'--webdriver-logfile=webdriver.log',
          //'--webdriver-loglevel=DEBUG',
                ],
                logLevel: 'silent'
            }
        }
        */
    }),
  //  browserA = matrix.select('browserA'),
    browserB = matrix.select('browserB');

var should = require('should');
    var chai = require('chai');
    var chaiAsPromised = require('chai-as-promised');

    chai.use(chaiAsPromised);
    expect = chai.expect;
    chai.Should();
    chaiAsPromised.transferPromiseness = browserB.transferPromiseness;

/**
 * Multiremote example
 * To run this script you need to have Mocha installed globally on your system.
 * If not try to run: $ npm install -g mocha
 *
 * To execute it just run it as a spec with a fair amount of timeout:
 * $ mocha -t 9999999 examples/webdriverio.multiremote.chat.js
 */

describe('multiremote', function() {

    //this.timeout = 99999999;
    before(function() {

		ninjaSocket = io('https://localhost:8000',{forceNew: true});
	});
    it('should open chat application', function() {
        return browserB.init().url('https://localhost:8000/sign_in?url=%2FMentor');
        //return browserB.init().url('http://webdriver.io');
    });

    it('should fill email and password and login as mentor', function() {
        return browserB.setValue('#email', 'jj')
                        .setValue('#password', '123')
                        .click('.btn').pause(1000)
                        .getTitle().should.eventually.equal('Mentor Toolbar');

    });

    it('ninja should request', function() {
			ninjaSocket.emit('requestHelp');
			return browserB.getHTML('#helpQueue .btn',false).should.eventually.to.exist;
	});

    it('mentor should answer', function() {
			return browserB.click('#helpQueue .btn').pause(1000)
                           .getHTML('#headingThree h4 a',false).should.eventually.equal('Chats');
	});

    it('should add video', function() {
            ninjaSocket.emit('test_addVideo');
			return browserB.getHTML('#ninjaScreen',false).should.eventually.to.exist
	});

    it('should take screenshot', function() {

            return browserB.pause(3000)
                           .click('#takescreenShot').pause(1000)
                           .getElementSize('#myCanvas','width').should.eventually.to.be.above(50);
	});

    it('should highlight screenshot', function() {
        var original_Canvas;

             browserB.getAttribute('#myCanvas','textContent').then(function(oc){
                 original_Canvas=oc;
             });
             browserB.pause(3000)
                     .moveToObject('#myCanvas',80,80)
                     .buttonDown().then(function(){
                         browserB.buttonPress()
                                 .moveToObject('#myCanvas',180,160)
                      })
                      .buttonUp()
                      .pause(1000)

         return browserB.getAttribute('#myCanvas','textContent').should.eventually.not.equal(original_Canvas);
	});

    it('should clear drawings on screenshot', function() {

        var highlighted_Canvas;
        var cleared_Canvas;
        browserB.getAttribute('#myCanvas','textContent').then(function(hc){
              highlighted_Canvas= hc;
              browserB.pause(1000)
                 .click('#clearCanvas')
                 .pause(1000);

              browserB.getAttribute('#myCanvas','textContent').then(function(cc){
                  cc.should.equal(highlighted_Canvas);
                  console.log(highlighted_Canvas)
              });
         });
         return browserB.pause(1000)
	});

    it('should end the session', function() {
        return browserB.pause(2000).end();
    });

});
<commit_msg>11/3/16<commit_after>/**
 * Multiremote example
 * To run this script you need to have Mocha installed globally on your system.
 * If not try to run: $ npm install -g mocha
 *
 * To execute it just run it as a spec with a fair amount of timeout:
 * $ mocha -t 9999999 examples/webdriverio.multiremote.chat.js
 */
var io = require('socket.io-client');
var ninjaSocket;
var WebdriverIO = require('webdriverio'),
    matrix = WebdriverIO.multiremote({
       browserB: { desiredCapabilities: { browserName: 'chrome' } },
       /* browserB: {
            desiredCapabilities:
            {
                browserName: 'phantomjs',
                //'phantomjs.binary.path': require('../node_modules/phantomjs').path,
                'phantomjs.cli.args': [
                '--ignore-ssl-errors=true',
                '--ssl-protocol=any', // tlsv1
                '--web-security=false',
                '--load-images=false',
          //'--debug=false',
          //'--webdriver-logfile=webdriver.log',
          //'--webdriver-loglevel=DEBUG',
                ],
                logLevel: 'silent'
            }
        }
        */
    }),
  //  browserA = matrix.select('browserA'),
    browserB = matrix.select('browserB');

var should = require('should');
    var chai = require('chai');
    var chaiAsPromised = require('chai-as-promised');

    chai.use(chaiAsPromised);
    expect = chai.expect;
    chai.Should();
    chaiAsPromised.transferPromiseness = browserB.transferPromiseness;

/**
 * Multiremote example
 * To run this script you need to have Mocha installed globally on your system.
 * If not try to run: $ npm install -g mocha
 *
 * To execute it just run it as a spec with a fair amount of timeout:
 * $ mocha -t 9999999 examples/webdriverio.multiremote.chat.js
 */

describe('multiremote', function() {

    //this.timeout = 99999999;
    before(function() {

		ninjaSocket = io('https://localhost:8000',{forceNew: true});
	});
    it('should open chat application', function() {
        return browserB.init().url('https://localhost:8000/sign_in?url=%2FMentor');
        //return browserB.init().url('http://webdriver.io');
    });

    it('should fill email and password and login as mentor', function() {
        return browserB.setValue('#email', 'jj')
                        .setValue('#password', '123')
                        .click('.btn').pause(1000)
                        .getTitle().should.eventually.equal('Mentor Toolbar');

    });

    it('ninja should request', function() {
			ninjaSocket.emit('requestHelp');
			return browserB.getHTML('#helpQueue .btn',false).should.eventually.to.exist;
	});

    it('mentor should answer', function() {
			return browserB.click('#helpQueue .btn').pause(1000)
                           .getHTML('#headingThree h4 a',false).should.eventually.equal('Chats');
	});

    it('should add video', function() {
            ninjaSocket.emit('test_addVideo');
			return browserB.getHTML('#ninjaScreen',false).should.eventually.to.exist
	});

    it('should take screenshot', function() {

            return browserB.pause(3000)
                           .click('#takescreenShot').pause(1000)
                           .getElementSize('#myCanvas','width').should.eventually.to.be.above(50);
	});

    it('should highlight screenshot', function() {
        var original_Canvas;

             browserB.getAttribute('#myCanvas','textContent').then(function(oc){
                 original_Canvas=oc;
             });
             browserB.pause(3000)
                     .moveToObject('#myCanvas',80,80)
                     .buttonDown().then(function(){
                         browserB.buttonPress()
                                 .moveToObject('#myCanvas',180,160)
                      })
                      .buttonUp()
                      .pause(1000)

         return browserB.getAttribute('#myCanvas','textContent').should.eventually.not.equal(original_Canvas);
	});

    it('should clear drawings on screenshot', function() {

        var highlighted_Canvas;
        var cleared_Canvas;
        browserB.getAttribute('#myCanvas','textContent').then(function(hc){
              highlighted_Canvas= hc;
              browserB.pause(1000)
                 .click('#clearCanvas')
                 .pause(1000);

              browserB.getAttribute('#myCanvas','textContent').then(function(cc){
                  cc.should.equal(highlighted_Canvas);
                  //console.log(highlighted_Canvas)
              });
         });
         return browserB.pause(1000)
	});

    it('should end the session', function() {
        return browserB.pause(2000).end();
    });

});
<|endoftext|>


<commit_before>/*
Simple OpenID Plugin
http://code.google.com/p/openid-selector/

This code is licenced under the New BSD License.
*/

var providers_large = {
  google: {
    name: 'Google',
    url: 'https://www.google.com/accounts/o8/id'
  },
  yahoo: {
    name: 'Yahoo',
    url: 'http://yahoo.com/'
  },
  aol: {
    name: 'AOL',
    label: 'Enter your AOL screenname.',
    url: 'http://openid.aol.com/{username}/'
  },
  openid: {
    name: 'OpenID',
    label: 'Enter your OpenID.',
    url: null
  }
};
var providers_small = {
  myopenid: {
    name: 'MyOpenID',
    label: 'Enter your MyOpenID username.',
    url: 'http://{username}.myopenid.com/'
  },
  livejournal: {
    name: 'LiveJournal',
    label: 'Enter your Livejournal username.',
    url: 'http://{username}.livejournal.com/'
  },
  flickr: {
    name: 'Flickr',
    label: 'Enter your Flickr username.',
    url: 'http://flickr.com/{username}/'
  },
  technorati: {
    name: 'Technorati',
    label: 'Enter your Technorati username.',
    url: 'http://technorati.com/people/technorati/{username}/'
  },
  wordpress: {
    name: 'Wordpress',
    label: 'Enter your Wordpress.com username.',
    url: 'http://{username}.wordpress.com/'
  },
  blogger: {
    name: 'Blogger',
    label: 'Your Blogger account',
    url: 'http://{username}.blogspot.com/'
  },
  verisign: {
    name: 'Verisign',
    label: 'Your Verisign username',
    url: 'http://{username}.pip.verisignlabs.com/'
  },
  vidoop: {
    name: 'Vidoop',
    label: 'Your Vidoop username',
    url: 'http://{username}.myvidoop.com/'
  },
  verisign: {
    name: 'Verisign',
    label: 'Your Verisign username',
    url: 'http://{username}.pip.verisignlabs.com/'
  },
  claimid: {
    name: 'ClaimID',
    label: 'Your ClaimID username',
    url: 'http://claimid.com/{username}'
  }
};
var providers = $.extend({}, providers_large, providers_small);

var openid = {

  cookie_expires: 6*30,	// 6 months.
  cookie_name: 'openid_provider',
  cookie_path: '/',

  img_path: '/media/images/',

  input_id: null,
  provider_url: null,
  provider_name: null,

  init: function(input_id) {

    var openid_btns = $('#openid_btns');

    this.input_id = input_id;

    $("#"+ input_id).type = "hidden"

    $('#openid_choice').show();
    $('#openid_input_area').empty();

    // add box for each provider
    for (id in providers_large) {

      openid_btns.append(this.getBoxHTML(providers_large[id], 'large', '.gif'));
    }
    if (providers_small) {
      openid_btns.append('
');

      for (id in providers_small) {

        openid_btns.append(this.getBoxHTML(providers_small[id], 'small', '.ico'));
      }
    }

    $('#openid_form').submit(this.submit);

    var self = this;
    $('.openidProvider').bind("click", function(e) {
      self.signin(e.target.id);
      return false;
    });

    var box_id = this.readCookie();
    if (box_id) {
      this.signin(box_id, true);
    }

  },
  getBoxHTML: function(provider, box_size, image_ext) {

    var box_id = provider["name"].toLowerCase();
    return '';

  },

  /* Provider image click */
  signin: function(box_id, onload) {

    var provider = providers[box_id];
    if (! provider) {
      return;
    }

    this.highlight(box_id);
    this.setCookie(box_id);

    // prompt user for input?
    if (provider['label']) {

      this.useInputBox(provider);
      this.provider_url = provider['url'];
      this.provider_name = provider['name'];

    } else {

      this.setOpenIdUrl(provider['url']);
      if (! onload) {
        $('#openid_form').submit();
      }
    }
  },
  /* Sign-in button click */
  submit: function() {
    var url = openid.provider_url;
    if (url) {
      url = url.replace('{username}', $('#openid_username').val());
      openid.setOpenIdUrl(url);
    }
    return true;
  },

  setOpenIdUrl: function (url) {
    var hidden = $('#'+this.input_id);
    if (hidden.length > 0) {
      hidden.val(url);
    } else {
      $('#openid_form').append('<input type="hidden" id="' + this.input_id + '" name="openid_url" value="'+url+'"/>');
    }

  },
  highlight: function (box_id) {

    // remove previous highlight.
    var highlight = $('#openid_highlight');
    if (highlight) {
      highlight.replaceWith($('#openid_highlight a')[0]);
    }
    // add new highlight.
    $('.'+box_id).wrap('

');
  },
  setCookie: function (value) {

    var date = new Date();
    date.setTime(date.getTime()+(this.cookie_expires*24*60*60*1000));
    var expires = "; expires="+date.toGMTString();

    document.cookie = this.cookie_name+"="+value+expires+"; path=" + this.cookie_path;
  },
  readCookie: function () {
    var nameEQ = this.cookie_name + "=";
    var ca = document.cookie.split(';');
    for(var i=0;i < ca.length;i++) {
      var c = ca[i];
      while (c.charAt(0)==' ') c = c.substring(1,c.length);
      if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
    }
    return null;
  },
  useInputBox: function (provider) {

    var input_area = $('#openid_input_area');

    var html = '';
    var id = 'openid_username';
    var name = id;
    var value = '';
    var label = provider['label'];
    var style = '';

    if (label) {
      html = '
' + label + '
';
    }
    if (provider['name'] == 'OpenID') {
      id = this.input_id;
      name = "openid_url";
      value = 'http://';
      style = 'background:#FFF url('+this.img_path+'openid-inputicon.gif) no-repeat scroll 0 50%; padding-left:18px;';
    }
    html += '<input id="'+id+'" type="text" style="'+style+'" name="'+name+'" value="'+value+'" />' +
    '<input id="openid_submit" type="submit" value="Sign-In"/>';

    input_area.empty();
    input_area.append(html);

    $('#'+id).focus();
  }
};
<commit_msg>make sure we use the right provider<commit_after>/*
Simple OpenID Plugin
http://code.google.com/p/openid-selector/

This code is licenced under the New BSD License.
*/

var providers_large = {
  google: {
    name: 'Google',
    url: 'https://www.google.com/accounts/o8/id'
  },
  yahoo: {
    name: 'Yahoo',
    url: 'http://yahoo.com/'
  },
  aol: {
    name: 'AOL',
    label: 'Enter your AOL screenname.',
    url: 'http://openid.aol.com/{username}/'
  },
  openid: {
    name: 'OpenID',
    label: 'Enter your OpenID.',
    url: null
  }
};
var providers_small = {
  myopenid: {
    name: 'MyOpenID',
    label: 'Enter your MyOpenID username.',
    url: 'http://{username}.myopenid.com/'
  },
  livejournal: {
    name: 'LiveJournal',
    label: 'Enter your Livejournal username.',
    url: 'http://{username}.livejournal.com/'
  },
  flickr: {
    name: 'Flickr',
    label: 'Enter your Flickr username.',
    url: 'http://flickr.com/{username}/'
  },
  technorati: {
    name: 'Technorati',
    label: 'Enter your Technorati username.',
    url: 'http://technorati.com/people/technorati/{username}/'
  },
  wordpress: {
    name: 'Wordpress',
    label: 'Enter your Wordpress.com username.',
    url: 'http://{username}.wordpress.com/'
  },
  blogger: {
    name: 'Blogger',
    label: 'Your Blogger account',
    url: 'http://{username}.blogspot.com/'
  },
  verisign: {
    name: 'Verisign',
    label: 'Your Verisign username',
    url: 'http://{username}.pip.verisignlabs.com/'
  },
  vidoop: {
    name: 'Vidoop',
    label: 'Your Vidoop username',
    url: 'http://{username}.myvidoop.com/'
  },
  verisign: {
    name: 'Verisign',
    label: 'Your Verisign username',
    url: 'http://{username}.pip.verisignlabs.com/'
  },
  claimid: {
    name: 'ClaimID',
    label: 'Your ClaimID username',
    url: 'http://claimid.com/{username}'
  }
};
var providers = $.extend({}, providers_large, providers_small);

var openid = {

  cookie_expires: 6*30,	// 6 months.
  cookie_name: 'openid_provider',
  cookie_path: '/',

  img_path: '/media/images/',

  input_id: null,
  provider_url: null,
  provider_name: null,

  init: function(input_id) {

    var openid_btns = $('#openid_btns');

    this.input_id = input_id;

    $("#"+ input_id).type = "hidden"

    $('#openid_choice').show();
    $('#openid_input_area').empty();

    // add box for each provider
    for (id in providers_large) {

      openid_btns.append(this.getBoxHTML(providers_large[id], 'large', '.gif'));
    }
    if (providers_small) {
      openid_btns.append('
');

      for (id in providers_small) {

        openid_btns.append(this.getBoxHTML(providers_small[id], 'small', '.ico'));
      }
    }

    $('#openid_form').submit(this.submit);

    var self = this;
    $('.openidProvider').bind("click", function(e) {
      self.signin(e.target.id);
      return false;
    });

    var box_id = this.readCookie();
    if (box_id) {
      this.signin(box_id, true);
    }

  },
  getBoxHTML: function(provider, box_size, image_ext) {

    var box_id = provider["name"].toLowerCase();
    return '';

  },

  /* Provider image click */
  signin: function(box_id, onload) {

    var provider = providers[box_id];
    if (! provider) {
      return;
    }

    this.highlight(box_id);
    this.setCookie(box_id);

    // prompt user for input?
    if (provider['label']) {

      this.useInputBox(provider);
      this.provider_url = provider['url'];
      this.provider_name = provider['name'];

    } else {
      this.provider_url = null;
      this.setOpenIdUrl(provider['url']);
      if (! onload) {
        $('#openid_form').submit();
      }
    }
  },
  /* Sign-in button click */
  submit: function() {
    var url = openid.provider_url;
    if (url) {
      url = url.replace('{username}', $('#openid_username').val());
      openid.setOpenIdUrl(url);
    }
    return true;
  },

  setOpenIdUrl: function (url) {
    var hidden = $('#'+this.input_id);
    if (hidden.length > 0) {
      hidden.val(url);
    } else {
      $('#openid_form').append('<input type="hidden" id="' + this.input_id + '" name="openid_url" value="'+url+'"/>');
    }

  },
  highlight: function (box_id) {

    // remove previous highlight.
    var highlight = $('#openid_highlight');
    if (highlight) {
      highlight.replaceWith($('#openid_highlight a')[0]);
    }
    // add new highlight.
    $('.'+box_id).wrap('

');
  },
  setCookie: function (value) {

    var date = new Date();
    date.setTime(date.getTime()+(this.cookie_expires*24*60*60*1000));
    var expires = "; expires="+date.toGMTString();

    document.cookie = this.cookie_name+"="+value+expires+"; path=" + this.cookie_path;
  },
  readCookie: function () {
    var nameEQ = this.cookie_name + "=";
    var ca = document.cookie.split(';');
    for(var i=0;i < ca.length;i++) {
      var c = ca[i];
      while (c.charAt(0)==' ') c = c.substring(1,c.length);
      if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
    }
    return null;
  },
  useInputBox: function (provider) {

    var input_area = $('#openid_input_area');

    var html = '';
    var id = 'openid_username';
    var name = id;
    var value = '';
    var label = provider['label'];
    var style = '';

    if (label) {
      html = '
' + label + '
';
    }
    if (provider['name'] == 'OpenID') {
      id = this.input_id;
      name = "openid_url";
      value = 'http://';
      style = 'background:#FFF url('+this.img_path+'openid-inputicon.gif) no-repeat scroll 0 50%; padding-left:18px;';
    }
    html += '<input id="'+id+'" type="text" style="'+style+'" name="'+name+'" value="'+value+'" />' +
    '<input id="openid_submit" type="submit" value="Sign-In"/>';

    input_area.empty();
    input_area.append(html);

    $('#'+id).focus();
  }
};
<|endoftext|>


<commit_before>/**
 * Test dependencies.
 */
var should = require('should'),
  express = require('express'),
  Coral = require('../lib/coral');

xdescribe('coral', function() {

  var app, coral;

  beforeEach(function() {
    app = express();
    coral = new Coral(app);
  });

  it.only('route - must create proper routes', function() {

    coral.route({
      path: 'localhost/user',
      model: 'User'
    });

    var get = app._router.get;
    get.should.have.length(2);

    //find
    get[0].path.should.equal('localhost/user');
    get[0].method.should.equal('get');

    //findById
    get[1].path.should.equal('localhost/user/:idAttribute');
    get[1].method.should.equal('get');

    var post = app.routes.post;
    post.should.have.length(1);
    post[0].path.should.equal('localhost/user');
    post[0].method.should.equal('post');

    var put = app.routes.put;
    put.should.have.length(1);
    put[0].path.should.equal('localhost/user/:idAttribute');
    put[0].method.should.equal('put');

    var del = app.routes.delete;
    del.should.have.length(1);
    del[0].path.should.equal('localhost/user/:idAttribute');
    del[0].method.should.equal('delete');

  });

  it('route with methods get, post, put - should create specific routes', function() {

    coral.route({
      path: 'localhost/article',
      model: 'Article',
      methods: ['get', 'post', 'put']
    });

    var get = app.routes.get;
    get.should.have.length(2);

    //find
    get[0].path.should.equal('localhost/article');
    get[0].method.should.equal('get');

    //findById
    get[1].path.should.equal('localhost/article/:idAttribute');
    get[1].method.should.equal('get');

    var post = app.routes.post;
    post.should.have.length(1);
    post[0].path.should.equal('localhost/article');
    post[0].method.should.equal('post');

    var put = app.routes.put;
    put.should.have.length(1);
    put[0].path.should.equal('localhost/article/:idAttribute');
    put[0].method.should.equal('put');

    var del = app.routes.delete;
    should.not.exist(del);

  });

  it('route with methods del - should create specific del routes', function() {

    coral.route({
      path: 'localhost/admin/user',
      model: 'User',
      methods: ['del']
    });

    var get = app.routes.get;
    should.not.exist(get);

    var post = app.routes.post;
    should.not.exist(post);

    var put = app.routes.put;
    should.not.exist(put);

    var del = app.routes.delete;
    del.should.have.length(1);
    del[0].path.should.equal('localhost/admin/user/:idAttribute');
    del[0].method.should.equal('delete');

  });

});<commit_msg>Modified ignored test<commit_after>/**
 * Test dependencies.
 */
var should = require('should'),
  express = require('express'),
  Coral = require('../lib/coral');

xdescribe('coral', function() {

  var app, coral;

  beforeEach(function() {
    app = express();
    coral = new Coral(app);
  });

  it('route - must create proper routes', function() {

    coral.route({
      path: 'localhost/user',
      model: 'User'
    });

    var get = app._router.get;
    get.should.have.length(2);

    //find
    get[0].path.should.equal('localhost/user');
    get[0].method.should.equal('get');

    //findById
    get[1].path.should.equal('localhost/user/:idAttribute');
    get[1].method.should.equal('get');

    var post = app.routes.post;
    post.should.have.length(1);
    post[0].path.should.equal('localhost/user');
    post[0].method.should.equal('post');

    var put = app.routes.put;
    put.should.have.length(1);
    put[0].path.should.equal('localhost/user/:idAttribute');
    put[0].method.should.equal('put');

    var del = app.routes.delete;
    del.should.have.length(1);
    del[0].path.should.equal('localhost/user/:idAttribute');
    del[0].method.should.equal('delete');

  });

  it('route with methods get, post, put - should create specific routes', function() {

    coral.route({
      path: 'localhost/article',
      model: 'Article',
      methods: ['get', 'post', 'put']
    });

    var get = app.routes.get;
    get.should.have.length(2);

    //find
    get[0].path.should.equal('localhost/article');
    get[0].method.should.equal('get');

    //findById
    get[1].path.should.equal('localhost/article/:idAttribute');
    get[1].method.should.equal('get');

    var post = app.routes.post;
    post.should.have.length(1);
    post[0].path.should.equal('localhost/article');
    post[0].method.should.equal('post');

    var put = app.routes.put;
    put.should.have.length(1);
    put[0].path.should.equal('localhost/article/:idAttribute');
    put[0].method.should.equal('put');

    var del = app.routes.delete;
    should.not.exist(del);

  });

  it('route with methods del - should create specific del routes', function() {

    coral.route({
      path: 'localhost/admin/user',
      model: 'User',
      methods: ['del']
    });

    var get = app.routes.get;
    should.not.exist(get);

    var post = app.routes.post;
    should.not.exist(post);

    var put = app.routes.put;
    should.not.exist(put);

    var del = app.routes.delete;
    del.should.have.length(1);
    del[0].path.should.equal('localhost/admin/user/:idAttribute');
    del[0].method.should.equal('delete');

  });

});<|endoftext|>


<commit_before>import React from 'react';

import {
  ScrollView,
  StyleSheet,
} from 'react-native';

import Row from './Row';

const styles = StyleSheet.create({
  container: {
    backgroundColor: '#4A637D',
    flex: 1,
    padding: 10,
  },
});

export default () => (
  <ScrollView
    style={styles.container}
  >
    <Row zIndex={100} />
    <Row zIndex={90} />
    <Row zIndex={80} />
    <Row zIndex={70} />
  </ScrollView>
);
<commit_msg>prettify example app<commit_after>import React from 'react';

import {
  Platform,
  ScrollView,
  StatusBar,
  StyleSheet,
  View,
} from 'react-native';

import Row from './Row';

const STATUSBAR_HEIGHT = Platform.OS === 'ios' ? 20 : 0;

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  scrollView: {
    backgroundColor: '#4A637D',
    flex: 1,
    padding: 10,
    paddingTop: STATUSBAR_HEIGHT,
  },
});

export default () => (
  <View style={styles.container}>
    <StatusBar
      barStyle="light-content"
    />
    <ScrollView
      style={styles.scrollView}
    >
      <Row zIndex={100} />
      <Row zIndex={90} />
      <Row zIndex={80} />
      <Row zIndex={70} />
    </ScrollView>
  </View>
);
<|endoftext|>


<commit_before>window.Fact = Backbone.Model.extend({
  getOwnContainingChannels: function() {
    var containingChannels = this.get('containing_channel_ids');
    var ret = [];

    currentUser.channels.each(function(ch) {
      if ( _.indexOf(containingChannels, ch.id ) !== -1 ) {
        ret.push(ch);
      }
    });

    return ret;
  },

  specialUrl: function(forChannel) {
    if ( forChannel ) {
      return this.collection.url() + '/' + this.get('id');
    } else {
      return '/facts/' + this.get('id');
    }
  },

  sync: function(method, model, options) {
    options = options || {};
    var forChannel = options.forChannel;

    if ( forChannel === undefined ) {
      forChannel = true;
    }

    options.url = model.specialUrl(forChannel);

    Backbone.sync(method, model, options);
  }
});<commit_msg>Removed whitespace :D & renamed specialUrl :)<commit_after>window.Fact = Backbone.Model.extend({
  getOwnContainingChannels: function() {
    var containingChannels = this.get('containing_channel_ids');
    var ret = [];

    currentUser.channels.each(function(ch) {
      if ( _.indexOf(containingChannels, ch.id ) !== -1 ) {
        ret.push(ch);
      }
    });

    return ret;
  },

  dependentUrl: function(forChannel) {
    if ( forChannel ) {
      return this.collection.url() + '/' + this.get('id');
    } else {
      return '/facts/' + this.get('id');
    }
  },

  sync: function(method, model, options) {
    options = options || {};
    var forChannel = options.forChannel;

    if ( forChannel === undefined ) {
      forChannel = true;
    }

    options.url = model.dependentUrl(forChannel);

    Backbone.sync(method, model, options);
  }
});<|endoftext|>


<commit_before>function CustomFileBrowser(field_name, url, type, win) {

    var cmsURL = "/admin/filebrowser/browse/?pop=2";
    cmsURL = cmsURL + "&type=" + type;

    tinyMCE.activeEditor.windowManager.open({
        file: cmsURL,
        width: 820,  // Your dimensions may differ - toy around with them!
        height: 500,
        resizable: "yes",
        scrollbars: "yes",
        inline: "no",  // This parameter only has an effect if you use the inlinepopups plugin!
        close_previous: "no"
    }, {
        window: win,
        input: field_name,
        editor_id: tinyMCE.selectedInstance.editorId
    });
    return false;
}

tinyMCE.init({
    mode: "textareas",
    theme: "advanced",
    language: "en",
    skin: "o2k7",
    browsers: "gecko",
    dialog_type: "modal",
    object_resizing: true,
    cleanup_on_startup: true,
    forced_root_block: "p",
    remove_trailing_nbsp: true,
    theme_advanced_toolbar_location: "top",
    theme_advanced_toolbar_align: "left",
    theme_advanced_statusbar_location: "none",
    theme_advanced_buttons1: "formatselect,styleselect,bold,italic,underline,bullist,numlist,undo,redo,link,unlink,image,code,template,visualchars,fullscreen,pasteword,media,search,replace,charmap",
    theme_advanced_buttons2: "",
    theme_advanced_buttons3: "",
    theme_advanced_path: false,
    theme_advanced_blockformats: "p,h2,h3,h4,div,code,pre",
    theme_advanced_styles: "[all] clearfix=clearfix;[p] summary=summary;[div] code=code;[img] img_left=img_left;[img] img_left_nospacetop=img_left_nospacetop;[img] img_right=img_right;[img] img_right_nospacetop=img_right_nospacetop;[img] img_block=img_block;[img] img_block_nospacetop=img_block_nospacetop;[div] column span-2=column span-2;[div] column span-4=column span-4;[div] column span-8=column span-8",
    width: '700',
    height: '200',
    plugins: "advimage,advlink,fullscreen,visualchars,paste,media,template,searchreplace",
    advimage_styles: "Linksbündig neben Text=img_left;Rechtsbündig neben Text=img_right;Eigener Block=img_block",
    advlink_styles: "internal (sehmaschine.net)=internal;external (link to an external site)=external",
    advimage_update_dimensions_onchange: true,
    file_browser_callback: "CustomFileBrowser",
    relative_urls: false,
    valid_elements : "" +
    "-p," +
    "a[href|target=_blank|class]," +
    "-strong/-b," +
    "-em/-i," +
    "-u," +
    "-ol," +
    "-ul," +
    "-li," +
    "br," +
    "img[class|src|alt=|width|height]," +
    "-h2,-h3,-h4," +
    "-pre," +
    "-code," +
    "-div",
    extended_valid_elements: "" +
    "a[name|class|href|target|title|onclick]," +
    "img[class|src|border=0|alt|title|hspace|vspace|width|height|align|onmouseover|onmouseout|name]," +
    "br[clearfix]," +
    "-p[class<clearfix?summary?code]," +
    "h2[class<clearfix],h3[class<clearfix],h4[class<clearfix]," +
    "ul[class<clearfix],ol[class<clearfix]," +
    "div[class],"
});

<commit_msg>wrong update, last change reverted<commit_after>function CustomFileBrowser(field_name, url, type, win) {

    var cmsURL = "/admin/filebrowser/?pop=2";
    cmsURL = cmsURL + "&type=" + type;

    tinyMCE.activeEditor.windowManager.open({
        file: cmsURL,
        width: 820,  // Your dimensions may differ - toy around with them!
        height: 500,
        resizable: "yes",
        scrollbars: "yes",
        inline: "no",  // This parameter only has an effect if you use the inlinepopups plugin!
        close_previous: "no"
    }, {
        window: win,
        input: field_name,
        editor_id: tinyMCE.selectedInstance.editorId
    });
    return false;
}

tinyMCE.init({
    mode: "textareas",
    theme: "advanced",
    language: "en",
    skin: "o2k7",
    browsers: "gecko",
    dialog_type: "modal",
    object_resizing: true,
    cleanup_on_startup: true,
    forced_root_block: "p",
    remove_trailing_nbsp: true,
    theme_advanced_toolbar_location: "top",
    theme_advanced_toolbar_align: "left",
    theme_advanced_statusbar_location: "none",
    theme_advanced_buttons1: "formatselect,styleselect,bold,italic,underline,bullist,numlist,undo,redo,link,unlink,image,code,template,visualchars,fullscreen,pasteword,media,search,replace,charmap",
    theme_advanced_buttons2: "",
    theme_advanced_buttons3: "",
    theme_advanced_path: false,
    theme_advanced_blockformats: "p,h2,h3,h4,div,code,pre",
    theme_advanced_styles: "[all] clearfix=clearfix;[p] summary=summary;[div] code=code;[img] img_left=img_left;[img] img_left_nospacetop=img_left_nospacetop;[img] img_right=img_right;[img] img_right_nospacetop=img_right_nospacetop;[img] img_block=img_block;[img] img_block_nospacetop=img_block_nospacetop;[div] column span-2=column span-2;[div] column span-4=column span-4;[div] column span-8=column span-8",
    width: '700',
    height: '200',
    plugins: "advimage,advlink,fullscreen,visualchars,paste,media,template,searchreplace",
    advimage_styles: "Linksbündig neben Text=img_left;Rechtsbündig neben Text=img_right;Eigener Block=img_block",
    advlink_styles: "internal (sehmaschine.net)=internal;external (link to an external site)=external",
    advimage_update_dimensions_onchange: true,
    file_browser_callback: "CustomFileBrowser",
    relative_urls: false,
    valid_elements : "" +
    "-p," +
    "a[href|target=_blank|class]," +
    "-strong/-b," +
    "-em/-i," +
    "-u," +
    "-ol," +
    "-ul," +
    "-li," +
    "br," +
    "img[class|src|alt=|width|height]," +
    "-h2,-h3,-h4," +
    "-pre," +
    "-code," +
    "-div",
    extended_valid_elements: "" +
    "a[name|class|href|target|title|onclick]," +
    "img[class|src|border=0|alt|title|hspace|vspace|width|height|align|onmouseover|onmouseout|name]," +
    "br[clearfix]," +
    "-p[class<clearfix?summary?code]," +
    "h2[class<clearfix],h3[class<clearfix],h4[class<clearfix]," +
    "ul[class<clearfix],ol[class<clearfix]," +
    "div[class],"
});

<|endoftext|>


<commit_before>/*
  Convert the contents of an HTML DOM element into a
  styled text document for an easier reading
  experience or to bring out certain features in the
  document. You can create your own README document.

  if (redistribute == true) {
    return credit;
  }

  --------------------------------------------------

  @DocTyp
  @author: Alexander Hovy
  @param:
    exports - Contains all the public variables and functions of the module.
    element - The HTML DOM element that will be Docified.
    style - You can optionally set the style to Dark or Light.
    doc - The elements text that will be Docified.
*/
var DocTyp = (function(exports) {
  /*============================================================
  ===========================Variable===========================
  ============================================================*/
  var prefix = 'doctyp-';
  var header = {
    'header1': {pattern: /\#/gm, regex: /^\#{1}(?!\#)(.*?)$/gm},
    'header2': {pattern: /\#/gm, regex: /^\#{2}(?!\#)(.*?)$/gm},
    'header3': {pattern: /\#/gm, regex: /^\#{3}(?!\#)(.*?)$/gm},
    'header4': {pattern: /\#/gm, regex: /^\#{4,}(.*?)$/gm}
  };
  var style = {
    'bold': {pattern: /\*/gm, regex: /\*{1,}(.*?)\*{1,}/gm},
    'italic': {pattern: /\//gm, regex: /\/{1,}(.*?)\/{1,}/gm},
    'underline': {pattern: /\_/gm, regex: /\_{1,}(.*?)\_{1,}/gm},
    'strike': {pattern: /\~/gm, regex: /\~{1,}(.*?)\~{1,}/gm},
    'highlight': {pattern: /\=/gm, regex: /\={1,}(.*?)\={1,}/gm}
  };
  var rule = {
    'header1': {pattern: /\#/gm, regex: /^\#{1}(?!\#)(.*?)$/gm},
    'header2': {pattern: /\#/gm, regex: /^\#{2}(?!\#)(.*?)$/gm},
    'header3': {pattern: /\#/gm, regex: /^\#{3}(?!\#)(.*?)$/gm},
    'header4': {pattern: /\#/gm, regex: /^\#{4,}(.*?)$/gm}
  };
  var block = {
    'header1': {pattern: /\#/gm, regex: /^\#{1}(?!\#)(.*?)$/gm},
    'header2': {pattern: /\#/gm, regex: /^\#{2}(?!\#)(.*?)$/gm},
    'header3': {pattern: /\#/gm, regex: /^\#{3}(?!\#)(.*?)$/gm},
    'header4': {pattern: /\#/gm, regex: /^\#{4,}(.*?)$/gm}
  };
  var list = {
    'header1': {pattern: /\#/gm, regex: /^\#{1}(?!\#)(.*?)$/gm},
    'header2': {pattern: /\#/gm, regex: /^\#{2}(?!\#)(.*?)$/gm},
    'header3': {pattern: /\#/gm, regex: /^\#{3}(?!\#)(.*?)$/gm},
    'header4': {pattern: /\#/gm, regex: /^\#{4,}(.*?)$/gm}
  };
  var link = {
    'header1': {pattern: /\#/gm, regex: /^\#{1}(?!\#)(.*?)$/gm},
    'header2': {pattern: /\#/gm, regex: /^\#{2}(?!\#)(.*?)$/gm},
    'header3': {pattern: /\#/gm, regex: /^\#{3}(?!\#)(.*?)$/gm},
    'header4': {pattern: /\#/gm, regex: /^\#{4,}(.*?)$/gm}
  };

  /*============================================================
  ============================Private===========================
  ============================================================*/
  function LoadStyle(style) {
    var link = document.createElement('link');
    link.type = 'text/css';
    link.rel = 'stylesheet';
    link.href = 'Style/' + style.toLowerCase() + '.css';
    link.media = 'none';
    link.onload = function() {
      if (media != 'all') {
        link.media = 'all';
      }
    };
    document.getElementsByTagName('head')[0].appendChild(link);
  }
  //Processing
  function Header(doc) {
    for (key in header) {
      doc = doc.replace(header[key].regex, function(match) {
        var temp = Prepare(match).replace(header[key].pattern, '');
        return '' + temp + '';
      });
    }
    return doc;
  }
  function Style(doc) {
    for (key in style) {
      doc = doc.replace(style[key].regex, function(match) {
        var temp = Prepare(match).replace(style[key].pattern, '');
        return '' + temp + '';
      });
    }
    return doc;
  }
  function Rule(doc) {
    return doc;
  }
  function Block(doc) {
    return doc;
  }
  function List(doc) {
    return doc;
  }
  function Link(doc) {
    return doc;
  }
  //Cleaning
  function Prepare(doc) {
    return doc.replace(/\<(\/)?span(.*?)\>/gm, '');
  }
  function Clean(doc) {
    return doc.replace(/\n/gm, '
');
  }

  /*============================================================
  ============================Public============================
  ============================================================*/
  exports.Docify = function(element, style) {
    //Check if element is an element
    if (element.nodeType && element.nodeType == 1) {
      //Check if user is using their own style
      if (style !== undefined) {
        LoadStyle(style);
      }
      //Cater for older browsers
      var doc = element.innerText ? element.innerText : element.textContent;
      //Processing
      doc = Header(doc);
      doc = Style(doc);
      doc = Rule(doc);
      doc = Block(doc);
      doc = List(doc);
      doc = Clean(doc);
      //Replace text with new text
      element.innerHTML = doc;
    } else {
      throw('The element is not defined or is not a DOM element.');
    }
  };

  /*============================================================
  ============================Export============================
  ============================================================*/
  return exports;
})({});
<commit_msg>Update DocTyp.js<commit_after>/*
  Convert the contents of an HTML DOM element into a
  styled text document for an easier reading
  experience or to bring out certain features in the
  document. You can create your own README document.

  if (redistribute == true) {
    return credit;
  }

  --------------------------------------------------

  @DocTyp
  @author: Alexander Hovy
  @param:
    exports - Contains all the public variables and functions of the module.
    element - The HTML DOM element that will be Docified.
    style - You can optionally set the style to Dark or Light.
    doc - The elements text that will be Docified.
*/
var DocTyp = (function(exports) {
  /*============================================================
  ===========================Variable===========================
  ============================================================*/
  var prefix = 'doctyp-';
  var header = {
    'header1': {pattern: /\#/gm, regex: /^\#{1}(?!\#)(.*?)$/gm},
    'header2': {pattern: /\#/gm, regex: /^\#{2}(?!\#)(.*?)$/gm},
    'header3': {pattern: /\#/gm, regex: /^\#{3}(?!\#)(.*?)$/gm},
    'header4': {pattern: /\#/gm, regex: /^\#{4,}(.*?)$/gm}
  };
  var style = {
    'bold': {pattern: /\*/gm, regex: /\*{1,}(.*?)\*{1,}/gm},
    'italic': {pattern: /\//gm, regex: /\/{1,}(.*?)\/{1,}/gm},
    'underline': {pattern: /\_/gm, regex: /\_{1,}(.*?)\_{1,}/gm},
    'strike': {pattern: /\~/gm, regex: /\~{1,}(.*?)\~{1,}/gm},
    'highlight': {pattern: /\=/gm, regex: /\={1,}(.*?)\={1,}/gm}
  };
  var rule = {
    'rule-solid': {pattern: /\-/gm, regex: /\-{4,}/gm},
    'rule-dash': {pattern: /\_/gm, regex: /\_{4,}/gm}
  };
  var block = {
    'header1': {pattern: /\#/gm, regex: /^\#{1}(?!\#)(.*?)$/gm},
    'header2': {pattern: /\#/gm, regex: /^\#{2}(?!\#)(.*?)$/gm},
    'header3': {pattern: /\#/gm, regex: /^\#{3}(?!\#)(.*?)$/gm},
    'header4': {pattern: /\#/gm, regex: /^\#{4,}(.*?)$/gm}
  };
  var list = {
    'header1': {pattern: /\#/gm, regex: /^\#{1}(?!\#)(.*?)$/gm},
    'header2': {pattern: /\#/gm, regex: /^\#{2}(?!\#)(.*?)$/gm},
    'header3': {pattern: /\#/gm, regex: /^\#{3}(?!\#)(.*?)$/gm},
    'header4': {pattern: /\#/gm, regex: /^\#{4,}(.*?)$/gm}
  };
  var link = {
    'header1': {pattern: /\#/gm, regex: /^\#{1}(?!\#)(.*?)$/gm},
    'header2': {pattern: /\#/gm, regex: /^\#{2}(?!\#)(.*?)$/gm},
    'header3': {pattern: /\#/gm, regex: /^\#{3}(?!\#)(.*?)$/gm},
    'header4': {pattern: /\#/gm, regex: /^\#{4,}(.*?)$/gm}
  };

  /*============================================================
  ============================Private===========================
  ============================================================*/
  function LoadStyle(style) {
    var link = document.createElement('link');
    link.type = 'text/css';
    link.rel = 'stylesheet';
    link.href = 'Style/' + style.toLowerCase() + '.css';
    link.media = 'none';
    link.onload = function() {
      if (media != 'all') {
        link.media = 'all';
      }
    };
    document.getElementsByTagName('head')[0].appendChild(link);
  }
  //Processing
  function Header(doc) {
    for (key in header) {
      doc = doc.replace(header[key].regex, function(match) {
        var temp = Prepare(match).replace(header[key].pattern, '');
        return '' + temp + '';
      });
    }
    return doc;
  }
  function Style(doc) {
    for (key in style) {
      doc = doc.replace(style[key].regex, function(match) {
        var temp = Prepare(match).replace(style[key].pattern, '');
        return '' + temp + '';
      });
    }
    return doc;
  }
  function Rule(doc) {
    for (key in rule) {
      doc = doc.replace(rule[key].regex, function(match) {
        return '
';
      });
    }
    return doc;
  }
  function Block(doc) {
    return doc;
  }
  function List(doc) {
    return doc;
  }
  function Link(doc) {
    return doc;
  }
  //Cleaning
  function Prepare(doc) {
    return doc.replace(/\<(\/)?span(.*?)\>/gm, '');
  }
  function Clean(doc) {
    return doc.replace(/\n/gm, '
');
  }

  /*============================================================
  ============================Public============================
  ============================================================*/
  exports.Docify = function(element, style) {
    //Check if element is an element
    if (element.nodeType && element.nodeType == 1) {
      //Check if user is using their own style
      if (style !== undefined) {
        LoadStyle(style);
      }
      //Cater for older browsers
      var doc = element.innerText ? element.innerText : element.textContent;
      //Processing
      doc = Header(doc);
      doc = Style(doc);
      doc = Rule(doc);
      doc = Block(doc);
      doc = List(doc);
      doc = Clean(doc);
      //Replace text with new text
      element.innerHTML = doc;
    } else {
      throw('The element is not defined or is not a DOM element.');
    }
  };

  /*============================================================
  ============================Export============================
  ============================================================*/
  return exports;
})({});
<|endoftext|>