<commit_before>'use strict';

// Required args: id, column, loopend, loopstart
function chess_check_column(args){
    if(args['loopstart'] > args['loopend']){
        const temp = args['loopstart'];
        args['loopstart'] = args['loopend'];
        args['loopend'] = temp;
    }

    for(let i = args['loopstart'] + 1; i < args['loopend']; i++){
        if(chess_games[args['id']]['board'][i][args['column']].length === 1){
            return true;
        }
    }
    return false;
}

// Required args: id, column, dx, dy, loopstart, loopend, row
function chess_check_diagonal(args){
    if(args['loopstart'] > args['loopend']){
        const temp = args['loopstart'];
        args['loopstart'] = args['loopend'];
        args['loopend'] = temp;
    }

    let x = args['column'];
    let y = args['row'];

    for(let i = args['loopstart'] + 1; i < args['loopend']; i++){
        x += args['dx'];
        y += args['dy'];

        if(chess_games[args['id']]['board'][y][x].length === 1){
            return true;
        }
    }

    return false;
}

// Required args: id, loopend, loopstart, row
function chess_check_row(args){
    if(args['loopstart'] > args['loopend']){
        const temp = args['loopstart'];
        args['loopstart'] = args['loopend'];
        args['loopend'] = temp;
    }

    for(let i = args['loopstart'] + 1; i < args['loopend']; i++){
        if(chess_games[args['id']]['board'][args['row']][i].length === 1){
            return true;
        }
    }
    return false;
}

// Required args: id, piece-x, piece-y, target-x, target-y
function chess_move(args){
    if(!chess_games[args['id']]){
        return false;
    }

    const validation = chess_validate(args);
    if(validation['valid']){
        chess_games[args['id']]['en-passant'] = validation['en-passant'];
        const piece_x = args['piece-x'] - 1;
        const piece_y = args['piece-y'] - 1;
        const player = chess_games[args['id']]['player'];
        let piece = chess_games[args['id']]['board'][piece_y][piece_x];

        chess_games[args['id']]['board'][piece_y][piece_x] = '';
        let taken_piece = chess_games[args['id']]['board'][args['target-y'] - 1][args['target-x'] - 1];
        if(validation['castling']){
            if(validation['rook-long-moved']){
                chess_games[args['id']]['board'][piece_y][0] = '';
                chess_games[args['id']]['board'][piece_y][3] = chess_pieces[player][3];

            }else if(validation['rook-short-moved']){
                chess_games[args['id']]['board'][piece_y][7] = '';
                chess_games[args['id']]['board'][piece_y][5] = chess_pieces[player][3];
            }

        }else if(validation['en-passant-taken']){
            taken_piece = chess_games[args['id']]['board'][piece_y][args['target-x'] - 1];
            chess_games[args['id']]['board'][piece_y][args['target-x'] - 1] = '';

        }else if(validation['pawn-promote']){
            piece = chess_pieces[player][chess_games[args['id']]['players'][player]['pawn-promote']];
        }

        chess_games[args['id']]['players'][player]['king-moved'] = validation['king-moved'];
        chess_games[args['id']]['players'][player]['pieces-taken'] += taken_piece;
        chess_games[args['id']]['players'][player]['rook-long-moved'] = validation['rook-long-moved'];
        chess_games[args['id']]['players'][player]['rook-short-moved'] = validation['rook-short-moved'];
        chess_games[args['id']]['board'][args['target-y'] - 1][args['target-x'] - 1] = piece;
        chess_games[args['id']]['player'] = 1 - player;
    }
    return validation;
}

// Required args: id
function chess_new(args){
    chess_games[args['id']] = {
      'board': [
        [chess_pieces[1][3], chess_pieces[1][1], chess_pieces[1][2], chess_pieces[1][4], chess_pieces[1][5], chess_pieces[1][2], chess_pieces[1][1], chess_pieces[1][3],],
        [chess_pieces[1][0], chess_pieces[1][0], chess_pieces[1][0], chess_pieces[1][0], chess_pieces[1][0], chess_pieces[1][0], chess_pieces[1][0], chess_pieces[1][0],],
        ['', '', '', '', '', '', '', '',],
        ['', '', '', '', '', '', '', '',],
        ['', '', '', '', '', '', '', '',],
        ['', '', '', '', '', '', '', '',],
        [chess_pieces[0][0], chess_pieces[0][0], chess_pieces[0][0], chess_pieces[0][0], chess_pieces[0][0], chess_pieces[0][0], chess_pieces[0][0], chess_pieces[0][0],],
        [chess_pieces[0][3], chess_pieces[0][1], chess_pieces[0][2], chess_pieces[0][4], chess_pieces[0][5], chess_pieces[0][2], chess_pieces[0][1], chess_pieces[0][3],],
      ],
      'en-passant': -1,
      'en-passant-taken': false,
      'player': 0,
      'players': [
        {
          'king-moved': false,
          'pawn-promote': 4,
          'pieces-taken': '',
          'rook-long-moved': false,
          'rook-short-moved': false,
        },
        {
          'king-moved': false,
          'pawn-promote': 4,
          'pieces-taken': '',
          'rook-long-moved': false,
          'rook-short-moved': false,
        },
      ],
    };
}

// Required args: id, piece-x, piece-y, target-x, target-y
function chess_validate(args){
    let castling = false;
    let en_passant = -1;
    let en_passant_taken = false;
    let king_moved = false;
    let rook_long_moved = false;
    let rook_short_moved = false;
    let pawn_promote = false;
    let valid_move = true;

    const piece_x = args['piece-x'] - 1;
    const piece_y = args['piece-y'] - 1;
    const target_x = args['target-x'] - 1;
    const target_y = args['target-y'] - 1;
    if(!chess_games[args['id']]
      || piece_x < 0 || piece_x > 7
      || piece_y < 0 || piece_y > 7
      || target_x < 0 || target_x > 7
      || target_y < 0 || target_y > 7){
        valid_move = false;

    }else{
        const player = chess_games[args['id']]['player'];
        king_moved = chess_games[args['id']]['players'][player]['king-moved'];
        rook_long_moved = chess_games[args['id']]['players'][player]['rook-long-moved'];
        rook_short_moved = chess_games[args['id']]['players'][player]['rook-short-moved'];

        const piece = chess_games[args['id']]['board'][piece_y][piece_x];
        if(piece.length === 0 || !chess_pieces[player].includes(piece)){
            valid_move = false;

        }else{
            const target_piece = chess_games[args['id']]['board'][target_y][target_x];
            if(chess_pieces[player].includes(target_piece)){
                valid_move = false;

            }else{
                const movement_x = Math.abs(piece_x - target_x);
                const movement_y = Math.abs(piece_y - target_y);
                switch(piece){
                    // Pawn
                    case chess_pieces[player][0]: {
                        const direction = player === 0 ? -1 : 1;

                        if(target_x !== piece_x){
                            if(movement_x !== 1
                              || target_y - piece_y !== direction){
                                valid_move = false;

                            }else if(target_x === chess_games[args['id']]['en-passant'] - 1
                              && target_y === 2 + (player * 3)){
                                en_passant_taken = true;

                            }else if(!chess_pieces[1 - player].includes(target_piece)){
                                valid_move = false;
                            }

                        }else if(target_piece.length === 0){
                            if(piece_y === 6 - (player * 5)){
                                if(target_y !== piece_y + direction
                                  && target_y !== piece_y + direction * 2){
                                    valid_move = false;

                                }else if(target_y === piece_y + direction * 2){
                                    en_passant = piece_x + 1;
                                }

                            }else if(target_y !== piece_y + direction){
                                valid_move = false;
                            }

                        }else{
                            valid_move = false;
                        }

                        if(valid_move && target_y === player * 7){
                            pawn_promote = true;
                        }

                        break;
                    }

                    // Knight
                    case chess_pieces[player][1]: {
                        if(movement_x < 1 || movement_x > 2 || movement_y < 1 || movement_y > 2){
                            valid_move = false;

                        }else if((movement_x === 1 && movement_y !== 2)
                          || (movement_x === 2 && movement_y !== 1)){
                            valid_move = false;
                        }

                        break;
                    }

                    // Bishop
                    case chess_pieces[player][2]: {
                        if(movement_x === movement_y){
                            if(movement_y > 1 && chess_check_diagonal({
                                'column': piece_x,
                                'dx': piece_x < target_x
                                  ? 1
                                  : -1,
                                'dy': piece_y < target_y
                                  ? 1
                                  : -1,
                                'id': args['id'],
                                'loopend': target_x,
                                'loopstart': piece_x,
                                'row': piece_y,
                              })){
                                valid_move = false;
                            }

                        }else{
                            valid_move = false;
                        }

                        break;
                    }

                    // Rook
                    case chess_pieces[player][3]: {
                        if(target_x === piece_x){
                            if(movement_y > 1 && chess_check_column({
                                'column': piece_x,
                                'id': args['id'],
                                'loopend': target_y,
                                'loopstart': piece_y,
                              })){
                                valid_move = false;
                            }

                        }else if(target_y === piece_y){
                            if(movement_x > 1 && chess_check_row({
                                'id': args['id'],
                                'loopend': target_x,
                                'loopstart': piece_x,
                                'row': piece_y,
                              })){
                                valid_move = false;
                            }

                        }else{
                            valid_move = false;
                        }

                        if(valid_move && piece_y === (1 - player) * 7){
                            if(!rook_long_moved && piece_x === 0){
                                rook_long_moved = true;

                            }else if(!rook_short_moved && piece_x === 7){
                                rook_short_moved = true;
                            }
                        }

                        break;
                    }

                    // Queen
                    case chess_pieces[player][4]: {
                        if(movement_x === movement_y){
                            if(movement_y > 1 && chess_check_diagonal({
                                'column': piece_x,
                                'dx': piece_x < target_x
                                  ? 1
                                  : -1,
                                'dy': piece_y < target_y
                                  ? 1
                                  : -1,
                                'id': args['id'],
                                'loopend': target_x,
                                'loopstart': piece_x,
                                'row': piece_y,
                              })){
                                valid_move = false;
                            }

                        }else if(target_x === piece_x){
                            if(movement_y > 1 && chess_check_column({
                                'column': piece_x,
                                'id': args['id'],
                                'loopend': target_y,
                                'loopstart': piece_y,
                              })){
                                valid_move = false;
                            }

                        }else if(target_y === piece_y){
                            if(movement_x > 1 && chess_check_row({
                                'id': args['id'],
                                'loopend': target_x,
                                'loopstart': piece_x,
                                'row': piece_y,
                              })){
                                valid_move = false;
                            }

                        }else{
                            valid_move = false;
                        }

                        break;
                    }

                    // King
                    case chess_pieces[player][5]: {
                        if(!king_moved
                          && movement_x === 2 && movement_y === 0
                          && target_y === (1 - player) * 7){
                            if(!rook_long_moved && target_x === 2){
                                if(!chess_check_row({
                                    'id': args['id'],
                                    'loopend': piece_x,
                                    'loopstart': 0,
                                    'row': piece_y,
                                  })){
                                    king_moved = true;
                                    castling = true;
                                    rook_long_moved = true;

                                }else{
                                    valid_move = false;
                                }

                            }else if(!rook_short_moved && target_x === 6){
                                if(!chess_check_row({
                                    'id': args['id'],
                                    'loopend': 7,
                                    'loopstart': piece_x,
                                    'row': piece_y,
                                  })){
                                    king_moved = true;
                                    castling = true;
                                    rook_short_moved = true;

                                }else{
                                    valid_move = false;
                                }

                            }else{
                                valid_move = false;
                            }

                        }else if(movement_x > 1 || movement_y > 1){
                            valid_move = false;

                        }else{
                            king_moved = true;
                        }

                        break;
                    }

                    default:
                        valid_move = false;
                }
            }
        }
    }

    return {
      'castling': castling,
      'en-passant': en_passant,
      'en-passant-taken': en_passant_taken,
      'king-moved': king_moved,
      'pawn-promote': pawn_promote,
      'rook-long-moved': rook_long_moved,
      'rook-short-moved': rook_short_moved,
      'valid': valid_move,
    };
}

