<commit_before>CodeMirror.defineMode("python", function(conf, parserConf) {
    var ERRORCLASS = 'error';

    function wordRegexp(words) {
        return new RegExp("^((" + words.join(")|(") + "))\\b");
    }

    var singleOperators = new RegExp("^[\\+\\-\\*/%&|\\^~<>!]");
    var singleDelimiters = new RegExp('^[\\(\\)\\[\\]\\{\\}@,:`=;\\.]');
    var doubleOperators = new RegExp("^((==)|(!=)|(<=)|(>=)|(<>)|(<<)|(>>)|(//)|(\\*\\*))");
    var doubleDelimiters = new RegExp("^((\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))");
    var tripleDelimiters = new RegExp("^((//=)|(>>=)|(<<=)|(\\*\\*=))");
    var identifiers = new RegExp("^[_A-Za-z][_A-Za-z0-9]*");

    var wordOperators = wordRegexp(['and', 'or', 'not', 'is', 'in']);
    var commonkeywords = ['as', 'assert', 'break', 'class', 'continue',
                          'def', 'del', 'elif', 'else', 'except', 'finally',
                          'for', 'from', 'global', 'if', 'import',
                          'lambda', 'pass', 'raise', 'return',
                          'try', 'while', 'with', 'yield'];
    var commonBuiltins = ['abs', 'all', 'any', 'bin', 'bool', 'callable', 'classmethod',
                          'compile', 'complex', 'delattr', 'dict', 'dir', 'divmod',
                          'enumerate', 'eval', 'filter', 'float', 'format', 'frozenset',
                          'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id',
                          'input', 'int', 'isinstance', 'issubclass', 'iter', 'len',
                          'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next',
                          'object', 'oct', 'open', 'ord', 'pow', 'property', 'range',
                          'repr', 'reversed', 'round', 'set', 'setattr', 'slice',
                          'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple',
                          'type', 'vars', 'zip', '__import__', 'NotImplemented',
                          'Ellipsis', '__debug__'];
    var py2 = {'builtins': ['apply', 'basestring', 'buffer', 'cmp', 'coerce', 'execfile',
                            'file', 'intern', 'long', 'raw_input', 'reduce', 'reload',
                            'unichr', 'unicode', 'xrange', 'False', 'True', 'None'],
               'keywords': ['exec', 'print']};
    var py3 = {'builtins': ['ascii', 'bytearray', 'bytes', 'exec', 'print'],
               'keywords': ['nonlocal', 'False', 'True', 'None']};

    if (!!parserConf.version && parseInt(parserConf.version, 10) === 3) {
        commonkeywords = commonkeywords.concat(py3.keywords);
        commonBuiltins = commonBuiltins.concat(py3.builtins);
        var stringPrefixes = new RegExp("^(([rb]|(br))?('{3}|\"{3}|['\"]))", "i");
    } else {
        commonkeywords = commonkeywords.concat(py2.keywords);
        commonBuiltins = commonBuiltins.concat(py2.builtins);
        var stringPrefixes = new RegExp("^(([rub]|(ur)|(br))?('{3}|\"{3}|['\"]))", "i");
    }
    var keywords = wordRegexp(commonkeywords);
    var builtins = wordRegexp(commonBuiltins);

    var indentInfo = null;

    // tokenizers
    function tokenBase(stream, state) {
        // Handle scope changes
        if (stream.sol()) {
            var scopeOffset = state.scopes[0].offset;
            if (stream.eatSpace()) {
                var lineOffset = stream.indentation();
                if (lineOffset > scopeOffset) {
                    indentInfo = 'indent';
                } else if (lineOffset < scopeOffset) {
                    indentInfo = 'dedent';
                }
                return null;
            } else {
                if (scopeOffset > 0) {
                    dedent(stream, state);
                }
            }
        }
        if (stream.eatSpace()) {
            return null;
        }

        var ch = stream.peek();

        // Handle Comments
        if (ch === '#') {
            stream.skipToEnd();
            return 'comment';
        }

        // Handle Number Literals
        if (stream.match(/^[0-9\.]/, false)) {
            var floatLiteral = false;
            // Floats
            if (stream.match(/^\d*\.\d+(e[\+\-]?\d+)?/i)) { floatLiteral = true; }
            if (stream.match(/^\d+\.\d*/)) { floatLiteral = true; }
            if (stream.match(/^\.\d+/)) { floatLiteral = true; }
            if (floatLiteral) {
                // Float literals may be "imaginary"
                stream.eat(/J/i);
                return 'number';
            }
            // Integers
            var intLiteral = false;
            // Hex
            if (stream.match(/^0x[0-9a-f]+/i)) { intLiteral = true; }
            // Binary
            if (stream.match(/^0b[01]+/i)) { intLiteral = true; }
            // Octal
            if (stream.match(/^0o[0-7]+/i)) { intLiteral = true; }
            // Decimal
            if (stream.match(/^[1-9]\d*(e[\+\-]?\d+)?/)) {
                // Decimal literals may be "imaginary"
                stream.eat(/J/i);
                // TODO - Can you have imaginary longs?
                intLiteral = true;
            }
            // Zero by itself with no other piece of number.
            if (stream.match(/^0(?![\dx])/i)) { intLiteral = true; }
            if (intLiteral) {
                // Integer literals may be "long"
                stream.eat(/L/i);
                return 'number';
            }
        }

        // Handle Strings
        if (stream.match(stringPrefixes)) {
            state.tokenize = tokenStringFactory(stream.current());
            return state.tokenize(stream, state);
        }

        // Handle operators and Delimiters
        if (stream.match(tripleDelimiters) || stream.match(doubleDelimiters)) {
            return null;
        }
        if (stream.match(doubleOperators)
            || stream.match(singleOperators)
            || stream.match(wordOperators)) {
            return 'operator';
        }
        if (stream.match(singleDelimiters)) {
            return null;
        }

        if (stream.match(keywords)) {
            return 'keyword';
        }

        if (stream.match(builtins)) {
            return 'builtin';
        }

        if (stream.match(identifiers)) {
            return 'variable';
        }

        // Handle non-detected items
        stream.next();
        return ERRORCLASS;
    }

    function tokenStringFactory(delimiter) {
        while ('rub'.indexOf(delimiter.charAt(0).toLowerCase()) >= 0) {
            delimiter = delimiter.substr(1);
        }
        var singleline = delimiter.length == 1;
        var OUTCLASS = 'string';

        return function tokenString(stream, state) {
            while (!stream.eol()) {
                stream.eatWhile(/[^'"\\]/);
                if (stream.eat('\\')) {
                    stream.next();
                    if (singleline && stream.eol()) {
                        return OUTCLASS;
                    }
                } else if (stream.match(delimiter)) {
                    state.tokenize = tokenBase;
                    return OUTCLASS;
                } else {
                    stream.eat(/['"]/);
                }
            }
            if (singleline) {
                if (parserConf.singleLineStringErrors) {
                    return ERRORCLASS;
                } else {
                    state.tokenize = tokenBase;
                }
            }
            return OUTCLASS;
        };
    }

    function indent(stream, state, type) {
        type = type || 'py';
        var indentUnit = 0;
        if (type === 'py') {
            if (state.scopes[0].type !== 'py') {
                state.scopes[0].offset = stream.indentation();
                return;
            }
            for (var i = 0; i < state.scopes.length; ++i) {
                if (state.scopes[i].type === 'py') {
                    indentUnit = state.scopes[i].offset + conf.indentUnit;
                    break;
                }
            }
        } else {
            indentUnit = stream.column() + stream.current().length;
        }
        state.scopes.unshift({
            offset: indentUnit,
            type: type
        });
    }

    function dedent(stream, state, type) {
        type = type || 'py';
        if (state.scopes.length == 1) return;
        if (state.scopes[0].type === 'py') {
            var _indent = stream.indentation();
            var _indent_index = -1;
            for (var i = 0; i < state.scopes.length; ++i) {
                if (_indent === state.scopes[i].offset) {
                    _indent_index = i;
                    break;
                }
            }
            if (_indent_index === -1) {
                return true;
            }
            while (state.scopes[0].offset !== _indent) {
                state.scopes.shift();
            }
            return false
        } else {
            if (type === 'py') {
                state.scopes[0].offset = stream.indentation();
                return false;
            } else {
                if (state.scopes[0].type != type) {
                    return true;
                }
                state.scopes.shift();
                return false;
            }
        }
    }

    function tokenLexer(stream, state) {
        indentInfo = null;
        var style = state.tokenize(stream, state);
        var current = stream.current();

        // Handle '.' connected identifiers
        if (current === '.') {
            style = state.tokenize(stream, state);
            current = stream.current();
            if (style === 'variable' || style === 'builtin') {
                return 'variable';
            } else {
                return ERRORCLASS;
            }
        }

        // Handle decorators
        if (current === '@') {
            style = state.tokenize(stream, state);
            current = stream.current();
            if (style === 'variable'
                || current === '@staticmethod'
                || current === '@classmethod') {
                return 'meta';
            } else {
                return ERRORCLASS;
            }
        }

        // Handle scope changes.
        if (current === 'pass' || current === 'return') {
            state.dedent += 1;
        }
        if ((current === ':' && !state.lambda && state.scopes[0].type == 'py')
            || indentInfo === 'indent') {
            indent(stream, state);
        }
        var delimiter_index = '[({'.indexOf(current);
        if (delimiter_index !== -1) {
            indent(stream, state, '])}'.slice(delimiter_index, delimiter_index+1));
        }
        if (indentInfo === 'dedent') {
            if (dedent(stream, state)) {
                return ERRORCLASS;
            }
        }
        delimiter_index = '])}'.indexOf(current);
        if (delimiter_index !== -1) {
            if (dedent(stream, state, current)) {
                return ERRORCLASS;
            }
        }
        if (state.dedent > 0 && stream.eol() && state.scopes[0].type == 'py') {
            if (state.scopes.length > 1) state.scopes.shift();
            state.dedent -= 1;
        }

        return style;
    }

    var external = {
        startState: function(basecolumn) {
            return {
              tokenize: tokenBase,
              scopes: [{offset:basecolumn || 0, type:'py'}],
              lastToken: null,
              lambda: false,
              dedent: 0
          };
        },

        token: function(stream, state) {
            var style = tokenLexer(stream, state);

            state.lastToken = {style:style, content: stream.current()};

            if (stream.eol() && stream.lambda) {
                state.lambda = false;
            }

            return style;
        },

        indent: function(state, textAfter) {
            if (state.tokenize != tokenBase) {
                return 0;
            }

            return state.scopes[0].offset;
        }

    };
    return external;
});

CodeMirror.defineMIME("text/x-python", "python");
<commit_msg>Fix: missing 'chr' and 'bytearray' built-ins in PY2.<commit_after>CodeMirror.defineMode("python", function(conf, parserConf) {
    var ERRORCLASS = 'error';

    function wordRegexp(words) {
        return new RegExp("^((" + words.join(")|(") + "))\\b");
    }

    var singleOperators = new RegExp("^[\\+\\-\\*/%&|\\^~<>!]");
    var singleDelimiters = new RegExp('^[\\(\\)\\[\\]\\{\\}@,:`=;\\.]');
    var doubleOperators = new RegExp("^((==)|(!=)|(<=)|(>=)|(<>)|(<<)|(>>)|(//)|(\\*\\*))");
    var doubleDelimiters = new RegExp("^((\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))");
    var tripleDelimiters = new RegExp("^((//=)|(>>=)|(<<=)|(\\*\\*=))");
    var identifiers = new RegExp("^[_A-Za-z][_A-Za-z0-9]*");

    var wordOperators = wordRegexp(['and', 'or', 'not', 'is', 'in']);
    var commonkeywords = ['as', 'assert', 'break', 'class', 'continue',
                          'def', 'del', 'elif', 'else', 'except', 'finally',
                          'for', 'from', 'global', 'if', 'import',
                          'lambda', 'pass', 'raise', 'return',
                          'try', 'while', 'with', 'yield'];
    var commonBuiltins = ['abs', 'all', 'any', 'bin', 'bool', 'bytearray', 'callable', 'chr',
                          'classmethod', 'compile', 'complex', 'delattr', 'dict', 'dir', 'divmod',
                          'enumerate', 'eval', 'filter', 'float', 'format', 'frozenset',
                          'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id',
                          'input', 'int', 'isinstance', 'issubclass', 'iter', 'len',
                          'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next',
                          'object', 'oct', 'open', 'ord', 'pow', 'property', 'range',
                          'repr', 'reversed', 'round', 'set', 'setattr', 'slice',
                          'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple',
                          'type', 'vars', 'zip', '__import__', 'NotImplemented',
                          'Ellipsis', '__debug__'];
    var py2 = {'builtins': ['apply', 'basestring', 'buffer', 'cmp', 'coerce', 'execfile',
                            'file', 'intern', 'long', 'raw_input', 'reduce', 'reload',
                            'unichr', 'unicode', 'xrange', 'False', 'True', 'None'],
               'keywords': ['exec', 'print']};
    var py3 = {'builtins': ['ascii', 'bytes', 'exec', 'print'],
               'keywords': ['nonlocal', 'False', 'True', 'None']};

    if (!!parserConf.version && parseInt(parserConf.version, 10) === 3) {
        commonkeywords = commonkeywords.concat(py3.keywords);
        commonBuiltins = commonBuiltins.concat(py3.builtins);
        var stringPrefixes = new RegExp("^(([rb]|(br))?('{3}|\"{3}|['\"]))", "i");
    } else {
        commonkeywords = commonkeywords.concat(py2.keywords);
        commonBuiltins = commonBuiltins.concat(py2.builtins);
        var stringPrefixes = new RegExp("^(([rub]|(ur)|(br))?('{3}|\"{3}|['\"]))", "i");
    }
    var keywords = wordRegexp(commonkeywords);
    var builtins = wordRegexp(commonBuiltins);

    var indentInfo = null;

    // tokenizers
    function tokenBase(stream, state) {
        // Handle scope changes
        if (stream.sol()) {
            var scopeOffset = state.scopes[0].offset;
            if (stream.eatSpace()) {
                var lineOffset = stream.indentation();
                if (lineOffset > scopeOffset) {
                    indentInfo = 'indent';
                } else if (lineOffset < scopeOffset) {
                    indentInfo = 'dedent';
                }
                return null;
            } else {
                if (scopeOffset > 0) {
                    dedent(stream, state);
                }
            }
        }
        if (stream.eatSpace()) {
            return null;
        }

        var ch = stream.peek();

        // Handle Comments
        if (ch === '#') {
            stream.skipToEnd();
            return 'comment';
        }

        // Handle Number Literals
        if (stream.match(/^[0-9\.]/, false)) {
            var floatLiteral = false;
            // Floats
            if (stream.match(/^\d*\.\d+(e[\+\-]?\d+)?/i)) { floatLiteral = true; }
            if (stream.match(/^\d+\.\d*/)) { floatLiteral = true; }
            if (stream.match(/^\.\d+/)) { floatLiteral = true; }
            if (floatLiteral) {
                // Float literals may be "imaginary"
                stream.eat(/J/i);
                return 'number';
            }
            // Integers
            var intLiteral = false;
            // Hex
            if (stream.match(/^0x[0-9a-f]+/i)) { intLiteral = true; }
            // Binary
            if (stream.match(/^0b[01]+/i)) { intLiteral = true; }
            // Octal
            if (stream.match(/^0o[0-7]+/i)) { intLiteral = true; }
            // Decimal
            if (stream.match(/^[1-9]\d*(e[\+\-]?\d+)?/)) {
                // Decimal literals may be "imaginary"
                stream.eat(/J/i);
                // TODO - Can you have imaginary longs?
                intLiteral = true;
            }
            // Zero by itself with no other piece of number.
            if (stream.match(/^0(?![\dx])/i)) { intLiteral = true; }
            if (intLiteral) {
                // Integer literals may be "long"
                stream.eat(/L/i);
                return 'number';
            }
        }

        // Handle Strings
        if (stream.match(stringPrefixes)) {
            state.tokenize = tokenStringFactory(stream.current());
            return state.tokenize(stream, state);
        }

        // Handle operators and Delimiters
        if (stream.match(tripleDelimiters) || stream.match(doubleDelimiters)) {
            return null;
        }
        if (stream.match(doubleOperators)
            || stream.match(singleOperators)
            || stream.match(wordOperators)) {
            return 'operator';
        }
        if (stream.match(singleDelimiters)) {
            return null;
        }

        if (stream.match(keywords)) {
            return 'keyword';
        }

        if (stream.match(builtins)) {
            return 'builtin';
        }

        if (stream.match(identifiers)) {
            return 'variable';
        }

        // Handle non-detected items
        stream.next();
        return ERRORCLASS;
    }

    function tokenStringFactory(delimiter) {
        while ('rub'.indexOf(delimiter.charAt(0).toLowerCase()) >= 0) {
            delimiter = delimiter.substr(1);
        }
        var singleline = delimiter.length == 1;
        var OUTCLASS = 'string';

        return function tokenString(stream, state) {
            while (!stream.eol()) {
                stream.eatWhile(/[^'"\\]/);
                if (stream.eat('\\')) {
                    stream.next();
                    if (singleline && stream.eol()) {
                        return OUTCLASS;
                    }
                } else if (stream.match(delimiter)) {
                    state.tokenize = tokenBase;
                    return OUTCLASS;
                } else {
                    stream.eat(/['"]/);
                }
            }
            if (singleline) {
                if (parserConf.singleLineStringErrors) {
                    return ERRORCLASS;
                } else {
                    state.tokenize = tokenBase;
                }
            }
            return OUTCLASS;
        };
    }

    function indent(stream, state, type) {
        type = type || 'py';
        var indentUnit = 0;
        if (type === 'py') {
            if (state.scopes[0].type !== 'py') {
                state.scopes[0].offset = stream.indentation();
                return;
            }
            for (var i = 0; i < state.scopes.length; ++i) {
                if (state.scopes[i].type === 'py') {
                    indentUnit = state.scopes[i].offset + conf.indentUnit;
                    break;
                }
            }
        } else {
            indentUnit = stream.column() + stream.current().length;
        }
        state.scopes.unshift({
            offset: indentUnit,
            type: type
        });
    }

    function dedent(stream, state, type) {
        type = type || 'py';
        if (state.scopes.length == 1) return;
        if (state.scopes[0].type === 'py') {
            var _indent = stream.indentation();
            var _indent_index = -1;
            for (var i = 0; i < state.scopes.length; ++i) {
                if (_indent === state.scopes[i].offset) {
                    _indent_index = i;
                    break;
                }
            }
            if (_indent_index === -1) {
                return true;
            }
            while (state.scopes[0].offset !== _indent) {
                state.scopes.shift();
            }
            return false
        } else {
            if (type === 'py') {
                state.scopes[0].offset = stream.indentation();
                return false;
            } else {
                if (state.scopes[0].type != type) {
                    return true;
                }
                state.scopes.shift();
                return false;
            }
        }
    }

    function tokenLexer(stream, state) {
        indentInfo = null;
        var style = state.tokenize(stream, state);
        var current = stream.current();

        // Handle '.' connected identifiers
        if (current === '.') {
            style = state.tokenize(stream, state);
            current = stream.current();
            if (style === 'variable' || style === 'builtin') {
                return 'variable';
            } else {
                return ERRORCLASS;
            }
        }

        // Handle decorators
        if (current === '@') {
            style = state.tokenize(stream, state);
            current = stream.current();
            if (style === 'variable'
                || current === '@staticmethod'
                || current === '@classmethod') {
                return 'meta';
            } else {
                return ERRORCLASS;
            }
        }

        // Handle scope changes.
        if (current === 'pass' || current === 'return') {
            state.dedent += 1;
        }
        if ((current === ':' && !state.lambda && state.scopes[0].type == 'py')
            || indentInfo === 'indent') {
            indent(stream, state);
        }
        var delimiter_index = '[({'.indexOf(current);
        if (delimiter_index !== -1) {
            indent(stream, state, '])}'.slice(delimiter_index, delimiter_index+1));
        }
        if (indentInfo === 'dedent') {
            if (dedent(stream, state)) {
                return ERRORCLASS;
            }
        }
        delimiter_index = '])}'.indexOf(current);
        if (delimiter_index !== -1) {
            if (dedent(stream, state, current)) {
                return ERRORCLASS;
            }
        }
        if (state.dedent > 0 && stream.eol() && state.scopes[0].type == 'py') {
            if (state.scopes.length > 1) state.scopes.shift();
            state.dedent -= 1;
        }

        return style;
    }

    var external = {
        startState: function(basecolumn) {
            return {
              tokenize: tokenBase,
              scopes: [{offset:basecolumn || 0, type:'py'}],
              lastToken: null,
              lambda: false,
              dedent: 0
          };
        },

        token: function(stream, state) {
            var style = tokenLexer(stream, state);

            state.lastToken = {style:style, content: stream.current()};

            if (stream.eol() && stream.lambda) {
                state.lambda = false;
            }

            return style;
        },

        indent: function(state, textAfter) {
            if (state.tokenize != tokenBase) {
                return 0;
            }

            return state.scopes[0].offset;
        }

    };
    return external;
});

CodeMirror.defineMIME("text/x-python", "python");
<|endoftext|>


<commit_before>var path = require('path')
  , pkg = require('../package.json')
  , fs = require('fs')
  , async = require('async')
  , winston = require('winston')
  , find = require('findit')
  , version = pkg.version
  , exec = require('child_process').exec
  , spawn = require('child_process').spawn
  , opts = require('optimist')
	.usage('Usage: $0')
	.options({
		help: {
			demand: false,
			alias: 'h',
			description: 'Show this help'
		},
		debug: {
			demand: false,
			alias: 'd',
			description: 'debug',
			default: false
		},
		port: {
			demand: true,
			alias: 'p',
			description: 'port',
			default: process.env.PORT || 9001,
		}
	}).argv;
  ;

// Show help if asked
if (opts.help) {
    optimist.showHelp();
    process.exit(0);
}

// Set version
opts.version = version;

// Setup logging
winston.remove(winston.transports.Console);
winston.add(winston.transports.Console, {colorize: true});

// Create a gith server on port process.env.PORT
var gith = require('gith').create(opts.port) ;

// Log
winston.info('[>] WebHooks Server listening on port '+opts.port);

// Bind post-commit hooks without filters
gith().on( 'all', function( payload ) {

	// Debug payload
	winston.warn('[>] Post-commit happened on '+payload.repo+' !');
	//winston.info(JSON.stringify(payload, null, 4));

	// Set post-commit script path
	var postCommit = path.resolve('./repos/'+payload.repo+'/post-commit');

	// Find post-commit script and exec it
	async.series({

		// Search for post-commit script
		exists: function(next) {
			fs.exists(postCommit, function(exists) {
				next(!exists?'No post-commit found for '+postCommit:null);
			});
		},

		// Run
		execute: function(next) {
			winston.info('[>] Launch post-commit : '+postCommit);
			var post_commit = spawn('/bin/sh', [postCommit]);

			post_commit.stdout.on('data', function (data) {
				console.log('stdout: ' + data);
			});

			post_commit.stderr.on('data', function (data) {
				console.log('stderr: ' + data);
			});

			post_commit.on('close', function (code) {
				console.log('child process exited with code ' + code);
			});
/*
			exec("/bin/sh " + postCommit, function(err, datas) {
				console.log(err, datas) ;
				next(err, datas);
			});
*/
		}
	},

	// Response
	function(err, success) {
		console.log(err, success)
		if ( err ) {
			winston.error(err);
		}
		else {
			winston.info('post-commit script exists for '+payload.repo);
		}
	});

});<commit_msg>Better logs<commit_after>var path = require('path')
  , pkg = require('../package.json')
  , fs = require('fs')
  , async = require('async')
  , winston = require('winston')
  , find = require('findit')
  , version = pkg.version
  , exec = require('child_process').exec
  , spawn = require('child_process').spawn
  , opts = require('optimist')
	.usage('Usage: $0')
	.options({
		help: {
			demand: false,
			alias: 'h',
			description: 'Show this help'
		},
		debug: {
			demand: false,
			alias: 'd',
			description: 'debug',
			default: false
		},
		port: {
			demand: true,
			alias: 'p',
			description: 'port',
			default: process.env.PORT || 9001,
		}
	}).argv;
  ;

// Show help if asked
if (opts.help) {
    optimist.showHelp();
    process.exit(0);
}

// Set version
opts.version = version;

// Setup logging
winston.remove(winston.transports.Console);
winston.add(winston.transports.Console, {colorize: true});

// Create a gith server on port process.env.PORT
var gith = require('gith').create(opts.port) ;

// Log
winston.info('[>] WebHooks Server listening on port '+opts.port);

// Bind post-commit hooks without filters
gith().on( 'all', function( payload ) {

	// Debug payload
	winston.warn('[>] Post-commit happened on '+payload.repo+' !');
	//winston.info(JSON.stringify(payload, null, 4));

	// Set post-commit script path
	var postCommit = path.resolve('./repos/'+payload.repo+'/post-commit');

	// Find post-commit script and exec it
	async.series({

		// Search for post-commit script
		exists: function(next) {
			fs.exists(postCommit, function(exists) {
				next(!exists?'No post-commit found for '+postCommit:null);
			});
		},

		// Run
		execute: function(next) {
			winston.info('[>] Launch post-commit : '+postCommit);
			var post_commit = spawn('/bin/sh', [postCommit]);

			// Pipe logs
			post_commit.stdout.on('data', winston.debug);
			post_commit.stderr.on('data', winston.debug);

			// On close
			post_commit.on('close', function (code) {
				console.log('child process exited with code ' + code);
			});
/*
			exec("/bin/sh " + postCommit, function(err, datas) {
				console.log(err, datas) ;
				next(err, datas);
			});
*/
		}
	},

	// Response
	function(err, success) {
		console.log(err, success)
		if ( err ) {
			winston.error(err);
		}
		else {
			winston.info('post-commit script exists for '+payload.repo);
		}
	});

});<|endoftext|>


<commit_before>// ==UserScript==
// @name Memer
// @description Translates memes to hover overs and links
// @version 0.1
// @match http://chat.stackexchange.com/rooms/*
// @authors
//		-- Ismael Miguel
//		-- Malachi26
// @run-at document-end
// ==/UserScript==
if (location.hostname != 'chat.stackexchange.com')
{
	;(function (window, undefined){
		'use strict';
		//Just in case of jQuery.noConflict();
		(function($) {

			var REPO = 'https://github.com/ismael-miguel/memer/';
			var ROOT = 'https://raw.githubusercontent.com/ismael-miguel/memer/master/memes/';
			//Please, StackExchange, give us something decent!
			//This fixed a bug where another chat plugin would break the matching
			var SITE = $('head link[rel="shortcut icon"]')[0].href.match(/static.net\/([^\/]+)\//)[1];

			//avoids creating a global function
			var translate = function() {
				$('#chat .message:not([data-checked="1"])')
					.attr('data-checked', 1)
					.find('>.content')
					.filter(':not(:has(.onebox))')
					.contents()
					.filter(function() {

						return this.nodeType === window.Node.TEXT_NODE;

					}).each(function() {

						var tmp_html = $('
');
						tmp_html.text(this.nodeValue);

						for(var type in meme_database)
						{
							memerize(tmp_html, meme_database[type].memes);
						}

						$(this).replaceWith(tmp_html.html());
					});

				setTimeout(translate, 5000);
			};

			var memerize = function(tmp_html, memes) {
				for (var meme_name in memes)
				{
					var meme = memes[meme_name];
					var find = meme.find
						? new RegExp(meme.find[0], meme.find[1])
						: new RegExp('(' + (meme_name.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')) + ')', 'g');
					var replace = [
							'$1'
						].join('');

					$(tmp_html).contents().each(function() {
						//It's stupid, but it must be done
						if (this.nodeType === window.Node.TEXT_NODE)
						{
							$(this).replaceWith(this.nodeValue.replace(find, replace));
						}
					});
				}
			};

			//this will be where all data is saved
			var meme_database = {
				'common': '_common',
				'memes': SITE
			};

			var popup = function(html) {
				//yup, standard way to create the popup
				popUp(0, 0)
					.css({
						'width': 'auto',
						'maxWidth': 300,
						'minWidth': 300,
						'top': 0,
						'left': (window.innerWidth - 300) / 2
					})
					.addClass('user-popup')
					.append(html);
			};

			var remaining = 0, failed = 0;
			for(var type in meme_database)
			{
				remaining++;
				//really? If I don't wrap it, it writes stuff on wrong places
				(function(type){
					$.get(
						ROOT + meme_database[type] + '.json',
						function(data) {
						if(data && (data = $.parseJSON(data)))
						{
							meme_database[type] = data;
						}
					})
					.fail(function(){
						failed++;
						popup([ //what an ugly piece of code!
							'
Memer error:
',
							'
Failed to load ' + type + '.json
',
							'
If you are sure your connection is working, head to',
								' Memer\'s github ',
							'and provide your meme list.
'
						].join(''));
						meme_database[type] = {};
					}).always(function() {
						remaining--;
						if(remaining <= 0 && !failed)
						{
							popup('
Memer:

All the files loaded successfully
');
							setTimeout(translate, 5000);
						}
					});
				})(type.toString());//ensures it is not a reference, but a copy
			}

		})(window.jQuery);

	})(Function('return this')());
}
<commit_msg>Fixed stupid error.<commit_after>// ==UserScript==
// @name Memer
// @description Translates memes to hover overs and links
// @version 0.1
// @match http://chat.stackexchange.com/rooms/*
// @authors
//		-- Ismael Miguel
//		-- Malachi26
// @run-at document-end
// ==/UserScript==
if (location.hostname == 'chat.stackexchange.com')
{
	;(function (window, undefined){
		'use strict';
		//Just in case of jQuery.noConflict();
		(function($) {

			var REPO = 'https://github.com/ismael-miguel/memer/';
			var ROOT = 'https://raw.githubusercontent.com/ismael-miguel/memer/master/memes/';
			//Please, StackExchange, give us something decent!
			//This fixed a bug where another chat plugin would break the matching
			var SITE = $('head link[rel="shortcut icon"]')[0].href.match(/static.net\/([^\/]+)\//)[1];

			//avoids creating a global function
			var translate = function() {
				$('#chat .message:not([data-checked="1"])')
					.attr('data-checked', 1)
					.find('>.content')
					.filter(':not(:has(.onebox))')
					.contents()
					.filter(function() {

						return this.nodeType === window.Node.TEXT_NODE;

					}).each(function() {

						var tmp_html = $('
');
						tmp_html.text(this.nodeValue);

						for(var type in meme_database)
						{
							memerize(tmp_html, meme_database[type].memes);
						}

						$(this).replaceWith(tmp_html.html());
					});

				setTimeout(translate, 5000);
			};

			var memerize = function(tmp_html, memes) {
				for (var meme_name in memes)
				{
					var meme = memes[meme_name];
					var find = meme.find
						? new RegExp(meme.find[0], meme.find[1])
						: new RegExp('(' + (meme_name.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')) + ')', 'g');
					var replace = [
							'$1'
						].join('');

					$(tmp_html).contents().each(function() {
						//It's stupid, but it must be done
						if (this.nodeType === window.Node.TEXT_NODE)
						{
							$(this).replaceWith(this.nodeValue.replace(find, replace));
						}
					});
				}
			};

			//this will be where all data is saved
			var meme_database = {
				'common': '_common',
				'memes': SITE
			};

			var popup = function(html) {
				//yup, standard way to create the popup
				popUp(0, 0)
					.css({
						'width': 'auto',
						'maxWidth': 300,
						'minWidth': 300,
						'top': 0,
						'left': (window.innerWidth - 300) / 2
					})
					.addClass('user-popup')
					.append(html);
			};

			var remaining = 0, failed = 0;
			for(var type in meme_database)
			{
				remaining++;
				//really? If I don't wrap it, it writes stuff on wrong places
				(function(type){
					$.get(
						ROOT + meme_database[type] + '.json',
						function(data) {
						if(data && (data = $.parseJSON(data)))
						{
							meme_database[type] = data;
						}
					})
					.fail(function(){
						failed++;
						popup([ //what an ugly piece of code!
							'
Memer error:
',
							'
Failed to load ' + type + '.json
',
							'
If you are sure your connection is working, head to',
								' Memer\'s github ',
							'and provide your meme list.
'
						].join(''));
						meme_database[type] = {};
					}).always(function() {
						remaining--;
						if(remaining <= 0 && !failed)
						{
							popup('
Memer:

All the files loaded successfully
');
							setTimeout(translate, 5000);
						}
					});
				})(type.toString());//ensures it is not a reference, but a copy
			}

		})(window.jQuery);

	})(Function('return this')());
}
<|endoftext|>


<commit_before>/**
 * Author: Koh Zi Han, based on implementation by Koh Zi Chun
 */
CodeMirror.defineMode("scheme", function (config, mode) {
    var BUILTIN = "builtin", COMMENT = "comment", STRING = "string",
        ATOM = "atom", NUMBER = "number", BRACKET = "bracket", KEYWORD="keyword";
    var INDENT_WORD_SKIP = 2, KEYWORDS_SKIP = 1;

    function makeKeywords(str) {
        var obj = {}, words = str.split(" ");
        for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
        return obj;
    }

    var keywords = makeKeywords("λ case-lambda call/cc class define-class exit-handler field import inherit init-field interface let*-values let-values let/ec mixin opt-lambda override protect provide public rename require require-for-syntax syntax syntax-case syntax-error unit/sig unless when with-syntax and begin call-with-current-continuation call-with-input-file call-with-output-file case cond define define-syntax delay do dynamic-wind else for-each if lambda let let* let-syntax letrec letrec-syntax map or syntax-rules abs acos angle append apply asin assoc assq assv atan boolean? caar cadr call-with-input-file call-with-output-file call-with-values car cdddar cddddr cdr ceiling char->integer char-alphabetic? char-ci<=? char-ci<? char-ci=? char-ci>=? char-ci>? char-downcase char-lower-case? char-numeric? char-ready? char-upcase char-upper-case? char-whitespace? char<=? char<? char=? char>=? char>? char? close-input-port close-output-port complex? cons cos current-input-port current-output-port denominator display eof-object? eq? equal? eqv? eval even? exact->inexact exact? exp expt #f floor force gcd imag-part inexact->exact inexact? input-port? integer->char integer? interaction-environment lcm length list list->string list->vector list-ref list-tail list? load log magnitude make-polar make-rectangular make-string make-vector max member memq memv min modulo negative? newline not null-environment null? number->string number? numerator odd? open-input-file open-output-file output-port? pair? peek-char port? positive? procedure? quasiquote quote quotient rational? rationalize read read-char real-part real? remainder reverse round scheme-report-environment set! set-car! set-cdr! sin sqrt string string->list string->number string->symbol string-append string-ci<=? string-ci<? string-ci=? string-ci>=? string-ci>? string-copy string-fill! string-length string-ref string-set! string<=? string<? string=? string>=? string>? string? substring symbol->string symbol? #t tan transcript-off transcript-on truncate values vector vector->list vector-fill! vector-length vector-ref vector-set! with-input-from-file with-output-to-file write write-char zero?");
    var indentKeys = makeKeywords("define let letrec let* lambda");

    function stateStack(indent, type, prev) { // represents a state stack object
        this.indent = indent;
        this.type = type;
        this.prev = prev;
    }

    function pushStack(state, indent, type) {
        state.indentStack = new stateStack(indent, type, state.indentStack);
    }

    function popStack(state) {
        state.indentStack = state.indentStack.prev;
    }

    /**
     * Scheme numbers are complicated unfortunately.
     * Checks if we're looking at a number, which might be possibly a fraction.
     * Also checks that it is not part of a longer identifier. Returns true/false accordingly.
     */
    function isNumber(ch, stream){
        if (!stream.eatWhile(/[0-9]/)) {
            if (stream.eat(/\//)) stream.eatWhile(/[0-9]/);
            if (stream.eol() || !(/[a-zA-Z\-\_\/]/.test(stream.peek()))) return true;
            stream.backUp(stream.current().length - 1); // undo all the eating
        }
        return false;
    }

    return {
        startState: function () {
            return {
                indentStack: null,
                indentation: 0,
                mode: false,
                sExprComment: false
            };
        },

        token: function (stream, state) {
            if (state.indentStack == null && stream.sol()) {
                // update indentation, but only if indentStack is empty
                state.indentation = stream.indentation();
            }

            // skip spaces
            if (stream.eatSpace()) {
                return null;
            }
            var returnType = null;

            switch(state.mode){
                case "string": // multi-line string parsing mode
                    var next, escaped = false;
                    while ((next = stream.next()) != null) {
                        if (next == "\"" && !escaped) {

                            state.mode = false;
                            break;
                        }
                        escaped = !escaped && next == "\\";
                    }
                    returnType = STRING; // continue on in scheme-string mode
                    break;
                case "comment": // comment parsing mode
                    var next, maybeEnd = false;
                    while ((next = stream.next()) != null) {
                        if (next == "#" && maybeEnd) {

                            state.mode = false;
                            break;
                        }
                        maybeEnd = (next == "|");
                    }
                    returnType = COMMENT;
                    break;
                case "s-expr-comment": // s-expr commenting mode
                    state.mode = false;
                    if(stream.peek() == "(" || stream.peek() == "["){
                        // actually start scheme s-expr commenting mode
                        state.sExprComment = 0;
                    }else{
                        // if not we just comment the entire of the next token
                        stream.eatWhile(/[^/s]/); // eat non spaces
                        returnType = COMMENT;
                        break;
                    }
                default: // default parsing mode
                    var ch = stream.next();

                    if (ch == "\"") {
                        state.mode = "string";
                        returnType = STRING;

                    } else if (ch == "'") {
                        returnType = ATOM;
                    } else if (ch == '#') {
                        if (stream.eat("|")) {					// Multi-line comment
                            state.mode = "comment"; // toggle to comment mode
                            returnType = COMMENT;
                        } else if (stream.eat(/[tf]/)) {			// #t/#f (atom)
                            returnType = ATOM;
                        } else if (stream.eat(';')) {				// S-Expr comment
                            state.mode = "s-expr-comment";
                            returnType = COMMENT;
                        }

                    } else if (ch == ";") { // comment
                        stream.skipToEnd(); // rest of the line is a comment
                        returnType = COMMENT;
                    } else if (ch == "-"){

                        if(!isNaN(parseInt(stream.peek()))){
                            stream.eatWhile(/[\/0-9]/);
                            returnType = NUMBER;
                        }else{
                            returnType = null;
                        }
                    } else if (isNumber(ch,stream)){
                        returnType = NUMBER;
                    } else if (ch == "(" || ch == "[") {
                        var keyWord = ''; var indentTemp = stream.column();
                        /**
                        Either
                        (indent-word ..
                        (non-indent-word ..
                        (;something else, bracket, etc.
                        */

                        while ((letter = stream.eat(/[^\s\(\[\;\)\]]/)) != null) {
                            keyWord += letter;
                        }

                        if (keyWord.length > 0 && indentKeys.propertyIsEnumerable(keyWord)) { // indent-word

                            pushStack(state, indentTemp + INDENT_WORD_SKIP, ch);
                        } else { // non-indent word
                            // we continue eating the spaces
                            stream.eatSpace();
                            if (stream.eol() || stream.peek() == ";") {
                                // nothing significant after
                                // we restart indentation 1 space after
                                pushStack(state, indentTemp + 1, ch);
                            } else {
                                pushStack(state, indentTemp + stream.current().length, ch); // else we match
                            }
                        }
                        stream.backUp(stream.current().length - 1); // undo all the eating

                        if(typeof state.sExprComment == "number") state.sExprComment++;

                        returnType = BRACKET;
                    } else if (ch == ")" || ch == "]") {
                        returnType = BRACKET;
                        if (state.indentStack != null && state.indentStack.type == (ch == ")" ? "(" : "[")) {
                            popStack(state);

                            if(typeof state.sExprComment == "number"){
                                if(--state.sExprComment == 0){
                                    returnType = COMMENT; // final closing bracket
                                    state.sExprComment = false; // turn off s-expr commenting mode
                                }
                            }
                        }
                    } else {
                        stream.eatWhile(/[\w\$_\-!$%&*+\.\/:<=>?@\^~]/);

                        if (keywords && keywords.propertyIsEnumerable(stream.current())) {
                            returnType = BUILTIN;
                        } else returnType = "variable";
                    }
            }
            return (typeof state.sExprComment == "number") ? COMMENT : returnType;
        },

        indent: function (state, textAfter) {
            if (state.indentStack == null) return state.indentation;
            return state.indentStack.indent;
        }
    };
});

CodeMirror.defineMIME("text/x-scheme", "scheme");
<commit_msg>[scheme mode] Fix parsing of numbers<commit_after>/**
 * Author: Koh Zi Han, based on implementation by Koh Zi Chun
 */
CodeMirror.defineMode("scheme", function (config, mode) {
    var BUILTIN = "builtin", COMMENT = "comment", STRING = "string",
        ATOM = "atom", NUMBER = "number", BRACKET = "bracket", KEYWORD="keyword";
    var INDENT_WORD_SKIP = 2, KEYWORDS_SKIP = 1;

    function makeKeywords(str) {
        var obj = {}, words = str.split(" ");
        for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
        return obj;
    }

    var keywords = makeKeywords("λ case-lambda call/cc class define-class exit-handler field import inherit init-field interface let*-values let-values let/ec mixin opt-lambda override protect provide public rename require require-for-syntax syntax syntax-case syntax-error unit/sig unless when with-syntax and begin call-with-current-continuation call-with-input-file call-with-output-file case cond define define-syntax delay do dynamic-wind else for-each if lambda let let* let-syntax letrec letrec-syntax map or syntax-rules abs acos angle append apply asin assoc assq assv atan boolean? caar cadr call-with-input-file call-with-output-file call-with-values car cdddar cddddr cdr ceiling char->integer char-alphabetic? char-ci<=? char-ci<? char-ci=? char-ci>=? char-ci>? char-downcase char-lower-case? char-numeric? char-ready? char-upcase char-upper-case? char-whitespace? char<=? char<? char=? char>=? char>? char? close-input-port close-output-port complex? cons cos current-input-port current-output-port denominator display eof-object? eq? equal? eqv? eval even? exact->inexact exact? exp expt #f floor force gcd imag-part inexact->exact inexact? input-port? integer->char integer? interaction-environment lcm length list list->string list->vector list-ref list-tail list? load log magnitude make-polar make-rectangular make-string make-vector max member memq memv min modulo negative? newline not null-environment null? number->string number? numerator odd? open-input-file open-output-file output-port? pair? peek-char port? positive? procedure? quasiquote quote quotient rational? rationalize read read-char real-part real? remainder reverse round scheme-report-environment set! set-car! set-cdr! sin sqrt string string->list string->number string->symbol string-append string-ci<=? string-ci<? string-ci=? string-ci>=? string-ci>? string-copy string-fill! string-length string-ref string-set! string<=? string<? string=? string>=? string>? string? substring symbol->string symbol? #t tan transcript-off transcript-on truncate values vector vector->list vector-fill! vector-length vector-ref vector-set! with-input-from-file with-output-to-file write write-char zero?");
    var indentKeys = makeKeywords("define let letrec let* lambda");

    function stateStack(indent, type, prev) { // represents a state stack object
        this.indent = indent;
        this.type = type;
        this.prev = prev;
    }

    function pushStack(state, indent, type) {
        state.indentStack = new stateStack(indent, type, state.indentStack);
    }

    function popStack(state) {
        state.indentStack = state.indentStack.prev;
    }

    return {
        startState: function () {
            return {
                indentStack: null,
                indentation: 0,
                mode: false,
                sExprComment: false
            };
        },

        token: function (stream, state) {
            if (state.indentStack == null && stream.sol()) {
                // update indentation, but only if indentStack is empty
                state.indentation = stream.indentation();
            }

            // skip spaces
            if (stream.eatSpace()) {
                return null;
            }
            var returnType = null;

            switch(state.mode){
                case "string": // multi-line string parsing mode
                    var next, escaped = false;
                    while ((next = stream.next()) != null) {
                        if (next == "\"" && !escaped) {

                            state.mode = false;
                            break;
                        }
                        escaped = !escaped && next == "\\";
                    }
                    returnType = STRING; // continue on in scheme-string mode
                    break;
                case "comment": // comment parsing mode
                    var next, maybeEnd = false;
                    while ((next = stream.next()) != null) {
                        if (next == "#" && maybeEnd) {

                            state.mode = false;
                            break;
                        }
                        maybeEnd = (next == "|");
                    }
                    returnType = COMMENT;
                    break;
                case "s-expr-comment": // s-expr commenting mode
                    state.mode = false;
                    if(stream.peek() == "(" || stream.peek() == "["){
                        // actually start scheme s-expr commenting mode
                        state.sExprComment = 0;
                    }else{
                        // if not we just comment the entire of the next token
                        stream.eatWhile(/[^/s]/); // eat non spaces
                        returnType = COMMENT;
                        break;
                    }
                default: // default parsing mode
                    var ch = stream.next();

                    if (ch == "\"") {
                        state.mode = "string";
                        returnType = STRING;

                    } else if (ch == "'") {
                        returnType = ATOM;
                    } else if (ch == '#') {
                        if (stream.eat("|")) {					// Multi-line comment
                            state.mode = "comment"; // toggle to comment mode
                            returnType = COMMENT;
                        } else if (stream.eat(/[tf]/)) {			// #t/#f (atom)
                            returnType = ATOM;
                        } else if (stream.eat(';')) {				// S-Expr comment
                            state.mode = "s-expr-comment";
                            returnType = COMMENT;
                        }

                    } else if (ch == ";") { // comment
                        stream.skipToEnd(); // rest of the line is a comment
                        returnType = COMMENT;
                    } else if (/\d/.test(ch) && stream.match(/$|\d+(?:\/\d+|(?:\.\d+)?(?:[eE][+\-]?\d+)?)\b/) ||
                               ch == "-" && stream.match(/\d+(?:\/\d+|(?:\.\d+)?(?:[eE][+\-]?\d+)?)\b/)) {
                        returnType = NUMBER;
                    } else if (ch == "(" || ch == "[") {
                        var keyWord = ''; var indentTemp = stream.column();
                        /**
                        Either
                        (indent-word ..
                        (non-indent-word ..
                        (;something else, bracket, etc.
                        */

                        while ((letter = stream.eat(/[^\s\(\[\;\)\]]/)) != null) {
                            keyWord += letter;
                        }

                        if (keyWord.length > 0 && indentKeys.propertyIsEnumerable(keyWord)) { // indent-word

                            pushStack(state, indentTemp + INDENT_WORD_SKIP, ch);
                        } else { // non-indent word
                            // we continue eating the spaces
                            stream.eatSpace();
                            if (stream.eol() || stream.peek() == ";") {
                                // nothing significant after
                                // we restart indentation 1 space after
                                pushStack(state, indentTemp + 1, ch);
                            } else {
                                pushStack(state, indentTemp + stream.current().length, ch); // else we match
                            }
                        }
                        stream.backUp(stream.current().length - 1); // undo all the eating

                        if(typeof state.sExprComment == "number") state.sExprComment++;

                        returnType = BRACKET;
                    } else if (ch == ")" || ch == "]") {
                        returnType = BRACKET;
                        if (state.indentStack != null && state.indentStack.type == (ch == ")" ? "(" : "[")) {
                            popStack(state);

                            if(typeof state.sExprComment == "number"){
                                if(--state.sExprComment == 0){
                                    returnType = COMMENT; // final closing bracket
                                    state.sExprComment = false; // turn off s-expr commenting mode
                                }
                            }
                        }
                    } else {
                        stream.eatWhile(/[\w\$_\-!$%&*+\.\/:<=>?@\^~]/);

                        if (keywords && keywords.propertyIsEnumerable(stream.current())) {
                            returnType = BUILTIN;
                        } else returnType = "variable";
                    }
            }
            return (typeof state.sExprComment == "number") ? COMMENT : returnType;
        },

        indent: function (state, textAfter) {
            if (state.indentStack == null) return state.indentation;
            return state.indentStack.indent;
        }
    };
});

CodeMirror.defineMIME("text/x-scheme", "scheme");
<|endoftext|>


<commit_before>const imageProportionsLocker = require('imcms-image-proportions-locker-button');

define(
    "imcms-image-editor-body-head-builder",
    [
        "imcms-i18n-texts", "imcms-bem-builder", "imcms-components-builder", "jquery", 'imcms-image-edit-size-controls',
        "imcms-image-rotate", "imcms-image-resize", 'imcms-editable-image', 'imcms-preview-image-area',
        'imcms-toolbar-view-builder', 'imcms-image-cropper', 'imcms-editable-area',
        'imcms-image-active-tab', 'imcms-image-zoom'
    ],
    function (texts, BEM, components, $, imageEditSizeControls, imageRotate, imageResize, editableImage, previewImageArea,
              ToolbarViewBuilder, cropper, editableImageArea, checkActiveTab, imageZoom) {

        texts = texts.editors.image;
        let imageData;

        const toggleImageAreaToolbarViewBuilder = new ToolbarViewBuilder()
            .hide(
                getShowImageRotationControls(),
                getRevertButton(),
                getCroppingButton(),
                imageProportionsLocker.getProportionsButton(),
                imageProportionsLocker.getProportionsText(),
            )
            .show(
                getZoomPlusButton(),
                getZoomMinusButton(),
                getPercentageRatio(),
                getZoomResetButton(),
                getFitButton()
            )
            .originControlSizeShow(imageEditSizeControls.getOriginSizeControls());

        function toggleImgArea() {
            const $previewImageArea = previewImageArea.getPreviewImageArea();
            const $controlTabs = $(".imcms-editable-img-control-tabs__tab");
            const $editableArea = editableImageArea.getEditableImageArea();//todo rename all modules on the origin instead edit
            const $exifInfoButton = $('.imcms-image_editor__right-side').find(`[name='exifInfo']`);

            if ($(this).data("tab") === "prev") {
                toggleImageAreaToolbarViewBuilder.buildEditorElement();
                imageEditSizeControls.getImageSizeControlBlock().show();

                $exifInfoButton.css({
                    'display': 'none'
                });

                $editableArea.css({
                    "z-index": "10",
                    'display': "none"
                });

                $previewImageArea.css({
                    "z-index": "50",
                    "display": "block"
                });
            } else {
                const width = imageResize.getWidth();
                const height = imageResize.getHeight();
                imageEditSizeControls.setWidth(width, true);
                imageEditSizeControls.setHeight(height, true);
                toggleImageAreaToolbarViewBuilder.build();
                imageEditSizeControls.getImageSizeControlBlock().hide();
                $exifInfoButton.show();
                if (imageData.path !== '') {
                    if (imageData.exifInfo && imageData.exifInfo.length !== 0) {
                        $exifInfoButton.removeAttr('disabled').removeClass('imcms-button--disabled');
                    } else {
                        $exifInfoButton.addClass('imcms-button--disabled').attr('disabled', '');
                    }

                } else {
                    $exifInfoButton.hide();
                }
                $previewImageArea.css({
                    "z-index": "10",
                    "display": "none"
                });

                $editableArea.css({
                    "z-index": "50",
                    'display': "block"
                });
            }

            $controlTabs.removeClass("imcms-editable-img-control-tabs__tab--active");
            $(this).addClass("imcms-editable-img-control-tabs__tab--active");

            imageZoom.updateZoomGradeValue();
        }

        function showHidePanel(panelOpts) {
            const panelAnimationOpts = {};

            if (panelOpts.$btn.data("state")) {
                panelAnimationOpts[panelOpts.panelSide] = "-" + panelOpts.newPanelSideValue + "px";
                panelOpts.$panel.animate(panelAnimationOpts, 300);
                panelOpts.$btn.data("state", false);
                panelOpts.$btn.text(panelOpts.textShow);

            } else {
                panelAnimationOpts[panelOpts.panelSide] = 0;
                panelOpts.$panel.animate(panelAnimationOpts, 300);
                panelOpts.$btn.data("state", true);
                panelOpts.$btn.text(panelOpts.textHide);
            }
        }

        function showHideRightPanel($rightSidePanel) {
            showHidePanel({
                $btn: $(this),
                newPanelSideValue: $rightSidePanel.width(),
                $panel: $rightSidePanel,
                panelSide: "right",
                textHide: texts.panels.right.hide,
                textShow: texts.panels.right.show
            });
        }

        function revertToPreviewImageChanges() {
            imageData = JSON.parse(JSON.stringify(imageResize.getFinalPreviewImageData()));
            imageRotate.rotateImage("NORTH");
            imageZoom.resetZoom();
            imageResize.resetToPreview(imageData);
        }

        function revertToOriginalImageChanges() {
            if (checkActiveTab.currentActiveTab() === 'prev') {
                imageData.cropRegion = {
                    cropX1: 0,
                    cropX2: 0,
                    cropY1: 0,
                    cropY2: 0,
                };
                imageRotate.rotateImage("NORTH");
                imageZoom.resetZoom();
                imageResize.resetToOriginal(imageData);
            } else {
                imageData.cropRegion = {
                    cropX1: 0,
                    cropX2: 0,
                    cropY1: 0,
                    cropY2: 0,
                };
                imageRotate.rotateImage("NORTH");
                imageZoom.resetZoom();
            }
        }

        let $switchViewControls;

        function getSwitchViewControls() {
            return $switchViewControls || ($switchViewControls = buildSwitchViewControls())
        }

        let $tabOriginal;
        let $tabPreview;

        function buildSwitchViewControls() {
            $tabPreview = components.texts.titleText("<div>", texts.preview, {
                "data-tab": "prev",
                click: toggleImgArea
            });
            $tabOriginal = components.texts.titleText("<div>", texts.original, {
                "data-tab": "origin",
                click: toggleImgArea
            });
            $tabPreview.modifiers = ["active"];

            return new BEM({
                block: "imcms-editable-img-control-tabs",
                elements: {
                    "tab": [$tabOriginal, $tabPreview]
                }
            }).buildBlockStructure("<div>");
        }

        function wrapWithNoOpIfNoImageYet(wrapMe) {
            return function () {
                if (imageData && imageData.path) wrapMe.apply(this, arguments)
            };
        }

        function onCancel() {
            ToolbarViewBuilder.getCurrentToolbarView().cancelChanges();
        }

        function onApply() {
            ToolbarViewBuilder.getCurrentToolbarView().applyChanges();
        }

        function onRotationActivated() {
            let previousRotateDegrees = parseInt(
                previewImageArea.getPreviewImage()[0].style.transform.split(' ')[0].replace(/\D/g, '')
            );

            new ToolbarViewBuilder()
                .hide(
                    getShowImageRotationControls(),
                    getRevertButton(),
                    getCroppingButton(),
                    getSwitchViewControls(),
                )
                .show(
                    getCancelChangesButton(),
                    getApplyChangesButton(),
                    getRotateLeftButton(),
                    getRotateRightButton(),
                )
                .onCancel(() => imageRotate.rotateImageByDegrees(previousRotateDegrees))
                .build();
        }

        function getCroppingProportionsInfo() {
            return components.texts.infoText(
                '<div>',
                `${imageResize.isProportionsLockedByStyle() ? texts.presetCrop : texts.crop}: ${imageResize.getPreviewWidth().toFixed()} x ${imageResize.getPreviewHeight().toFixed()}`,
                {
                    'class': 'imcms-image-crop-proportions-info',
                    style: 'display: block;'
                }
            );
        }

        let $cancelChangesButton;

        function getCancelChangesButton() {
            if ($cancelChangesButton) {
                return $cancelChangesButton;
            }
            $cancelChangesButton = components.buttons.negativeButton({
                text: texts.buttons.cancelText,
                click: onCancel,
                style: 'display: none;',
            });
            components.overlays.defaultTooltip($cancelChangesButton, texts.buttons.cancelTitle);

            return $cancelChangesButton;
        }

        let $applyChangesButton;

        function getApplyChangesButton() {
            if ($applyChangesButton) {
                return $applyChangesButton;
            }
            $applyChangesButton = components.buttons.saveButton({
                text: texts.buttons.applyChangeText,
                click: onApply,
                style: 'display: none;',
            });
            components.overlays.defaultTooltip($applyChangesButton, texts.buttons.applyChangeTitle);

            return $applyChangesButton;
        }

        let $removeCroppingButton;

        function getRemoveCroppingButton() {
            return $removeCroppingButton || ($removeCroppingButton = components.buttons.negativeButton({
                text: texts.buttons.removeCropping,
                style: 'display: none;',
                click: () => cropper.initImageCropper(imageData),
            }));
        }

        let $showImageRotationControls;

        function getShowImageRotationControls() {
            if ($showImageRotationControls) {
                return $showImageRotationControls;
            }
            $showImageRotationControls = components.buttons.rotationButton({
                click: onRotationActivated,
            });
            components.overlays.defaultTooltip($showImageRotationControls, texts.buttons.rotationTitle);

            return $showImageRotationControls;
        }

        let $zoomPlusButton;

        function getZoomPlusButton() {
            if ($zoomPlusButton) {
                return $zoomPlusButton;
            }
            $zoomPlusButton = components.buttons.zoomPlusButton({
                click: wrapWithNoOpIfNoImageYet(imageZoom.zoomPlus),
                style: 'display: none;',
            });
            components.overlays.defaultTooltip($zoomPlusButton, texts.buttons.zoomIn);

            return $zoomPlusButton;
        }

        let $zoomMinusButton;

        function getZoomMinusButton() {
            if ($zoomMinusButton) {
                return $zoomMinusButton;
            }
            $zoomMinusButton = components.buttons.zoomMinusButton({
                click: wrapWithNoOpIfNoImageYet(imageZoom.zoomMinus),
                style: 'display: none;',
            });
            components.overlays.defaultTooltip($zoomMinusButton, texts.buttons.zoomOut);

            return $zoomMinusButton;
        }

        let $fitButton;

        function getFitButton() {
            if ($fitButton) {
                return $fitButton;
            }
            $fitButton = components.buttons.fitButton({
                'class': 'icon-image-fit',
                click: imageZoom.fitImage,
                style: 'display: none;'
            });
            components.overlays.defaultTooltip($fitButton, 'fit');

            return $fitButton;
        }

        let $zoomResetButton;

        function getZoomResetButton() {
            if ($zoomResetButton) {
                return $zoomResetButton;
            }
            $zoomResetButton = components.buttons.zoomResetButton({
                style: 'display: none;',
                click: wrapWithNoOpIfNoImageYet(revertToOriginalImageChanges),
            });
            components.overlays.defaultTooltip($zoomResetButton, texts.buttons.reset);

            return $zoomResetButton;
        }

        let $rotateLeftButton;

        function getRotateLeftButton() {
            if ($rotateLeftButton) {
                return $rotateLeftButton;
            }
            $rotateLeftButton = components.buttons.rotateLeftButton({
                click: wrapWithNoOpIfNoImageYet(imageRotate.rotateLeft),
                style: 'display: none;',
            });
            components.overlays.defaultTooltip($rotateLeftButton, texts.buttons.rotateLeft);

            return $rotateLeftButton;
        }

        let $rotateRightButton;

        function getRotateRightButton() {
            if ($rotateRightButton) {
                return $rotateRightButton;
            }
            $rotateRightButton = components.buttons.rotateRightButton({
                click: wrapWithNoOpIfNoImageYet(imageRotate.rotateRight),
                style: 'display: none;',
            });
            components.overlays.defaultTooltip($rotateRightButton, texts.buttons.rotateRight);

            return $rotateRightButton;
        }

        let $revertButton;

        function getRevertButton() {
            if ($revertButton) {
                return $revertButton;
            }
            $revertButton = components.buttons.revertButton({
                click: wrapWithNoOpIfNoImageYet(revertToPreviewImageChanges),
            });
            components.overlays.defaultTooltip($revertButton, texts.buttons.revert);

            return $revertButton;
        }

        function showCroppingStuff() {
            cropper.initImageCropper(imageData);
            const $croppingProportionsInfo = getCroppingProportionsInfo();
            $croppingProportionsInfo.insertAfter(getApplyChangesButton());

            new ToolbarViewBuilder()
                .hide(
                    getShowImageRotationControls(),
                    getRevertButton(),
                    getCroppingButton(),
                    getSwitchViewControls(),
                )
                .show(
                    getCancelChangesButton(),
                    getRemoveCroppingButton(),
                    getApplyChangesButton(),
                )
                .onCancel(() => {
                    cropper.destroyImageCropper();
                    $croppingProportionsInfo.remove();
                })
                .onApply(() => {
                    $croppingProportionsInfo.remove();
                    cropper.applyCropping();
                    cropper.destroyImageCropper();
                })
                .build();

            $croppingProportionsInfo.css('display', 'inline-block');
        }

        let $croppingButton;

        function getCroppingButton() {
            if ($croppingButton) {
                return $croppingButton;
            }
            $croppingButton = components.buttons.croppingButton({
                click: showCroppingStuff,
            });
            components.overlays.defaultTooltip($croppingButton, texts.buttons.cropping);

            return $croppingButton;
        }

        let $percentageRatio;

        function getPercentageRatio() {
            if ($percentageRatio) {
                return $percentageRatio;
            }
            $percentageRatio = imageZoom.buildZoomGradeField();

            return $percentageRatio;
        }

        let $scaleAndRotateControls;

        function getScaleAndRotateControls() {
            return $scaleAndRotateControls || ($scaleAndRotateControls = new BEM({
                block: "imcms-edit-image",
                elements: {
                    'size-place': [
                        imageEditSizeControls.getOriginSizeControls(),
                    ],
                    "button": [
                        imageProportionsLocker.getProportionsButton(),
                        imageProportionsLocker.getProportionsText(),
                        getRemoveCroppingButton(),
                        getZoomPlusButton(),
                        getZoomMinusButton(),
                        getPercentageRatio(),
                        getZoomResetButton(),
                        getFitButton(),
                        getShowImageRotationControls(),
                        getRotateLeftButton(),
                        getRotateRightButton(),
                        getCroppingButton(),
                        getRevertButton(),
                    ],
                }
            }).buildBlockStructure("<div>"))
        }

        function buildToolbar() {

            return new BEM({
                block: "imcms-editable-img-controls",
                elements: {
                    'control-button': '',
                    "control-scale-n-rotate": '',
                    "control-view": '',
                }
            }).buildBlock("<div>", [
                {'control-button': getCancelChangesButton()},
                {"control-scale-n-rotate": getScaleAndRotateControls()},
                {"control-button": getApplyChangesButton()},
                {"control-view": getSwitchViewControls()}
            ]);
        }

        const $imgUrl = $("<a>");

        module.exports = {
            showOriginalImageArea: () => toggleImgArea.call($tabOriginal),

            showPreviewImageArea: () => toggleImgArea.call($tabPreview),

            build: function ($rightSidePanel, _imageData) {
                imageData = _imageData;

                const bodyHeadBEM = new BEM({
                    block: "imcms-image-toolbar",
                    elements: {
                        "button": "imcms-image-characteristic",
                        "img-title": "imcms-title imcms-image-characteristic",
                        "img-url": "imcms-title imcms-image-characteristic",
                        "img-origin-size": "imcms-title imcms-image-characteristic"
                    }
                });

                const $showHideRightPanelBtn = components.buttons.neutralButton({
                    "class": "imcms-image-characteristic",
                    text: texts.panels.right.show,
                    click: function () {
                        showHideRightPanel.call(this, $rightSidePanel);
                    }
                });

                return bodyHeadBEM.buildBlock("<div>", [
                    {
                        "toolbar": buildToolbar()
                    }, {
                        "button": $showHideRightPanelBtn,
                        modifiers: ["right-panel"]
                    }
                ]);
            },
            getImageUrl: () => $imgUrl,
            getImagePath: () => $imgUrl.attr('data-path'),

            clearData() {
                [
                    imageEditSizeControls.getImageSizeControlBlock(),
                    imageEditSizeControls.getOriginSizeControls(),
                    getCancelChangesButton(),
                    imageProportionsLocker.getProportionsButton(),
                    imageProportionsLocker.getProportionsText(),
                    getApplyChangesButton(),
                    getRemoveCroppingButton(),
                    getRotateLeftButton(),
                    getRotateRightButton(),
                    getPercentageRatio(),
                    getZoomPlusButton(),
                    getZoomMinusButton(),
                    getZoomResetButton(),
                    getFitButton(),

                ].forEach($elem => $elem.hide());

                $('.imcms-image-crop-proportions-info').remove();

                getSwitchViewControls().show();

                previewImageArea.clearData();

                imageProportionsLocker.enableProportionsLock();

                cropper.destroyImageCropper();

                imageZoom.clearData();

            },
        }
    }
);
<commit_msg>Issue IMCMS-508: Improve the image editor - Fix set original W/H<commit_after>const imageProportionsLocker = require('imcms-image-proportions-locker-button');

define(
    "imcms-image-editor-body-head-builder",
    [
        "imcms-i18n-texts", "imcms-bem-builder", "imcms-components-builder", "jquery", 'imcms-image-edit-size-controls',
        "imcms-image-rotate", "imcms-image-resize", 'imcms-editable-image', 'imcms-preview-image-area',
        'imcms-toolbar-view-builder', 'imcms-image-cropper', 'imcms-editable-area',
        'imcms-image-active-tab', 'imcms-image-zoom'
    ],
    function (texts, BEM, components, $, imageEditSizeControls, imageRotate, imageResize, editableImage, previewImageArea,
              ToolbarViewBuilder, cropper, editableImageArea, checkActiveTab, imageZoom) {

        texts = texts.editors.image;
        let imageData;

        const toggleImageAreaToolbarViewBuilder = new ToolbarViewBuilder()
            .hide(
                getShowImageRotationControls(),
                getRevertButton(),
                getCroppingButton(),
                imageProportionsLocker.getProportionsButton(),
                imageProportionsLocker.getProportionsText(),
            )
            .show(
                getZoomPlusButton(),
                getZoomMinusButton(),
                getPercentageRatio(),
                getZoomResetButton(),
                getFitButton()
            )
            .originControlSizeShow(imageEditSizeControls.getOriginSizeControls());

        function toggleImgArea() {
            const $previewImageArea = previewImageArea.getPreviewImageArea();
            const $controlTabs = $(".imcms-editable-img-control-tabs__tab");
            const $editableArea = editableImageArea.getEditableImageArea();//todo rename all modules on the origin instead edit
            const $exifInfoButton = $('.imcms-image_editor__right-side').find(`[name='exifInfo']`);

            if ($(this).data("tab") === "prev") {
                toggleImageAreaToolbarViewBuilder.buildEditorElement();
                imageEditSizeControls.getImageSizeControlBlock().show();

                $exifInfoButton.css({
                    'display': 'none'
                });

                $editableArea.css({
                    "z-index": "10",
                    'display': "none"
                });

                $previewImageArea.css({
                    "z-index": "50",
                    "display": "block"
                });
            } else {
                const original = imageResize.getOriginal();
                const width = original.width;
                const height = original.height;
                imageEditSizeControls.setWidth(width, true);
                imageEditSizeControls.setHeight(height, true);
                toggleImageAreaToolbarViewBuilder.build();
                imageEditSizeControls.getImageSizeControlBlock().hide();
                $exifInfoButton.show();
                if (imageData.path !== '') {
                    if (imageData.exifInfo && imageData.exifInfo.length !== 0) {
                        $exifInfoButton.removeAttr('disabled').removeClass('imcms-button--disabled');
                    } else {
                        $exifInfoButton.addClass('imcms-button--disabled').attr('disabled', '');
                    }

                } else {
                    $exifInfoButton.hide();
                }
                $previewImageArea.css({
                    "z-index": "10",
                    "display": "none"
                });

                $editableArea.css({
                    "z-index": "50",
                    'display': "block"
                });
            }

            $controlTabs.removeClass("imcms-editable-img-control-tabs__tab--active");
            $(this).addClass("imcms-editable-img-control-tabs__tab--active");

            imageZoom.updateZoomGradeValue();
        }

        function showHidePanel(panelOpts) {
            const panelAnimationOpts = {};

            if (panelOpts.$btn.data("state")) {
                panelAnimationOpts[panelOpts.panelSide] = "-" + panelOpts.newPanelSideValue + "px";
                panelOpts.$panel.animate(panelAnimationOpts, 300);
                panelOpts.$btn.data("state", false);
                panelOpts.$btn.text(panelOpts.textShow);

            } else {
                panelAnimationOpts[panelOpts.panelSide] = 0;
                panelOpts.$panel.animate(panelAnimationOpts, 300);
                panelOpts.$btn.data("state", true);
                panelOpts.$btn.text(panelOpts.textHide);
            }
        }

        function showHideRightPanel($rightSidePanel) {
            showHidePanel({
                $btn: $(this),
                newPanelSideValue: $rightSidePanel.width(),
                $panel: $rightSidePanel,
                panelSide: "right",
                textHide: texts.panels.right.hide,
                textShow: texts.panels.right.show
            });
        }

        function revertToPreviewImageChanges() {
            imageData = JSON.parse(JSON.stringify(imageResize.getFinalPreviewImageData()));
            imageRotate.rotateImage("NORTH");
            imageZoom.resetZoom();
            imageResize.resetToPreview(imageData);
        }

        function revertToOriginalImageChanges() {
            if (checkActiveTab.currentActiveTab() === 'prev') {
                imageData.cropRegion = {
                    cropX1: 0,
                    cropX2: 0,
                    cropY1: 0,
                    cropY2: 0,
                };
                imageRotate.rotateImage("NORTH");
                imageZoom.resetZoom();
                imageResize.resetToOriginal(imageData);
            } else {
                imageData.cropRegion = {
                    cropX1: 0,
                    cropX2: 0,
                    cropY1: 0,
                    cropY2: 0,
                };
                imageRotate.rotateImage("NORTH");
                imageZoom.resetZoom();
            }
        }

        let $switchViewControls;

        function getSwitchViewControls() {
            return $switchViewControls || ($switchViewControls = buildSwitchViewControls())
        }

        let $tabOriginal;
        let $tabPreview;

        function buildSwitchViewControls() {
            $tabPreview = components.texts.titleText("<div>", texts.preview, {
                "data-tab": "prev",
                click: toggleImgArea
            });
            $tabOriginal = components.texts.titleText("<div>", texts.original, {
                "data-tab": "origin",
                click: toggleImgArea
            });
            $tabPreview.modifiers = ["active"];

            return new BEM({
                block: "imcms-editable-img-control-tabs",
                elements: {
                    "tab": [$tabOriginal, $tabPreview]
                }
            }).buildBlockStructure("<div>");
        }

        function wrapWithNoOpIfNoImageYet(wrapMe) {
            return function () {
                if (imageData && imageData.path) wrapMe.apply(this, arguments)
            };
        }

        function onCancel() {
            ToolbarViewBuilder.getCurrentToolbarView().cancelChanges();
        }

        function onApply() {
            ToolbarViewBuilder.getCurrentToolbarView().applyChanges();
        }

        function onRotationActivated() {
            let previousRotateDegrees = parseInt(
                previewImageArea.getPreviewImage()[0].style.transform.split(' ')[0].replace(/\D/g, '')
            );

            new ToolbarViewBuilder()
                .hide(
                    getShowImageRotationControls(),
                    getRevertButton(),
                    getCroppingButton(),
                    getSwitchViewControls(),
                )
                .show(
                    getCancelChangesButton(),
                    getApplyChangesButton(),
                    getRotateLeftButton(),
                    getRotateRightButton(),
                )
                .onCancel(() => imageRotate.rotateImageByDegrees(previousRotateDegrees))
                .build();
        }

        function getCroppingProportionsInfo() {
            return components.texts.infoText(
                '<div>',
                `${imageResize.isProportionsLockedByStyle() ? texts.presetCrop : texts.crop}: ${imageResize.getPreviewWidth().toFixed()} x ${imageResize.getPreviewHeight().toFixed()}`,
                {
                    'class': 'imcms-image-crop-proportions-info',
                    style: 'display: block;'
                }
            );
        }

        let $cancelChangesButton;

        function getCancelChangesButton() {
            if ($cancelChangesButton) {
                return $cancelChangesButton;
            }
            $cancelChangesButton = components.buttons.negativeButton({
                text: texts.buttons.cancelText,
                click: onCancel,
                style: 'display: none;',
            });
            components.overlays.defaultTooltip($cancelChangesButton, texts.buttons.cancelTitle);

            return $cancelChangesButton;
        }

        let $applyChangesButton;

        function getApplyChangesButton() {
            if ($applyChangesButton) {
                return $applyChangesButton;
            }
            $applyChangesButton = components.buttons.saveButton({
                text: texts.buttons.applyChangeText,
                click: onApply,
                style: 'display: none;',
            });
            components.overlays.defaultTooltip($applyChangesButton, texts.buttons.applyChangeTitle);

            return $applyChangesButton;
        }

        let $removeCroppingButton;

        function getRemoveCroppingButton() {
            return $removeCroppingButton || ($removeCroppingButton = components.buttons.negativeButton({
                text: texts.buttons.removeCropping,
                style: 'display: none;',
                click: () => cropper.initImageCropper(imageData),
            }));
        }

        let $showImageRotationControls;

        function getShowImageRotationControls() {
            if ($showImageRotationControls) {
                return $showImageRotationControls;
            }
            $showImageRotationControls = components.buttons.rotationButton({
                click: onRotationActivated,
            });
            components.overlays.defaultTooltip($showImageRotationControls, texts.buttons.rotationTitle);

            return $showImageRotationControls;
        }

        let $zoomPlusButton;

        function getZoomPlusButton() {
            if ($zoomPlusButton) {
                return $zoomPlusButton;
            }
            $zoomPlusButton = components.buttons.zoomPlusButton({
                click: wrapWithNoOpIfNoImageYet(imageZoom.zoomPlus),
                style: 'display: none;',
            });
            components.overlays.defaultTooltip($zoomPlusButton, texts.buttons.zoomIn);

            return $zoomPlusButton;
        }

        let $zoomMinusButton;

        function getZoomMinusButton() {
            if ($zoomMinusButton) {
                return $zoomMinusButton;
            }
            $zoomMinusButton = components.buttons.zoomMinusButton({
                click: wrapWithNoOpIfNoImageYet(imageZoom.zoomMinus),
                style: 'display: none;',
            });
            components.overlays.defaultTooltip($zoomMinusButton, texts.buttons.zoomOut);

            return $zoomMinusButton;
        }

        let $fitButton;

        function getFitButton() {
            if ($fitButton) {
                return $fitButton;
            }
            $fitButton = components.buttons.fitButton({
                'class': 'icon-image-fit',
                click: imageZoom.fitImage,
                style: 'display: none;'
            });
            components.overlays.defaultTooltip($fitButton, 'fit');

            return $fitButton;
        }

        let $zoomResetButton;

        function getZoomResetButton() {
            if ($zoomResetButton) {
                return $zoomResetButton;
            }
            $zoomResetButton = components.buttons.zoomResetButton({
                style: 'display: none;',
                click: wrapWithNoOpIfNoImageYet(revertToOriginalImageChanges),
            });
            components.overlays.defaultTooltip($zoomResetButton, texts.buttons.reset);

            return $zoomResetButton;
        }

        let $rotateLeftButton;

        function getRotateLeftButton() {
            if ($rotateLeftButton) {
                return $rotateLeftButton;
            }
            $rotateLeftButton = components.buttons.rotateLeftButton({
                click: wrapWithNoOpIfNoImageYet(imageRotate.rotateLeft),
                style: 'display: none;',
            });
            components.overlays.defaultTooltip($rotateLeftButton, texts.buttons.rotateLeft);

            return $rotateLeftButton;
        }

        let $rotateRightButton;

        function getRotateRightButton() {
            if ($rotateRightButton) {
                return $rotateRightButton;
            }
            $rotateRightButton = components.buttons.rotateRightButton({
                click: wrapWithNoOpIfNoImageYet(imageRotate.rotateRight),
                style: 'display: none;',
            });
            components.overlays.defaultTooltip($rotateRightButton, texts.buttons.rotateRight);

            return $rotateRightButton;
        }

        let $revertButton;

        function getRevertButton() {
            if ($revertButton) {
                return $revertButton;
            }
            $revertButton = components.buttons.revertButton({
                click: wrapWithNoOpIfNoImageYet(revertToPreviewImageChanges),
            });
            components.overlays.defaultTooltip($revertButton, texts.buttons.revert);

            return $revertButton;
        }

        function showCroppingStuff() {
            cropper.initImageCropper(imageData);
            const $croppingProportionsInfo = getCroppingProportionsInfo();
            $croppingProportionsInfo.insertAfter(getApplyChangesButton());

            new ToolbarViewBuilder()
                .hide(
                    getShowImageRotationControls(),
                    getRevertButton(),
                    getCroppingButton(),
                    getSwitchViewControls(),
                )
                .show(
                    getCancelChangesButton(),
                    getRemoveCroppingButton(),
                    getApplyChangesButton(),
                )
                .onCancel(() => {
                    cropper.destroyImageCropper();
                    $croppingProportionsInfo.remove();
                })
                .onApply(() => {
                    $croppingProportionsInfo.remove();
                    cropper.applyCropping();
                    cropper.destroyImageCropper();
                })
                .build();

            $croppingProportionsInfo.css('display', 'inline-block');
        }

        let $croppingButton;

        function getCroppingButton() {
            if ($croppingButton) {
                return $croppingButton;
            }
            $croppingButton = components.buttons.croppingButton({
                click: showCroppingStuff,
            });
            components.overlays.defaultTooltip($croppingButton, texts.buttons.cropping);

            return $croppingButton;
        }

        let $percentageRatio;

        function getPercentageRatio() {
            if ($percentageRatio) {
                return $percentageRatio;
            }
            $percentageRatio = imageZoom.buildZoomGradeField();

            return $percentageRatio;
        }

        let $scaleAndRotateControls;

        function getScaleAndRotateControls() {
            return $scaleAndRotateControls || ($scaleAndRotateControls = new BEM({
                block: "imcms-edit-image",
                elements: {
                    'size-place': [
                        imageEditSizeControls.getOriginSizeControls(),
                    ],
                    "button": [
                        imageProportionsLocker.getProportionsButton(),
                        imageProportionsLocker.getProportionsText(),
                        getRemoveCroppingButton(),
                        getZoomPlusButton(),
                        getZoomMinusButton(),
                        getPercentageRatio(),
                        getZoomResetButton(),
                        getFitButton(),
                        getShowImageRotationControls(),
                        getRotateLeftButton(),
                        getRotateRightButton(),
                        getCroppingButton(),
                        getRevertButton(),
                    ],
                }
            }).buildBlockStructure("<div>"))
        }

        function buildToolbar() {

            return new BEM({
                block: "imcms-editable-img-controls",
                elements: {
                    'control-button': '',
                    "control-scale-n-rotate": '',
                    "control-view": '',
                }
            }).buildBlock("<div>", [
                {'control-button': getCancelChangesButton()},
                {"control-scale-n-rotate": getScaleAndRotateControls()},
                {"control-button": getApplyChangesButton()},
                {"control-view": getSwitchViewControls()}
            ]);
        }

        const $imgUrl = $("<a>");

        module.exports = {
            showOriginalImageArea: () => toggleImgArea.call($tabOriginal),

            showPreviewImageArea: () => toggleImgArea.call($tabPreview),

            build: function ($rightSidePanel, _imageData) {
                imageData = _imageData;

                const bodyHeadBEM = new BEM({
                    block: "imcms-image-toolbar",
                    elements: {
                        "button": "imcms-image-characteristic",
                        "img-title": "imcms-title imcms-image-characteristic",
                        "img-url": "imcms-title imcms-image-characteristic",
                        "img-origin-size": "imcms-title imcms-image-characteristic"
                    }
                });

                const $showHideRightPanelBtn = components.buttons.neutralButton({
                    "class": "imcms-image-characteristic",
                    text: texts.panels.right.show,
                    click: function () {
                        showHideRightPanel.call(this, $rightSidePanel);
                    }
                });

                return bodyHeadBEM.buildBlock("<div>", [
                    {
                        "toolbar": buildToolbar()
                    }, {
                        "button": $showHideRightPanelBtn,
                        modifiers: ["right-panel"]
                    }
                ]);
            },
            getImageUrl: () => $imgUrl,
            getImagePath: () => $imgUrl.attr('data-path'),

            clearData() {
                [
                    imageEditSizeControls.getImageSizeControlBlock(),
                    imageEditSizeControls.getOriginSizeControls(),
                    getCancelChangesButton(),
                    imageProportionsLocker.getProportionsButton(),
                    imageProportionsLocker.getProportionsText(),
                    getApplyChangesButton(),
                    getRemoveCroppingButton(),
                    getRotateLeftButton(),
                    getRotateRightButton(),
                    getPercentageRatio(),
                    getZoomPlusButton(),
                    getZoomMinusButton(),
                    getZoomResetButton(),
                    getFitButton(),

                ].forEach($elem => $elem.hide());

                $('.imcms-image-crop-proportions-info').remove();

                getSwitchViewControls().show();

                previewImageArea.clearData();

                imageProportionsLocker.enableProportionsLock();

                cropper.destroyImageCropper();

                imageZoom.clearData();

            },
        }
    }
);
<|endoftext|>