globalThis.chess_games = {};
globalThis.chess_pieces = [
  ['♙', '♘', '♗', '♖', '♕', '♔'],
  ['♟', '♞', '♝', '♜', '♛', '♚'],
];
<commit_msg>started chess_threat()<commit_after>'use strict';

// Required args: id, column, loopend, loopstart
function chess_check_column(args){
    if(args['loopstart'] > args['loopend']){
        const temp = args['loopstart'];
        args['loopstart'] = args['loopend'];
        args['loopend'] = temp;
    }

    for(let i = args['loopstart'] + 1; i < args['loopend']; i++){
        if(chess_games[args['id']]['board'][i][args['column']].length === 1){
            return true;
        }
    }
    return false;
}

// Required args: id, column, dx, dy, loopstart, loopend, row
function chess_check_diagonal(args){
    if(args['loopstart'] > args['loopend']){
        const temp = args['loopstart'];
        args['loopstart'] = args['loopend'];
        args['loopend'] = temp;
    }

    let x = args['column'];
    let y = args['row'];

    for(let i = args['loopstart'] + 1; i < args['loopend']; i++){
        x += args['dx'];
        y += args['dy'];

        if(chess_games[args['id']]['board'][y][x].length === 1){
            return true;
        }
    }

    return false;
}

// Required args: id, loopend, loopstart, row
function chess_check_row(args){
    if(args['loopstart'] > args['loopend']){
        const temp = args['loopstart'];
        args['loopstart'] = args['loopend'];
        args['loopend'] = temp;
    }

    for(let i = args['loopstart'] + 1; i < args['loopend']; i++){
        if(chess_games[args['id']]['board'][args['row']][i].length === 1){
            return true;
        }
    }
    return false;
}

// Required args: id, piece-x, piece-y, target-x, target-y
function chess_move(args){
    if(!chess_games[args['id']]){
        return false;
    }

    const validation = chess_validate(args);
    if(validation['valid']){
        chess_games[args['id']]['en-passant'] = validation['en-passant'];
        const piece_x = args['piece-x'] - 1;
        const piece_y = args['piece-y'] - 1;
        const player = chess_games[args['id']]['player'];
        let piece = chess_games[args['id']]['board'][piece_y][piece_x];

        chess_games[args['id']]['board'][piece_y][piece_x] = '';
        let taken_piece = chess_games[args['id']]['board'][args['target-y'] - 1][args['target-x'] - 1];
        if(validation['castling']){
            if(validation['rook-long-moved']){
                chess_games[args['id']]['board'][piece_y][0] = '';
                chess_games[args['id']]['board'][piece_y][3] = chess_pieces[player][3];

            }else if(validation['rook-short-moved']){
                chess_games[args['id']]['board'][piece_y][7] = '';
                chess_games[args['id']]['board'][piece_y][5] = chess_pieces[player][3];
            }

        }else if(validation['en-passant-taken']){
            taken_piece = chess_games[args['id']]['board'][piece_y][args['target-x'] - 1];
            chess_games[args['id']]['board'][piece_y][args['target-x'] - 1] = '';

        }else if(validation['pawn-promote']){
            piece = chess_pieces[player][chess_games[args['id']]['players'][player]['pawn-promote']];
        }

        chess_games[args['id']]['players'][player]['king-moved'] = validation['king-moved'];
        chess_games[args['id']]['players'][player]['pieces-taken'] += taken_piece;
        chess_games[args['id']]['players'][player]['rook-long-moved'] = validation['rook-long-moved'];
        chess_games[args['id']]['players'][player]['rook-short-moved'] = validation['rook-short-moved'];
        chess_games[args['id']]['board'][args['target-y'] - 1][args['target-x'] - 1] = piece;
        chess_games[args['id']]['player'] = 1 - player;
    }
    return validation;
}

// Required args: id
function chess_new(args){
    chess_games[args['id']] = {
      'board': [
        [chess_pieces[1][3], chess_pieces[1][1], chess_pieces[1][2], chess_pieces[1][4], chess_pieces[1][5], chess_pieces[1][2], chess_pieces[1][1], chess_pieces[1][3],],
        [chess_pieces[1][0], chess_pieces[1][0], chess_pieces[1][0], chess_pieces[1][0], chess_pieces[1][0], chess_pieces[1][0], chess_pieces[1][0], chess_pieces[1][0],],
        ['', '', '', '', '', '', '', '',],
        ['', '', '', '', '', '', '', '',],
        ['', '', '', '', '', '', '', '',],
        ['', '', '', '', '', '', '', '',],
        [chess_pieces[0][0], chess_pieces[0][0], chess_pieces[0][0], chess_pieces[0][0], chess_pieces[0][0], chess_pieces[0][0], chess_pieces[0][0], chess_pieces[0][0],],
        [chess_pieces[0][3], chess_pieces[0][1], chess_pieces[0][2], chess_pieces[0][4], chess_pieces[0][5], chess_pieces[0][2], chess_pieces[0][1], chess_pieces[0][3],],
      ],
      'en-passant': -1,
      'en-passant-taken': false,
      'player': 0,
      'players': [
        {
          'king-moved': false,
          'pawn-promote': 4,
          'pieces-taken': '',
          'rook-long-moved': false,
          'rook-short-moved': false,
        },
        {
          'king-moved': false,
          'pawn-promote': 4,
          'pieces-taken': '',
          'rook-long-moved': false,
          'rook-short-moved': false,
        },
      ],
    };
}

// Required args: id, piece-x, piece-y
function chess_threat(args){
    return false;
}

// Required args: id, piece-x, piece-y, target-x, target-y
function chess_validate(args){
    let castling = false;
    let en_passant = -1;
    let en_passant_taken = false;
    let king_moved = false;
    let rook_long_moved = false;
    let rook_short_moved = false;
    let pawn_promote = false;
    let valid_move = true;

    const piece_x = args['piece-x'] - 1;
    const piece_y = args['piece-y'] - 1;
    const target_x = args['target-x'] - 1;
    const target_y = args['target-y'] - 1;
    if(!chess_games[args['id']]
      || piece_x < 0 || piece_x > 7
      || piece_y < 0 || piece_y > 7
      || target_x < 0 || target_x > 7
      || target_y < 0 || target_y > 7){
        valid_move = false;

    }else{
        const player = chess_games[args['id']]['player'];
        king_moved = chess_games[args['id']]['players'][player]['king-moved'];
        rook_long_moved = chess_games[args['id']]['players'][player]['rook-long-moved'];
        rook_short_moved = chess_games[args['id']]['players'][player]['rook-short-moved'];

        const piece = chess_games[args['id']]['board'][piece_y][piece_x];
        if(piece.length === 0 || !chess_pieces[player].includes(piece)){
            valid_move = false;

        }else{
            const target_piece = chess_games[args['id']]['board'][target_y][target_x];
            if(chess_pieces[player].includes(target_piece)){
                valid_move = false;

            }else{
                const movement_x = Math.abs(piece_x - target_x);
                const movement_y = Math.abs(piece_y - target_y);
                switch(piece){
                    // Pawn
                    case chess_pieces[player][0]: {
                        const direction = player === 0 ? -1 : 1;

                        if(target_x !== piece_x){
                            if(movement_x !== 1
                              || target_y - piece_y !== direction){
                                valid_move = false;

                            }else if(target_x === chess_games[args['id']]['en-passant'] - 1
                              && target_y === 2 + (player * 3)){
                                en_passant_taken = true;

                            }else if(!chess_pieces[1 - player].includes(target_piece)){
                                valid_move = false;
                            }

                        }else if(target_piece.length === 0){
                            if(piece_y === 6 - (player * 5)){
                                if(target_y !== piece_y + direction
                                  && target_y !== piece_y + direction * 2){
                                    valid_move = false;

                                }else if(target_y === piece_y + direction * 2){
                                    en_passant = piece_x + 1;
                                }

                            }else if(target_y !== piece_y + direction){
                                valid_move = false;
                            }

                        }else{
                            valid_move = false;
                        }

                        if(valid_move && target_y === player * 7){
                            pawn_promote = true;
                        }

                        break;
                    }

                    // Knight
                    case chess_pieces[player][1]: {
                        if(movement_x < 1 || movement_x > 2 || movement_y < 1 || movement_y > 2){
                            valid_move = false;

                        }else if((movement_x === 1 && movement_y !== 2)
                          || (movement_x === 2 && movement_y !== 1)){
                            valid_move = false;
                        }

                        break;
                    }

                    // Bishop
                    case chess_pieces[player][2]: {
                        if(movement_x === movement_y){
                            if(movement_y > 1 && chess_check_diagonal({
                                'column': piece_x,
                                'dx': piece_x < target_x
                                  ? 1
                                  : -1,
                                'dy': piece_y < target_y
                                  ? 1
                                  : -1,
                                'id': args['id'],
                                'loopend': target_x,
                                'loopstart': piece_x,
                                'row': piece_y,
                              })){
                                valid_move = false;
                            }

                        }else{
                            valid_move = false;
                        }

                        break;
                    }

                    // Rook
                    case chess_pieces[player][3]: {
                        if(target_x === piece_x){
                            if(movement_y > 1 && chess_check_column({
                                'column': piece_x,
                                'id': args['id'],
                                'loopend': target_y,
                                'loopstart': piece_y,
                              })){
                                valid_move = false;
                            }

                        }else if(target_y === piece_y){
                            if(movement_x > 1 && chess_check_row({
                                'id': args['id'],
                                'loopend': target_x,
                                'loopstart': piece_x,
                                'row': piece_y,
                              })){
                                valid_move = false;
                            }

                        }else{
                            valid_move = false;
                        }

                        if(valid_move && piece_y === (1 - player) * 7){
                            if(!rook_long_moved && piece_x === 0){
                                rook_long_moved = true;

                            }else if(!rook_short_moved && piece_x === 7){
                                rook_short_moved = true;
                            }
                        }

                        break;
                    }

                    // Queen
                    case chess_pieces[player][4]: {
                        if(movement_x === movement_y){
                            if(movement_y > 1 && chess_check_diagonal({
                                'column': piece_x,
                                'dx': piece_x < target_x
                                  ? 1
                                  : -1,
                                'dy': piece_y < target_y
                                  ? 1
                                  : -1,
                                'id': args['id'],
                                'loopend': target_x,
                                'loopstart': piece_x,
                                'row': piece_y,
                              })){
                                valid_move = false;
                            }

                        }else if(target_x === piece_x){
                            if(movement_y > 1 && chess_check_column({
                                'column': piece_x,
                                'id': args['id'],
                                'loopend': target_y,
                                'loopstart': piece_y,
                              })){
                                valid_move = false;
                            }

                        }else if(target_y === piece_y){
                            if(movement_x > 1 && chess_check_row({
                                'id': args['id'],
                                'loopend': target_x,
                                'loopstart': piece_x,
                                'row': piece_y,
                              })){
                                valid_move = false;
                            }

                        }else{
                            valid_move = false;
                        }

                        break;
                    }

                    // King
                    case chess_pieces[player][5]: {
                        if(!king_moved
                          && movement_x === 2 && movement_y === 0
                          && target_y === (1 - player) * 7){
                            if(!rook_long_moved && target_x === 2){
                                if(!chess_check_row({
                                    'id': args['id'],
                                    'loopend': piece_x,
                                    'loopstart': 0,
                                    'row': piece_y,
                                  })){
                                    king_moved = true;
                                    castling = true;
                                    rook_long_moved = true;

                                }else{
                                    valid_move = false;
                                }

                            }else if(!rook_short_moved && target_x === 6){
                                if(!chess_check_row({
                                    'id': args['id'],
                                    'loopend': 7,
                                    'loopstart': piece_x,
                                    'row': piece_y,
                                  })){
                                    king_moved = true;
                                    castling = true;
                                    rook_short_moved = true;

                                }else{
                                    valid_move = false;
                                }

                            }else{
                                valid_move = false;
                            }

                        }else if(movement_x > 1 || movement_y > 1){
                            valid_move = false;

                        }else{
                            king_moved = true;
                        }

                        break;
                    }

                    default:
                        valid_move = false;
                }
            }
        }
    }

    return {
      'castling': castling,
      'en-passant': en_passant,
      'en-passant-taken': en_passant_taken,
      'king-moved': king_moved,
      'pawn-promote': pawn_promote,
      'rook-long-moved': rook_long_moved,
      'rook-short-moved': rook_short_moved,
      'valid': valid_move,
    };
}

globalThis.chess_games = {};
globalThis.chess_pieces = [
  ['♙', '♘', '♗', '♖', '♕', '♔'],
  ['♟', '♞', '♝', '♜', '♛', '♚'],
];
<|endoftext|>


<commit_before>/*eslint-disable */

var fs = require('fs')
var gulp = require('gulp')
var source = require('vinyl-source-stream')
var rename = require('gulp-rename')
var browserify = require('browserify')
var buffer = require('vinyl-buffer')
var uglify = require('gulp-uglify')
var taskListing = require('gulp-task-listing')
var awspublish = require('gulp-awspublish')
var injectVersion = require('gulp-inject-version')
var derequire = require('gulp-derequire')
var es = require('event-stream')
var karma = require('karma')
var runSequence = require('run-sequence')
var webdriver = require('gulp-webdriver')
var selenium = require('selenium-standalone')

var connect = require('gulp-connect')

require('gulp-release-tasks')(gulp)

var jeditor = require('gulp-json-editor')

var webdriverConfig = {
    user: process.env.SAUCE_USERNAME || 'opbeat',
    key: process.env.SAUCE_ACCESS_KEY || 'de42e589-1450-41a2-8a44-90aa00c15168',
    host: process.env.SAUCE_HOST ||'ondemand.saucelabs.com',
    port: process.env.SAUCE_PORT || 80,
    baseUrl: process.env.SAUCE_BASEURL || 'http://localhost:8000'
}

// Static file server
gulp.task('server', function () {
  connect.server({
    root: ['examples', 'dist'],
    port: 7000,
    livereload: false,
    open: false,
  })
})

function createBuildStream (mainFilePath) {
  return browserify({
    entries: [mainFilePath],
    standalone: '',
    insertGlobalVars: { define: function () { return 'undefined'; }, process: function () { return 'undefined'; } }
  })
    .bundle()
    .pipe(source(mainFilePath))
    .pipe(rename({ dirname: '' }))
    .pipe(buffer())
    .pipe(injectVersion({
      replace: new RegExp(RegExp.escape('%%VERSION%%'), 'g')
    }))
    .pipe(derequire())
}

function writeToDestinations (stream, dests) {
  var tasks = dests.map(function (destPath) {
    return stream.pipe(gulp.dest(versionPath))
  })
  return es.merge.apply(null, tasks)
}

function getMajorVersion () {
  var version = require('./package').version
  var majorVersion = version.match(/^(\d).(\d).(\d)/)[1]
  return majorVersion
}

gulp.task('build:release', function () {
  var version = require('./package').version
  var majorVersion = version.match(/^(\d).(\d).(\d)/)[1]

  var versionPath = './dist/cdn/' + majorVersion
  var prodPath = './dist/'

  var integrations = [
    { name: 'opbeat-angular', entry: './src/angular/opbeat-angular.js', description: 'Official AngularJS client for logging exceptions, stacktraces and performance data to Opbeat' },
    { name: 'opbeat-js', entry: './src/opbeat.js', description: 'This is the official frontend JavaScript module for Opbeat' }
  ]

  var tasks = integrations.map(function (integration) {
    var mainStream = createBuildStream(integration.entry)
      .pipe(gulp.dest(versionPath))
      .pipe(gulp.dest(prodPath))
      .pipe(gulp.dest(prodPath + integration.name))
      .pipe(rename({
        extname: '.min.js'
      }))
      .pipe(uglify())
      .pipe(gulp.dest(versionPath))
      .pipe(gulp.dest(prodPath))
      .pipe(gulp.dest(prodPath + integration.name))

    var filename = integration.entry.split('/')
    filename = filename[filename.length - 1]

    var packagejson = gulp.src(['./release/*.json'])
      .pipe(jeditor({
        'name': integration.name,
        'version': version,
        'main': filename,
        'description': integration.description
      }))
      .pipe(gulp.dest(prodPath + integration.name))

    return es.merge.apply(null, [mainStream, packagejson, gulp.src(['./README.md', 'LICENSE']).pipe(gulp.dest(prodPath + integration.name))])
  })

  return es.merge.apply(null, tasks)
})

gulp.task('build', function () {
  var sourceTargets = [
    './src/opbeat.js',
    './src/angular/opbeat-angular.js',
    './e2e_test/angular/opbeat-angular.e2e.js'
  ]

  var tasks = sourceTargets.map(function (entry) {
    return createBuildStream(entry)
      .pipe(gulp.dest('./dist/dev/'))
      .pipe(rename({
        extname: '.min.js'
      }))
      .pipe(uglify())
      .pipe(gulp.dest('./dist/dev/'))
  })

  return es.merge.apply(null, tasks)
})

// Development mode
gulp.task('watch', [], function (cb) {
  gulp.run(
    'build',
    'server'
  )

  // Watch JS files
  gulp.watch(['libs/**', 'src/**'], function () { runSequence('build', 'karma-run') })
  console.log('\nExample site running on http://localhost:7000/\n')
})

//
// Deploy task
//
gulp.task('deploy', ['build:release'], function () {
  // Load options from file
  awsoptions = JSON.parse(fs.readFileSync('aws.json'))

  // Hardcoded bucketname, to avoid mistakes
  awsoptions.params = {
    Bucket: 'opbeat-js-cdn'
  }

  // Create new publisher
  var publisher = awspublish.create(awsoptions)

  // Set headers
  var headers = {
    'Cache-Control': 'max-age=1800, public'
  }

  var version = require('./package').version
  var majorVersion = version.match(/^(\d).(\d).(\d)/)[1]

  var versionPath = './dist/cdn/**'

  return gulp.src([versionPath])
    // Gzip
    .pipe(awspublish.gzip())
    // Publish files with headers
    .pipe(publisher.publish(headers))
    // Create a cache file to speed up consecutive uploads
    .pipe(publisher.cache())
    // Print upload updates to console
    .pipe(awspublish.reporter())
})

function runKarma (configFile, done) {
  var exec = require('child_process').exec

  var cmd = process.platform === 'win32' ? 'node_modules\\.bin\\karma run ' :
    'node node_modules/.bin/karma run '
  cmd += configFile
  exec(cmd, function (e, stdout) {
    // ignore errors, we don't want to fail the build in the interactive (non-ci) mode
    // karma server will print all test failures
    done()
  })
}

gulp.task('karma-run', function (done) {
  // run the run command in a new process to avoid duplicate logging by both server and runner from
  // a single process
  runKarma('karma.conf.js', done)
})

gulp.task('test', function (done) {
  new karma.Server({
    configFile: __dirname + '/karma.conf.js',
    singleRun: true
  }, done).start()
})

gulp.task('test:e2e:protractor', function () {
  var protractor = require('gulp-protractor').protractor

  return gulp.src(['e2e_test/**/*.pspec.js'])
    .pipe(protractor({
      configFile: 'protractor.conf.js',
    }))
    .on('error', function (e) { throw e })
})

// Run end-to-end tests on the local machine using webdriver configuration
gulp.task('test:e2e:run', ['test:e2e:protractor'], function (done) {
  gulp.src('wdio.conf.js')
    .pipe(webdriver())
    .on('error', function () {
      return process.exit(1)
    })
    .on('end', function () {
      return process.exit(0)
    })
})

gulp.task('test:e2e:sauceconnect:failsafe', function () {
  var failSafeStream = gulp.src('wdio.failsafe.conf.js')
    .pipe(webdriver(webdriverConfig))
    .on('error', function () {
      console.log('Exiting process with status 1')
      process.exit(1)
    })
    .on('end', function () {
      console.log('Tests complete')
    })
  return failSafeStream
})

// Run end-to-end tests remotely in saucelabs using webdriver configuration
gulp.task('test:e2e:sauceconnect', ['test:e2e:sauceconnect:failsafe'], function () {
  var e2eStream = gulp.src('wdio.sauce.conf.js')
    .pipe(webdriver(webdriverConfig))
    .on('error', function () {
      console.log('Exiting process with status 1')
      process.exit(1)
    })
    .on('end', function () {
      console.log('Tests complete')
    })
  return e2eStream
})

// Launch sauce connect and connect
gulp.task('test:e2e:launchsauceconnect', function (done) {
  var sauceConnectLauncher = require('sauce-connect-launcher')

  var config = {
    username: webdriverConfig.user,
    accessKey: webdriverConfig.key,
    logger: console.log
  }

  var tryConnect = function(maxAttempts, currAttempts, done) {
    sauceConnectLauncher(config, function (err, sauceConnectProcess) {
      if (err) {
        console.error(err.message)
        if (currAttempts <= maxAttempts) {
          console.log("Retrying... (attempt " + currAttempts + " of " + maxAttempts + ")")
          tryConnect(maxAttempts, ++currAttempts, done)
        }else{
          return process.exit(1)
        }
      }else{
        console.log('Sauce Connect ready')
        done()
      }
    })
  }

  tryConnect(3, 1, done)
})

// Serve test application
gulp.task('test:e2e:serve', function () {
  return connect.server({
    root: ['e2e_test', 'src', './'],
    port: 8000,
    livereload: false,
    open: false,
    middleware: function (connect, opt) {
      var middlewares = []
      middlewares.push(connect.favicon())
      return middlewares
    }
  })
})

// Install and start selenium
gulp.task('test:e2e:selenium', function (done) {
  selenium.install({ logger: console.log }, function () {
    selenium.start(function () {
      done()
    })
  })
})

gulp.task('test:e2e:start-local', function (done) {
  runSequence('build', 'build:release', 'test:e2e:serve', 'test:e2e:selenium', function () {
    console.log('All tasks completed.')
  })
})

// Run all required tasks to perform remote end-to-end testing
gulp.task('test:e2e:start-sauce', function (done) {
  runSequence('build', 'test:e2e:launchsauceconnect', function () {
    console.log('All tasks completed.')
  })
})

gulp.task('test:e2e', function (done) {
  runSequence('build', 'test:e2e:serve', 'test:e2e:launchsauceconnect', 'test:e2e:sauceconnect', function () {
    console.log('All tasks completed.')
    done()
    process.exit(0)
  })
})

gulp.task('test:unit:sauce', function (done) {
  runSequence('build', 'test:e2e:serve', 'test:e2e:launchsauceconnect', 'test', function () {
    console.log('All tasks completed.')
    done()
    process.exit(0)
  })
})

gulp.task('watch:e2e', ['e2e-serve', 'selenium-start'], function (done) {
  gulp.watch(['e2e_test/**'], function () {
    runSequence('test:e2e')
  })
})

gulp.task('default', taskListing)
<commit_msg>gulpfile, minor clean up and formatting<commit_after>/*eslint-disable */

var fs = require('fs')
var gulp = require('gulp')
var source = require('vinyl-source-stream')
var rename = require('gulp-rename')
var browserify = require('browserify')
var buffer = require('vinyl-buffer')
var uglify = require('gulp-uglify')
var taskListing = require('gulp-task-listing')
var awspublish = require('gulp-awspublish')
var injectVersion = require('gulp-inject-version')
var derequire = require('gulp-derequire')
var es = require('event-stream')
var karma = require('karma')
var runSequence = require('run-sequence')
var webdriver = require('gulp-webdriver')
var selenium = require('selenium-standalone')

var connect = require('gulp-connect')

require('gulp-release-tasks')(gulp)

var jeditor = require('gulp-json-editor')

var webdriverConfig = {
  user: process.env.SAUCE_USERNAME || 'opbeat',
  key: process.env.SAUCE_ACCESS_KEY || 'de42e589-1450-41a2-8a44-90aa00c15168',
  host: process.env.SAUCE_HOST || 'ondemand.saucelabs.com',
  port: process.env.SAUCE_PORT || 80,
  baseUrl: process.env.SAUCE_BASEURL || 'http://localhost:8000'
}

// Static file server
gulp.task('server', function () {
  connect.server({
    root: ['examples', 'dist'],
    port: 7000,
    livereload: false,
    open: false,
  })
})

function createBuildStream (mainFilePath) {
  return browserify({
    entries: [mainFilePath],
    standalone: '',
    insertGlobalVars: { define: function () { return 'undefined'; }, process: function () { return 'undefined'; } }
  })
    .bundle()
    .pipe(source(mainFilePath))
    .pipe(rename({ dirname: '' }))
    .pipe(buffer())
    .pipe(injectVersion({
      replace: new RegExp(RegExp.escape('%%VERSION%%'), 'g')
    }))
    .pipe(derequire())
}

function writeToDestinations (stream, dests) {
  var tasks = dests.map(function (destPath) {
    return stream.pipe(gulp.dest(versionPath))
  })
  return es.merge.apply(null, tasks)
}

function getMajorVersion () {
  var version = require('./package').version
  var majorVersion = version.match(/^(\d).(\d).(\d)/)[1]
  return majorVersion
}

gulp.task('build:release', function () {
  var version = require('./package').version
  var majorVersion = version.match(/^(\d).(\d).(\d)/)[1]

  var versionPath = './dist/cdn/' + majorVersion
  var prodPath = './dist/'

  var integrations = [
    { name: 'opbeat-angular', entry: './src/angular/opbeat-angular.js', description: 'Official AngularJS client for logging exceptions, stacktraces and performance data to Opbeat' },
    { name: 'opbeat-js', entry: './src/opbeat.js', description: 'This is the official frontend JavaScript module for Opbeat' }
  ]

  var tasks = integrations.map(function (integration) {
    var mainStream = createBuildStream(integration.entry)
      .pipe(gulp.dest(versionPath))
      .pipe(gulp.dest(prodPath))
      .pipe(gulp.dest(prodPath + integration.name))
      .pipe(rename({
        extname: '.min.js'
      }))
      .pipe(uglify())
      .pipe(gulp.dest(versionPath))
      .pipe(gulp.dest(prodPath))
      .pipe(gulp.dest(prodPath + integration.name))

    var filename = integration.entry.split('/')
    filename = filename[filename.length - 1]

    var packagejson = gulp.src(['./release/*.json'])
      .pipe(jeditor({
        'name': integration.name,
        'version': version,
        'main': filename,
        'description': integration.description
      }))
      .pipe(gulp.dest(prodPath + integration.name))

    return es.merge.apply(null, [mainStream, packagejson, gulp.src(['./README.md', 'LICENSE']).pipe(gulp.dest(prodPath + integration.name))])
  })

  return es.merge.apply(null, tasks)
})

gulp.task('build', function () {
  var sourceTargets = [
    './src/opbeat.js',
    './src/angular/opbeat-angular.js',
    './e2e_test/angular/opbeat-angular.e2e.js'
  ]

  var tasks = sourceTargets.map(function (entry) {
    return createBuildStream(entry)
      .pipe(gulp.dest('./dist/dev/'))
      .pipe(rename({
        extname: '.min.js'
      }))
      .pipe(uglify())
      .pipe(gulp.dest('./dist/dev/'))
  })

  return es.merge.apply(null, tasks)
})

// Development mode
gulp.task('watch', [], function (cb) {
  gulp.run(
    'build',
    'server'
  )

  // Watch JS files
  gulp.watch(['libs/**', 'src/**'], function () { runSequence('build', 'karma-run') })
  console.log('\nExample site running on http://localhost:7000/\n')
})

//
// Deploy task
//
gulp.task('deploy', ['build:release'], function () {
  // Load options from file
  awsoptions = JSON.parse(fs.readFileSync('aws.json'))

  // Hardcoded bucketname, to avoid mistakes
  awsoptions.params = {
    Bucket: 'opbeat-js-cdn'
  }

  // Create new publisher
  var publisher = awspublish.create(awsoptions)

  // Set headers
  var headers = {
    'Cache-Control': 'max-age=1800, public'
  }

  var version = require('./package').version
  var majorVersion = version.match(/^(\d).(\d).(\d)/)[1]

  var versionPath = './dist/cdn/**'

  return gulp.src([versionPath])
    // Gzip
    .pipe(awspublish.gzip())
    // Publish files with headers
    .pipe(publisher.publish(headers))
    // Create a cache file to speed up consecutive uploads
    .pipe(publisher.cache())
    // Print upload updates to console
    .pipe(awspublish.reporter())
})

function runKarma (configFile, done) {
  var exec = require('child_process').exec

  var cmd = process.platform === 'win32' ? 'node_modules\\.bin\\karma run ' :
    'node node_modules/.bin/karma run '
  cmd += configFile
  exec(cmd, function (e, stdout) {
    // ignore errors, we don't want to fail the build in the interactive (non-ci) mode
    // karma server will print all test failures
    done()
  })
}

gulp.task('karma-run', function (done) {
  // run the run command in a new process to avoid duplicate logging by both server and runner from
  // a single process
  runKarma('karma.conf.js', done)
})

gulp.task('test', function (done) {
  new karma.Server({
    configFile: __dirname + '/karma.conf.js',
    singleRun: true
  }, done).start()
})

gulp.task('test:e2e:protractor', function () {
  var protractor = require('gulp-protractor').protractor

  return gulp.src(['e2e_test/**/*.pspec.js'])
    .pipe(protractor({
      configFile: 'protractor.conf.js',
    }))
    .on('error', function (e) { throw e })
})

// Run end-to-end tests on the local machine using webdriver configuration
gulp.task('test:e2e:run', ['test:e2e:protractor'], function (done) {
  gulp.src('wdio.conf.js')
    .pipe(webdriver())
    .on('error', function () {
      return process.exit(1)
    })
    .on('end', function () {
      return process.exit(0)
    })
})

gulp.task('test:e2e:sauceconnect:failsafe', function () {
  var failSafeStream = gulp.src('wdio.failsafe.conf.js')
    .pipe(webdriver(webdriverConfig))
    .on('error', function () {
      console.log('Exiting process with status 1')
      process.exit(1)
    })
    .on('end', function () {
      console.log('Tests complete')
    })
  return failSafeStream
})

// Run end-to-end tests remotely in saucelabs using webdriver configuration
gulp.task('test:e2e:sauceconnect', ['test:e2e:sauceconnect:failsafe'], function () {
  var e2eStream = gulp.src('wdio.sauce.conf.js')
    .pipe(webdriver(webdriverConfig))
    .on('error', function () {
      console.log('Exiting process with status 1')
      process.exit(1)
    })
    .on('end', function () {
      console.log('Tests complete')
    })
  return e2eStream
})

// Launch sauce connect and connect
gulp.task('test:e2e:launchsauceconnect', function (done) {
  var sauceConnectLauncher = require('sauce-connect-launcher')

  var config = {
    username: webdriverConfig.user,
    accessKey: webdriverConfig.key,
    logger: console.log
  }

  var tryConnect = function (maxAttempts, currAttempts, done) {
    sauceConnectLauncher(config, function (err, sauceConnectProcess) {
      if (err) {
        console.error(err.message)
        if (currAttempts <= maxAttempts) {
          console.log('Retrying... (attempt ' + currAttempts + ' of ' + maxAttempts + ')')
          tryConnect(maxAttempts, ++currAttempts, done)
        } else {
          return process.exit(1)
        }
      } else {
        console.log('Sauce Connect ready')
        done()
      }
    })
  }

  tryConnect(3, 1, done)
})

// Serve test application
gulp.task('test:e2e:serve', function () {
  return connect.server({
    root: ['e2e_test', 'src', './'],
    port: 8000,
    livereload: false,
    open: false,
    middleware: function (connect, opt) {
      var middlewares = []
      middlewares.push(connect.favicon())
      return middlewares
    }
  })
})

// Install and start selenium
gulp.task('test:e2e:selenium', function (done) {
  selenium.install({ logger: console.log }, function () {
    selenium.start(function () {
      done()
    })
  })
})

gulp.task('test:e2e:start-local', function (done) {
  runSequence('build', 'build:release', 'test:e2e:serve', 'test:e2e:selenium', function () {
    console.log('All tasks completed.')
  })
})

// Run all required tasks to perform remote end-to-end testing
gulp.task('test:e2e:start-sauce', function (done) {
  runSequence('build', 'test:e2e:launchsauceconnect', function () {
    console.log('All tasks completed.')
  })
})

gulp.task('test:e2e', function (done) {
  runSequence('build', 'test:e2e:serve', 'test:e2e:launchsauceconnect', 'test:e2e:sauceconnect', function () {
    console.log('All tasks completed.')
    done()
    process.exit(0)
  })
})

gulp.task('test:unit:sauce', function (done) {
  runSequence('build', 'test:e2e:launchsauceconnect', 'test', function () {
    console.log('All tasks completed.')
    done()
    process.exit(0)
  })
})

gulp.task('watch:e2e', ['e2e-serve', 'selenium-start'], function (done) {
  gulp.watch(['e2e_test/**'], function () {
    runSequence('test:e2e')
  })
})

gulp.task('default', taskListing)
<|endoftext|>


<commit_before>import {Button} from 'widget/button'
import {Context} from './context'
import PropTypes from 'prop-types'
import React from 'react'
import styles from './toolbar.module.css'

export class ToolbarButton extends React.Component {
    render() {
        const {className, icon, label, tooltip, tooltipDelay, tooltipPlacement, disabled, selected, onClick} = this.props
        return (
            <Context.Consumer>
                {({horizontal, panel}) =>
                    <Button
                        className={[selected && !disabled ? styles.selected : null, panel ? styles.panel : null, className].join(' ')}
                        icon={icon}
                        label={label}
                        disabled={disabled}
                        onClick={e => onClick(e)}
                        tooltip={tooltip}
                        tooltipPlacement={tooltipPlacement || horizontal ? 'top' : 'left'}
                        tooltipDisabled={!!(disabled || (panel && selected))}
                        tooltipDelay={tooltipDelay}
                    />
                }
            </Context.Consumer>
        )
    }
}

ToolbarButton.propTypes = {
    className: PropTypes.string,
    disabled: PropTypes.any,
    icon: PropTypes.string,
    label: PropTypes.string,
    selected: PropTypes.any,
    tooltip: PropTypes.any,
    tooltipDelay: PropTypes.number,
    tooltipPlacement: PropTypes.string,
    onClick: PropTypes.func
}
<commit_msg>Fixed ToolbarButton onClick.<commit_after>import {Button} from 'widget/button'
import {Context} from './context'
import PropTypes from 'prop-types'
import React from 'react'
import styles from './toolbar.module.css'

export class ToolbarButton extends React.Component {
    render() {
        const {className, icon, label, tooltip, tooltipDelay, tooltipPlacement, disabled, selected, onClick} = this.props
        return (
            <Context.Consumer>
                {({horizontal, panel}) =>
                    <Button
                        className={[selected && !disabled ? styles.selected : null, panel ? styles.panel : null, className].join(' ')}
                        icon={icon}
                        label={label}
                        disabled={disabled}
                        onClick={onClick}
                        tooltip={tooltip}
                        tooltipPlacement={tooltipPlacement || horizontal ? 'top' : 'left'}
                        tooltipDisabled={!!(disabled || (panel && selected))}
                        tooltipDelay={tooltipDelay}
                    />
                }
            </Context.Consumer>
        )
    }
}

ToolbarButton.propTypes = {
    className: PropTypes.string,
    disabled: PropTypes.any,
    icon: PropTypes.string,
    label: PropTypes.string,
    selected: PropTypes.any,
    tooltip: PropTypes.any,
    tooltipDelay: PropTypes.number,
    tooltipPlacement: PropTypes.string,
    onClick: PropTypes.func
}
<|endoftext|>


<commit_before>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import React from 'react';
import Link from '@docusaurus/Link';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import useBaseUrl from '@docusaurus/useBaseUrl';
import {Editor, EditorState, RichUtils, getDefaultKeyBinding} from 'draft-js';
import classnames from 'classnames';

import Layout from '@theme/Layout';

import './css/example.css';
import './css/draft.css';
import './css/rich-editor.css';

class RichEditorExample extends React.Component {
  constructor(props) {
    super(props);
    this.state = {editorState: EditorState.createEmpty()};

    this.focus = () => this.editor.focus();
    this.onChange = editorState => this.setState({editorState});

    this.handleKeyCommand = this._handleKeyCommand.bind(this);
    this.mapKeyToEditorCommand = this._mapKeyToEditorCommand.bind(this);
    this.toggleBlockType = this._toggleBlockType.bind(this);
    this.toggleInlineStyle = this._toggleInlineStyle.bind(this);
  }

  _handleKeyCommand(command, editorState) {
    const newState = RichUtils.handleKeyCommand(editorState, command);
    if (newState) {
      this.onChange(newState);
      return true;
    }
    return false;
  }

  _mapKeyToEditorCommand(e) {
    switch (e.keyCode) {
      case 9: // TAB
        const newEditorState = RichUtils.onTab(
          e,
          this.state.editorState,
          4 /* maxDepth */,
        );
        if (newEditorState !== this.state.editorState) {
          this.onChange(newEditorState);
        }
        return;
    }
    return getDefaultKeyBinding(e);
  }

  _toggleBlockType(blockType) {
    this.onChange(RichUtils.toggleBlockType(this.state.editorState, blockType));
  }

  _toggleInlineStyle(inlineStyle) {
    this.onChange(
      RichUtils.toggleInlineStyle(this.state.editorState, inlineStyle),
    );
  }

  render() {
    const {editorState} = this.state;

    // If the user changes block type before entering any text, we can
    // either style the placeholder or hide it. Let's just hide it now.
    let className = 'RichEditor-editor';
    var contentState = editorState.getCurrentContent();
    if (!contentState.hasText()) {
      if (
        contentState
          .getBlockMap()
          .first()
          .getType() !== 'unstyled'
      ) {
        className += ' RichEditor-hidePlaceholder';
      }
    }

    return (

        <BlockStyleControls
          editorState={editorState}
          onToggle={this.toggleBlockType}
        />
        <InlineStyleControls
          editorState={editorState}
          onToggle={this.toggleInlineStyle}
        />

          <Editor
            blockStyleFn={getBlockStyle}
            customStyleMap={styleMap}
            editorState={editorState}
            handleKeyCommand={this.handleKeyCommand}
            keyBindingFn={this.mapKeyToEditorCommand}
            onChange={this.onChange}
            placeholder="Tell a story..."
            ref={ref => (this.editor = ref)}
            spellCheck={true}
          />

    );
  }
}

// Custom overrides for "code" style.
const styleMap = {
  CODE: {
    backgroundColor: 'rgba(0, 0, 0, 0.05)',
    fontFamily: '"Inconsolata", "Menlo", "Consolas", monospace',
    fontSize: 16,
    padding: 2,
  },
};

function getBlockStyle(block) {
  switch (block.getType()) {
    case 'blockquote':
      return 'RichEditor-blockquote';
    default:
      return null;
  }
}

class StyleButton extends React.Component {
  constructor() {
    super();
    this.onToggle = e => {
      e.preventDefault();
      this.props.onToggle(this.props.style);
    };
  }

  render() {
    let className = 'RichEditor-styleButton';
    if (this.props.active) {
      className += ' RichEditor-activeButton';
    }

    return (

        {this.props.label}

    );
  }
}

const BLOCK_TYPES = [
  {label: 'H1', style: 'header-one'},
  {label: 'H2', style: 'header-two'},
  {label: 'H3', style: 'header-three'},
  {label: 'H4', style: 'header-four'},
  {label: 'H5', style: 'header-five'},
  {label: 'H6', style: 'header-six'},
  {label: 'Blockquote', style: 'blockquote'},
  {label: 'UL', style: 'unordered-list-item'},
  {label: 'OL', style: 'ordered-list-item'},
  {label: 'Code Block', style: 'code-block'},
];

const BlockStyleControls = props => {
  const {editorState} = props;
  const selection = editorState.getSelection();
  const blockType = editorState
    .getCurrentContent()
    .getBlockForKey(selection.getStartKey())
    .getType();

  return (

      {BLOCK_TYPES.map(type => (


<commit_before>// @flow
import { push } from "react-router-redux"

type param = { dispatch: Function, getState: Function }

/** Middleware to simplify code and reduce the need for boilerplate in Redux actions.
 * This follows the REQUEST, SUCCESS, FAILURE terminology for action names.
 */

const callAPI = ({ dispatch, getState }: param) => {
  return (next: Function) => async (action: Object) => {
    const { types, url, config } = action

    if (!types || !url) {
      // normal action: pass it on
      return next(action)
    }

    // make sure types matches expected three item array
    if (
      !Array.isArray(types) ||
      types.length !== 3 ||
      !types.every(type => typeof type === "string")
    ) {
      throw new Error("Expected an array of three string types.")
    }

    // helper function to print HTTP errors to console
    // responses are structured in JSONAPI format
    const printError = (res, json) => {
      console.error("HTTP Error")
      console.error(
        `HTTP Response: ${res.status}
      Title: ${json.errors[0].title}
      Detail: ${json.errors[0].detail}`
      )
    }

    const [requestType, successType, failureType] = types

    dispatch({
      type: requestType,
      payload: {
        isFetching: true
      }
    })

    try {
      // make sure POST/PATCH requests have appropriate header with JWT
      if (config.method === "PATCH" || config.method === "POST") {
        config.headers = {
          "Content-Type": "application/json",
          Application: `Bearer: ${getState().auth.token}`
        }
      }
      const res = await fetch(url, config)
      const contentType = res.headers.get("content-type")
      if (contentType && contentType.includes("application/vnd.api+json")) {
        const json = await res.json()
        if (res.ok) {
          switch (successType) {
            case "SAVE_PAGE_SUCCESS":
              // timeout is needed to show changes after action is passed through
              setTimeout(() => {
                dispatch(push(`/information/${json.data.attributes.name}`))
              }, 500)
              break
            // case "SAVE_INLINE_PAGE_SUCCESS":
            //   setTimeout(() => {
            //     window.location.reload()
            //   }, 500)
            //   break
            default:
              return next({
                type: successType,
                payload: {
                  isFetching: false,
                  json
                }
              })
          }
        } else {
          // print console errors if in development mode
          if (process.env.NODE_ENV !== "production") {
            printError(res, json)
          }
          // dispatch(push("/error"))
          return next({
            type: failureType,
            payload: {
              error: json.errors[0].title
            }
          })
        }
      } else {
        // dispatch(push("/error"))
        return next({
          type: failureType,
          payload: {
            error: res.body
          }
        })
      }
    } catch (error) {
      if (process.env.NODE_ENV !== "production") {
        console.error(`Network error: ${error.message}`)
      }
      // dispatch(push("/error"))
      return next({
        type: failureType,
        payload: {
          error: error.toString()
        }
      })
    }
  }
}

export default callAPI
<commit_msg>add error messages to UI<commit_after>// @flow
import { push } from "react-router-redux"

type param = { dispatch: Function, getState: Function }

/** Middleware to simplify code and reduce the need for boilerplate in Redux actions.
 * This follows the REQUEST, SUCCESS, FAILURE terminology for action names.
 */

const callAPI = ({ dispatch, getState }: param) => {
  return (next: Function) => async (action: Object) => {
    const { types, url, config } = action

    if (!types || !url) {
      // normal action: pass it on
      return next(action)
    }

    // make sure types matches expected three item array
    if (
      !Array.isArray(types) ||
      types.length !== 3 ||
      !types.every(type => typeof type === "string")
    ) {
      throw new Error("Expected an array of three string types.")
    }

    // helper function to print HTTP errors to console
    // responses are structured in JSONAPI format
    const printError = (res, json) => {
      console.error("HTTP Error")
      console.error(
        `HTTP Response: ${res.status}
      Title: ${json.errors[0].title}
      Detail: ${json.errors[0].detail}`,
      )
    }

    const [requestType, successType, failureType] = types

    dispatch({
      type: requestType,
      payload: {
        isFetching: true,
      },
    })

    try {
      // make sure POST/PATCH requests have appropriate header with JWT
      if (config.method === "PATCH" || config.method === "POST") {
        config.headers = {
          "Content-Type": "application/json",
          Application: `Bearer: ${getState().auth.token}`,
        }
      }
      const res = await fetch(url, config)
      const contentType = res.headers.get("content-type")
      if (contentType && contentType.includes("application/vnd.api+json")) {
        const json = await res.json()
        if (res.ok) {
          switch (successType) {
            case "SAVE_PAGE_SUCCESS":
              // timeout is needed to show changes after action is passed through
              setTimeout(() => {
                dispatch(push(`/information/${json.data.attributes.name}`))
              }, 500)
              break
            // case "SAVE_INLINE_PAGE_SUCCESS":
            //   setTimeout(() => {
            //     window.location.reload()
            //   }, 500)
            //   break
            default:
              return next({
                type: successType,
                payload: {
                  isFetching: false,
                  json,
                },
              })
          }
        } else {
          // print console errors if in development mode
          if (process.env.NODE_ENV !== "production") {
            printError(res, json)
          }
          dispatch(push("/error"))
          return next({
            type: failureType,
            payload: {
              error: json.errors[0].title,
            },
          })
        }
      } else {
        dispatch(push("/error"))
        return next({
          type: failureType,
          payload: {
            error: res.body,
          },
        })
      }
    } catch (error) {
      if (process.env.NODE_ENV !== "production") {
        console.error(`Network error: ${error.message}`)
      }
      dispatch(push("/error"))
      return next({
        type: failureType,
        payload: {
          error: error.toString(),
        },
      })
    }
  }
}

export default callAPI
<|endoftext|>


<commit_before>/*
 * Source:
 * http://github.com/funkatron/spazcore/blob/0e9fec769b3f9f3edd7f217bf8085bea67b51b6c/incubator/libs/spazmenu.js
 *
 * Added a conditional to avoid overwriting the function if it exists.
 */

/**
 * A class for dynamically generating menus.
 *
 * hash structure:
 * var hash = [
 * 	{
 * 		'label':"Menu label",
 * 		'id':"a_unique_id", // optional, not used if not present
 * 		'class':"menu_label", // optional, generated if not present
 * 		'handler':function(e, data) {}, // a handler. will be listening via delegation
 * 		'data':{} // some data, passed as second param to onClick handler
 * 		}
 *
 * ];
 *
 *
 * @param {object} trigger_event the event that is triggering the creation of this menu. needed for positioning
 *
 * @param {object} opts options
 *
 * @param {array}  opts.items_func a function that generates a hash of item objects. takes one parameter "data"
 * @param {string} [opts.base_id] the id attribute for the menu's base element. default is 'spaz_menu'
 * @param {string} [opts.base_class] the class attribute for the menu's base element. default is 'spaz_menu'
 * @param {string} [opts.li_class] the class attribute for the menu's base element. default is 'spaz_menu_li'
 * @param {string} [opts.show_immediately] whether or not to immediately show the menu on creation. Default is TRUE
 * @param {string} [opts.close_on_any_click] whether or not to close the menu when anything is clicked. Default is TRUE
 */

if(typeof SpazMenu === 'undefined' || !SpazMenu){

SpazMenu = function(opts) {
	this.opts = sch.defaults({
		'items_func':function(data){ return null; },
		'base_id'   :'spaz_menu',
		'base_class':'spaz_menu',
		'li_class'  :'spaz_menu_li',
		'show_immediately':  true,
		'close_on_any_click':true
	}, opts);

	// close on ANY clicks
	if(this.opts.close_on_any_click){
		jQuery(document).bind('click', {'spazmenu':this}, this.hide);
	}

	/**
	 * dismiss with escape
	 */
	jQuery(document).bind('keydown', {'spazmenu':this}, this.keypressHide);

	// just in case, we need to destroy any existing menus before creating new ones
	// with the same settings
	jQuery('div.'+this.opts.base_class).remove();
};

/**
 * Creates the menu, but doesn't show
 * @param {object} trigger_event the event that triggered the show
 * @param {object} itemsdata a data structure that will be passed to the items_func
 * @param {object} [showOpts.position] {left: <number>, top: <number>} position at which to show the menu. Defaults to trigger_event coordinates.
 */
SpazMenu.prototype.show = function(trigger_event, itemsdata, showOpts) {
	sch.debug('creating');

	var that = this;

	if(!showOpts){ showOpts = {}; }

	// map the triggering event
	this.trigger_event = trigger_event;

	// create items with items_func
	this.items = this.opts.items_func(itemsdata);

 	// create base DOM elements
	if (jQuery('#'+this.opts.base_id).length < 1) {
		jQuery('body').append(this._tplBase());
	} else { // if exists, empty it
		jQuery('#'+this.opts.base_id + ' ul').empty();
	}

	// iterate over items
	var item, itemhtml = '';
	for (var i=0; i < this.items.length; i++) {
		item = this.items[i];
		if (!item['class']) {
			item['class'] = this._generateItemClass(item);
		}

		// create the item HTML
		itemhtml = this._tplItem(item);

		// -- add item DOM element
		jQuery('#'+this.opts.base_id + ' ul').append(itemhtml);

		// -- remove any existing handlers (in case this menu was shown before)
		jQuery('#'+this.opts.base_id + ' ul').undelegate('.'+item['class'], 'click');

		// -- add delegated handler
		jQuery('#'+this.opts.base_id + ' ul').delegate('.'+item['class'], 'click', {'item':item, 'spazmenu':this}, function(e, data) {
			e.data.item.handler.call(this, e, e.data.item.data||itemsdata);
			that.hide();
		});
	}

	sch.debug('show');

	showOpts.position = jQuery.extend({
		left: trigger_event.clientX,
		top:  trigger_event.clientY
	}, showOpts.position);

	this._positionBeforeShow({
		// Filter out any stray properties aside from these:
		left: showOpts.position.left,
		top:  showOpts.position.top
	});
	jQuery('#' + this.opts.base_id).show();
	this._reposition(trigger_event);
};

/**
 * hides a created menu
 */
SpazMenu.prototype.hide = function(e) {
	sch.debug('hide');
	var that;

	if (e && e.data && e.data.spazmenu) {
		that = e.data.spazmenu;
	} else {
		that = this;
	}

	jQuery('#'+that.opts.base_id).hide();
};

/**
 * handler if esc is hit
 */
SpazMenu.prototype.keypressHide = function(e) {
	if (e.keyCode == 27) {
		e.data.spazmenu.hide();
	} // escape
};

/**
 * destroys a menu completely (DOM and JS object)
 */
SpazMenu.prototype.destroy = function() {
	sch.debug('destroy');

	// close on ANY clicks
	if(this.opts.close_on_any_click){
		jQuery(document).unbind('click', {'spazmenu':this}, this.hide);
	}

	jQuery(document).unbind('keydown', {'spazmenu':this}, this.keypressHide);

	// remove base DOM element
	jQuery('#'+this.opts.base_id).remove();
};

/**
 * hides AND destroys
 */
SpazMenu.prototype.hideAndDestroy = function(e) {

	if (this.hide && this.destroy) {
		this.hide();
		this.destroy();
	} else if (e && e.data && e.data.spazmenu) {
		e.data.spazmenu.hide();
		e.data.spazmenu.destroy();
	} else {
		sch.error('couldn\'t hide and destroy');
	}
};

/**
 * sets the position of the menu right before we show it
 * @param {object} position {left: <number>, top: <number>}
 */
SpazMenu.prototype._positionBeforeShow = function(position) {
	sch.debug('_positionBeforeShow');
	jQuery('#' + this.opts.base_id).css(position);
};

/**
 * Repositions the menu after showing in case we're outside the viewport boundaries
 */
SpazMenu.prototype._reposition = function(e, data) {
	sch.debug('_reposition');

	var jqMenu          = jQuery('#' + this.opts.base_id),
	    viewportWidth   = jQuery(window).width(),
	    menuWidth       = jqMenu.width(),
	    menuMarginRight = parseInt(jqMenu.css('margin-right'), 10),
	    menuOffset      = jqMenu.offset();

	if(menuOffset.left + menuWidth + menuMarginRight > viewportWidth){
		jqMenu.offset(function(i, offset){
			return {
				left: viewportWidth - menuWidth - menuMarginRight,
				top:  offset.top
			};
		});
	}
};

/**
 * this generates the item class if one has not been provided
 */
SpazMenu.prototype._generateItemClass = function(item) {
	return item.label.replace(/[^a-z]/gi, '_').toLowerCase();
};

/**
 * generates the html for the base DOM elements
 */
SpazMenu.prototype._tplBase = function() {

	var html = '';

	html += '
';
	html += '
';
	html += '
';
	html += '
';

	sch.debug(html);

	return html;
};

/**
 * generates the HTML for a menu item
 * @param {object} i the item object
 */
SpazMenu.prototype._tplItem = function(i) {
	var html = '';

	html += '
'+i.label+'
';

	sch.debug(html);

	return html;
};

}
<commit_msg>SpazMenu patch: Added `rebuild` option to allow/disallow rebuilding menu items on show<commit_after>/*
 * Source:
 * http://github.com/funkatron/spazcore/blob/0e9fec769b3f9f3edd7f217bf8085bea67b51b6c/incubator/libs/spazmenu.js
 *
 * Added a conditional to avoid overwriting the function if it exists.
 */

/**
 * A class for dynamically generating menus.
 *
 * hash structure:
 * var hash = [
 * 	{
 * 		'label':"Menu label",
 * 		'id':"a_unique_id", // optional, not used if not present
 * 		'class':"menu_label", // optional, generated if not present
 * 		'handler':function(e, data) {}, // a handler. will be listening via delegation
 * 		'data':{} // some data, passed as second param to onClick handler
 * 		}
 *
 * ];
 *
 *
 * @param {object} trigger_event the event that is triggering the creation of this menu. needed for positioning
 *
 * @param {object} opts options
 *
 * @param {array}  opts.items_func a function that generates a hash of item objects. takes one parameter "data"
 * @param {string} [opts.base_id] the id attribute for the menu's base element. default is 'spaz_menu'
 * @param {string} [opts.base_class] the class attribute for the menu's base element. default is 'spaz_menu'
 * @param {string} [opts.li_class] the class attribute for the menu's base element. default is 'spaz_menu_li'
 * @param {string} [opts.show_immediately] whether or not to immediately show the menu on creation. Default is TRUE
 * @param {string} [opts.close_on_any_click] whether or not to close the menu when anything is clicked. Default is TRUE
 */

if(typeof SpazMenu === 'undefined' || !SpazMenu){

SpazMenu = function(opts) {
	this.opts = sch.defaults({
		'items_func':function(data){ return null; },
		'base_id'   :'spaz_menu',
		'base_class':'spaz_menu',
		'li_class'  :'spaz_menu_li',
		'show_immediately':  true,
		'close_on_any_click':true
	}, opts);

	// close on ANY clicks
	if(this.opts.close_on_any_click){
		jQuery(document).bind('click', {'spazmenu':this}, this.hide);
	}

	/**
	 * dismiss with escape
	 */
	jQuery(document).bind('keydown', {'spazmenu':this}, this.keypressHide);

	// just in case, we need to destroy any existing menus before creating new ones
	// with the same settings
	jQuery('div.'+this.opts.base_class).remove();
};

/**
 * Creates the menu, but doesn't show
 * @param {object} trigger_event the event that triggered the show
 * @param {object} itemsdata a data structure that will be passed to the items_func
 * @param {object} [showOpts.position] {left: <number>, top: <number>} position at which to show the menu. Defaults to trigger_event coordinates.
 * @param {object} [showOpts.rebuild] whether to rebuild the menu contents if the menu already exists. Defaults to false.
 */
SpazMenu.prototype.show = function(trigger_event, itemsdata, showOpts) {
	sch.debug('creating');

	var that = this;

	showOpts = sch.defaults({
		rebuild: false
	}, showOpts);

	// map the triggering event
	this.trigger_event = trigger_event;

	// create items with items_func
	this.items = this.opts.items_func(itemsdata);

 	// create base DOM elements
	if (jQuery('#'+this.opts.base_id).length < 1) {
		jQuery('body').append(this._tplBase());
	} else if(showOpts.rebuild) { // if exists, empty it
		jQuery('#'+this.opts.base_id + ' ul').empty();
	}

	// iterate over items
	var item, itemhtml = '';
	if(showOpts.rebuild || !jQuery('#' + this.opts.base_id + ' ul li')[0]){
		for (var i=0; i < this.items.length; i++) {
			item = this.items[i];
			if (!item['class']) {
				item['class'] = this._generateItemClass(item);
			}

			// create the item HTML
			itemhtml = this._tplItem(item);

			// -- add item DOM element
			jQuery('#'+this.opts.base_id + ' ul').append(itemhtml);

			// -- remove any existing handlers (in case this menu was shown before)
			jQuery('#'+this.opts.base_id + ' ul').undelegate('.'+item['class'], 'click');

			// -- add delegated handler
			jQuery('#'+this.opts.base_id + ' ul').delegate('.'+item['class'], 'click', {'item':item, 'spazmenu':this}, function(e, data) {
				e.data.item.handler.call(this, e, e.data.item.data||itemsdata);
				that.hide();
			});
		}
	}

	sch.debug('show');

	showOpts.position = jQuery.extend({
		left: trigger_event.clientX,
		top:  trigger_event.clientY
	}, showOpts.position);

	this._positionBeforeShow({
		// Filter out any stray properties aside from these:
		left: showOpts.position.left,
		top:  showOpts.position.top
	});
	jQuery('#' + this.opts.base_id).show();
	this._reposition(trigger_event);
};

/**
 * hides a created menu
 */
SpazMenu.prototype.hide = function(e) {
	sch.debug('hide');
	var that;

	if (e && e.data && e.data.spazmenu) {
		that = e.data.spazmenu;
	} else {
		that = this;
	}

	jQuery('#'+that.opts.base_id).hide();
};

/**
 * handler if esc is hit
 */
SpazMenu.prototype.keypressHide = function(e) {
	if (e.keyCode == 27) {
		e.data.spazmenu.hide();
	} // escape
};

/**
 * destroys a menu completely (DOM and JS object)
 */
SpazMenu.prototype.destroy = function() {
	sch.debug('destroy');

	// close on ANY clicks
	if(this.opts.close_on_any_click){
		jQuery(document).unbind('click', {'spazmenu':this}, this.hide);
	}

	jQuery(document).unbind('keydown', {'spazmenu':this}, this.keypressHide);

	// remove base DOM element
	jQuery('#'+this.opts.base_id).remove();
};

/**
 * hides AND destroys
 */
SpazMenu.prototype.hideAndDestroy = function(e) {

	if (this.hide && this.destroy) {
		this.hide();
		this.destroy();
	} else if (e && e.data && e.data.spazmenu) {
		e.data.spazmenu.hide();
		e.data.spazmenu.destroy();
	} else {
		sch.error('couldn\'t hide and destroy');
	}
};

/**
 * sets the position of the menu right before we show it
 * @param {object} position {left: <number>, top: <number>}
 */
SpazMenu.prototype._positionBeforeShow = function(position) {
	sch.debug('_positionBeforeShow');
	jQuery('#' + this.opts.base_id).css(position);
};

/**
 * Repositions the menu after showing in case we're outside the viewport boundaries
 */
SpazMenu.prototype._reposition = function(e, data) {
	sch.debug('_reposition');

	var jqMenu          = jQuery('#' + this.opts.base_id),
	    viewportWidth   = jQuery(window).width(),
	    menuWidth       = jqMenu.width(),
	    menuMarginRight = parseInt(jqMenu.css('margin-right'), 10),
	    menuOffset      = jqMenu.offset();

	if(menuOffset.left + menuWidth + menuMarginRight > viewportWidth){
		jqMenu.offset(function(i, offset){
			return {
				left: viewportWidth - menuWidth - menuMarginRight,
				top:  offset.top
			};
		});
	}
};

/**
 * this generates the item class if one has not been provided
 */
SpazMenu.prototype._generateItemClass = function(item) {
	return item.label.replace(/[^a-z]/gi, '_').toLowerCase();
};

/**
 * generates the html for the base DOM elements
 */
SpazMenu.prototype._tplBase = function() {

	var html = '';

	html += '
';
	html += '
';
	html += '
';
	html += '
';

	sch.debug(html);

	return html;
};

/**
 * generates the HTML for a menu item
 * @param {object} i the item object
 */
SpazMenu.prototype._tplItem = function(i) {
	var html = '';

	html += '
'+i.label+'
';

	sch.debug(html);

	return html;
};

}
<|endoftext|>


<commit_before>var neolao          = require('./index'),
    express         = require('express'),
    http            = require('http'),
    mustache        = require('hogan-express'),
    Request         = require('./site/Request');

/**
 * Site
 *
 * @class       neolao/Site
 */
module.exports = function()
{
    this._express = express();
};
proto = module.exports.prototype;

/**
 * Middleware Express
 *
 * @type    express
 */
proto._express = null;

/**
 * Server port
 *
 * @type    Integer
 */
proto._serverPort = null;

/**
 * Server name
 *
 * @type    String
 */
proto._serverName = null;

/**
 * Controllers path
 *
 * @type    String
 */
proto._controllersPath = null;

/**
 * Views path
 *
 * @type    String
 */
proto._viewsPath = null;

/**
 * Public path
 *
 * @type    String
 */
proto._publicPath = null;

/**
 * Get the representation string
 *
 * @return  String          The representation string
 */
proto.toString = function()
{
    return '[neolao/Site]';
};

/**
 * Server port
 *
 * @type    Integer
 */
Object.defineProperty(proto, 'serverPort',
{
    get: function()
    {
        return this._serverPort;
    },
    set: function(port)
    {
        this._serverPort = port;
        this._express.set('port', this._serverPort);
    }
});

/**
 * Server name
 *
 * @type    String
 */
Object.defineProperty(proto, 'serverName',
{
    get: function()
    {
        return this._serverName;
    },
    set: function(name)
    {
        this._serverName = name;
    }
});

/**
 * Controllers path
 *
 * @type    String
 */
Object.defineProperty(proto, 'controllersPath',
{
    get: function()
    {
        return this._controllersPath;
    },
    set: function(path)
    {
        this._controllersPath = path;
    }
});

/**
 * Views path
 *
 * @type    String
 */
Object.defineProperty(proto, 'viewsPath',
{
    get: function()
    {
        return this._viewsPath;
    },
    set: function(path)
    {
        this._viewsPath = path;
        this._express.set('views', this._viewsPath);
    }
});

/**
 * Public  path
 *
 * @type    String
 */
Object.defineProperty(proto, 'publicPath',
{
    get: function()
    {
        return this._publicPath;
    },
    set: function(path)
    {
        this._publicPath = path;
        this._express.use(express.static(this._publicPath));
    }
});

/**
 * Configure the routes
 *
 * @param   Object      routes      Routes configuration
 */
proto.configureRoutes = function(routes)
{
    var self = this,
        route, routeName, routeHandler;

    routeHandler = function(route)
    {
        var routePattern    = route.pattern,
            routeController = route.controller,
            routeAction     = route.action,
            routeReverse    = route.reverse,
            routePath;

        if (routePattern === undefined) {
            routePath = '*';
        } else {
            routePath = eval(routePattern);
        }

        self._express.get(routePath, function(serverRequest, serverResponse)
        {
            var ControllerClass = require(self._controllersPath+'/'+routeController),
                controller      = new ControllerClass(),
                request         = new Request();

            request.serverRequest   = serverRequest;
            request.action          = routeAction;
            controller.response     = serverResponse;
            controller.dispatch(request);
        });
    };
    for (routeName in routes) {
        route = routes[routeName];
        routeHandler(route);
    }
};

/**
 * Run the site
 */
proto.run = function()
{
    var self = this;

    // Initialize the views
    this._express.engine('mustache', mustache);
    this._express.set('view engine', 'mustache');
    this._express.set('partials', {
        _header: '_header',
        _footer: '_footer'
    });

    //application.use(express.favicon());
    //application.use(express.logger('dev'));
    //application.use(express.bodyParser());
    //application.use(express.methodOverride());
    //application.use(application.router);

    // Error handler
    this._express.configure('development', function()
    {
        self._express.use(express.errorHandler());
    });

    // Run the server
    http.createServer(this._express).listen(this._express.get('port'), function()
    {
        console.log("Server listening on port " + self._express.get('port'));
    });

};

<commit_msg>The site accepts view and controller helpers<commit_after>var neolao          = require('./index'),
    express         = require('express'),
    http            = require('http'),
    mustache        = require('hogan-express'),
    Request         = require('./site/Request');

/**
 * Site
 *
 * @class       neolao/Site
 */
module.exports = function()
{
    // Initialize the properties
    this._controllerHelpers = [];
    this._viewHelpers = [];

    // Initialize Express
    this._express = express();
};
proto = module.exports.prototype;

/**
 * Middleware Express
 *
 * @type    express
 */
proto._express = null;

/**
 * Server port
 *
 * @type    Integer
 */
proto._serverPort = null;

/**
 * Server name
 *
 * @type    String
 */
proto._serverName = null;

/**
 * Controllers path
 *
 * @type    String
 */
proto._controllersPath = null;

/**
 * Views path
 *
 * @type    String
 */
proto._viewsPath = null;

/**
 * Public path
 *
 * @type    String
 */
proto._publicPath = null;

/**
 * Controller helpers
 *
 * @type    Array
 */
proto._controllerHelpers = null;

/**
 * View helpers
 *
 * @type    Array
 */
proto._viewHelpers = null;

/**
 * Get the representation string
 *
 * @return  String          The representation string
 */
proto.toString = function()
{
    return '[neolao/Site]';
};

/**
 * Server port
 *
 * @type    Integer
 */
Object.defineProperty(proto, 'serverPort',
{
    get: function()
    {
        return this._serverPort;
    },
    set: function(port)
    {
        this._serverPort = port;
        this._express.set('port', this._serverPort);
    }
});

/**
 * Server name
 *
 * @type    String
 */
Object.defineProperty(proto, 'serverName',
{
    get: function()
    {
        return this._serverName;
    },
    set: function(name)
    {
        this._serverName = name;
    }
});

/**
 * Controllers path
 *
 * @type    String
 */
Object.defineProperty(proto, 'controllersPath',
{
    get: function()
    {
        return this._controllersPath;
    },
    set: function(path)
    {
        this._controllersPath = path;
    }
});

/**
 * Views path
 *
 * @type    String
 */
Object.defineProperty(proto, 'viewsPath',
{
    get: function()
    {
        return this._viewsPath;
    },
    set: function(path)
    {
        this._viewsPath = path;
        this._express.set('views', this._viewsPath);
    }
});

/**
 * Public  path
 *
 * @type    String
 */
Object.defineProperty(proto, 'publicPath',
{
    get: function()
    {
        return this._publicPath;
    },
    set: function(path)
    {
        this._publicPath = path;
        this._express.use(express.static(this._publicPath));
    }
});

/**
 * Configure the routes
 *
 * @param   Object      routes      Routes configuration
 */
proto.configureRoutes = function(routes)
{
    var self = this,
        route, routeName, routeHandler;

    routeHandler = function(route)
    {
        var routePattern    = route.pattern,
            routeController = route.controller,
            routeAction     = route.action,
            routeReverse    = route.reverse,
            routePath;

        if (routePattern === undefined) {
            routePath = '*';
        } else {
            routePath = eval(routePattern);
        }

        self._express.get(routePath, function(serverRequest, serverResponse)
        {
            var ControllerClass = require(self._controllersPath+'/'+routeController),
                controller      = new ControllerClass(),
                request         = new Request();

            request.serverRequest   = serverRequest;
            request.action          = routeAction;
            controller.response     = serverResponse;
            controller.dispatch(request);
        });
    };
    for (routeName in routes) {
        route = routes[routeName];
        routeHandler(route);
    }
};

/**
 * Add a controller helper
 *
 * @param   neolao/site/helper/controller/AbstractHelper    helper      Helper instance
 */
proto.addControllerHelper = function(helper)
{
    this._controllerHelpers.push(helper);
};

/**
 * Add a view helper
 *
 * @param   neolao/site/helper/view/AbstractHelper          helper      Helper instance
 */
proto.addViewHelper = function(helper)
{
    this._viewHelpers.push(helper);
};

/**
 * Run the site
 */
proto.run = function()
{
    var self = this;

    // Initialize the views
    this._express.engine('mustache', mustache);
    this._express.set('view engine', 'mustache');
    this._express.set('partials', {
        _header: '_header',
        _footer: '_footer'
    });

    //application.use(express.favicon());
    //application.use(express.logger('dev'));
    //application.use(express.bodyParser());
    //application.use(express.methodOverride());
    //application.use(application.router);

    // Error handler
    this._express.configure('development', function()
    {
        self._express.use(express.errorHandler());
    });

    // Run the server
    http.createServer(this._express).listen(this._express.get('port'), function()
    {
        console.log("Server listening on port " + self._express.get('port'));
    });

};

<|endoftext|>