<commit_before>on('ready', function() {
    if (!_.has(state, 'Supernotes')) {
        state.Supernotes = {
            sheet: 'Default',
            template: 'default',
            title: 'name',
            theText: '',
            sendToPlayers: true

        };
        message = 'Welcome to Supernotes! If this is your first time running it, the script is set to use the Default Roll Template. You can choose a different sheet template below, as well as decide whether you want the script to display a "Send to Players" footer at the end of every GM message. It is currently set to true.

[Default Template - any sheet](!gmnote --config|default)
[D&D 5th Edition by Roll20](!gmnote --config|dnd5e)
[DnD 5e Shaped](!gmnote --config|5eshaped)
[Pathfinder by Roll20](!gmnote --config|pfofficial)
[Pathfinder Community](!gmnote --config|pfcommunity)
[Pathfinder 2e by Roll20](!gmnote --config|pf2e)
[Starfinder by Roll20](!gmnote --config|starfinder)

[Toggle Send to Players](!gmnote --config|sendtoPlayers)';
        sendChat('Supernotes', '/w gm &{template:' + state.Supernotes.template + '}{{' + state.Supernotes.title + '=' + 'Config' + '}} {{' + state.Supernotes.theText + '=' + message + '}}');
    }
});

on('ready', () => {

    const decodeUnicode = (str) => str.replace(/%u[0-9a-fA-F]{2,4}/g, (m) => String.fromCharCode(parseInt(m.slice(2), 16)));

    const version = '0.0.8';
    log('Supernotes v' + version + ' is ready!  To set the template of choice or to toggle the send to players option, Use the command !gmnote --config');

    on('chat:message', function(msg) {
        if ('api' === msg.type && msg.content.match(/^!(gm|pc|self)note\b/)) {
            let match = msg.content.match(/^!gmnote-(.*)$/);

            //define command
            let command = msg.content.split(/\s+--/)[0];
let sender = msg.who
log(sender);
            let messagePrefix = '/w gm ';
            if (command === '!pcnote') {
                messagePrefix = '';
            }

           if (command === '!selfnote') {
                messagePrefix = '/w '+sender + ' ';
            }

            //define option
            let option = msg.content.split(/\s+--/)[1];
            let secondOption = msg.content.split(/\s+--/)[2];
            if (option === 'notitle'){
                option = secondOption;
                secondOption = 'notitle';}

            const template = state.Supernotes.template;
            const title = state.Supernotes.title;
            const theText = state.Supernotes.theText;
            const sendToPlayers = state.Supernotes.sendToPlayers;

 if (option !== undefined && option.includes('config')) {
                let templateChoice = option.split('|')[1]

                if (templateChoice === undefined) {
                    message = 'Current sheet template:
' + state.Supernotes.sheet + '
Send to Players:
' + state.Supernotes.sendToPlayers + '

Choose a template for Supernotes to use.

[Default Template - any sheet](!gmnote --config|default)
[D&D 5th Edition by Roll20](!gmnote --config|dnd5e)
[DnD 5e Shaped](!gmnote --config|5eshaped)
[Pathfinder Community](!gmnote --config|pfcommunity)
[Pathfinder by Roll20](!gmnote --config|pfofficial)
[Pathfinder 2e by Roll20](!gmnote --config|pf2e)
[Starfinder by Roll20](!gmnote --config|starfinder)

[Toggle Send to Players](!gmnote --config|sendtoPlayers)'
                    sendChat('Supernotes', messagePrefix + '&{template:' + template + '}{{' + title + '=' + 'Config' + '}} {{' + theText + '=' + message + '}}');
                }

                switch (templateChoice) {
                    case 'default':
                        state.Supernotes.sheet = 'Default';
                        state.Supernotes.template = 'default';
                        state.Supernotes.title = 'name';
                        state.Supernotes.theText = '';
                        sendChat('Supernotes', '/w gm Supernotes set to Default roll template');
                        break;
                    case 'dnd5e':
                        state.Supernotes.sheet = 'D&D 5th Edition by Roll20';
                        state.Supernotes.template = 'npcaction';
                        state.Supernotes.title = 'rname';
                        state.Supernotes.theText = 'description';
                        sendChat('Supernotes', '/w gm Supernotes set to ' + state.Supernotes.sheet);
                        break;
                    case '5eshaped':
                        state.Supernotes.sheet = 'DnD 5e Shaped';
                        state.Supernotes.template = '5e-shaped';
                        state.Supernotes.title = 'title';
                        state.Supernotes.theText = 'text_big';
                        sendChat('Supernotes', '/w gm Supernotes set to ' + state.Supernotes.sheet);
                        break;
                    case 'pfcommunity':
                        state.Supernotes.sheet = 'Pathfinder Community';
                        state.Supernotes.template = 'pf_generic';
                        state.Supernotes.title = 'name';
                        state.Supernotes.theText = 'description';
                        sendChat('Supernotes', '/w gm Supernotes set to ' + state.Supernotes.sheet);
                        break;
                    case 'pfofficial':
                        state.Supernotes.sheet = 'Pathfinder by Roll20';
                        state.Supernotes.template = 'npc';
                        state.Supernotes.title = 'name';
                        state.Supernotes.theText = 'descflag=1}} {{desc';
                        sendChat('Supernotes', '/w gm Supernotes set to ' + state.Supernotes.sheet);
                        break;
                    case 'pf2e':
                        state.Supernotes.sheet = 'Pathefinder 2e';
                        state.Supernotes.template = 'rolls';
                        state.Supernotes.title = 'header';
                        state.Supernotes.theText = 'notes_show=[[1]]}} {{notes';
                        sendChat('Supernotes', '/w gm Supernotes set to ' + state.Supernotes.sheet);
                        break;
                    case 'starfinder':
                        state.Supernotes.sheet = 'Starfinder';
                        state.Supernotes.template = 'sf_generic';
                        state.Supernotes.title = 'title';
                        state.Supernotes.theText = 'buttons0';
                        sendChat('Supernotes', '/w gm Supernotes set to ' + state.Supernotes.sheet);
                        break;
                    case 'sendtoPlayers':
                        if (state.Supernotes.sendToPlayers) {
                            state.Supernotes.sendToPlayers = false
                        } else {
                            state.Supernotes.sendToPlayers = true
                        };
                        sendChat('Supernotes', '/w gm Send to Players set to ' + state.Supernotes.sendToPlayers);
                        break;
                }
            } else {
                if (option !== undefined && option.includes('help')) {
                    message = 'Supernotes pulls the contents from a token's GM Notes field. If the token represents a character, you can optionally pull in the Bio or GM notes from the character, as well as the avatar, or extract just the image from the bio field. The user can decide whether to whisper the notes to the GM or broadcast them to all players. Finally, there is the option to add a footer to notes whispered to the GM. This footer creates a chat button to give the option of sending the notes on to the players.
This script as written is optimized for the D&D 5th Edition by Roll20 sheet, but can be adapted easily suing the Configuration section below.

Commands:
!gmnote whispers the note to the GM
!pcnote sends the note to all players

Paramaters

--token Pulls notes from the selected token's gm notes field. This is optional. If it is missing, the script assumes --token

--charnote Pulls notes from the gm notes field of the character assigned to a token.

--bio Pulls notes from the bio field of the character assigned to a token.

--avatar Pulls the image from the avatar field of the character assigned to a token.

--image Pulls first image from the bio field of the character assigned to a token, if any exists. Otherwise returns notice that no artwork is available

--images Pulls all images from the bio field of the character assigned to a token, if any exist. Otherwise returns notice that no artwork is available

--image[number] Pulls indexed image from the bio field of the character assigned to a token, if any exist. --image1 will pull the first image, --image2 the second and so on. Otherwise returns first image if available. If no images are available, returns notice that no artwork is available.

--help Displays help.

--config Returns a configuration dialog box that allows you to set which sheet's roll template to use, and to toggle the "Send to Players" footer.

Configuration
When first installed, Supernotes is configured for the default roll template. It will display a config dialog box at startup that will allow you to choose a roll template based on your character sheet of choice, as well as the option  to toggle whether you want the "Send to Players" footer button to appear.
You will need to edit the code of the script to create a custom configuration. The pre-installed sheets are:

Default Template
D&D 5th Edition by Roll20
5e Shaped
Pathfinder by Roll20
Pathfinder Community
Pathfinder 2e by Roll20
Starfinder
';
                    sendChat('Supernotes', messagePrefix + '&{template:' + template + '}{{' + title + '=' + 'Supernotes Help' + '}} {{' + theText + '=' + message + '}}');

                } else {
                    if (!(option + '').match(/^(bio|charnote|avatar|imag(e|es|e[1-9]))/)) {
                        option = 'token';
                    }

                    let playerButton = '';
                    if (sendToPlayers && (command === '!gmnote'||command ===  '!selfnote')) {
                        playerButton = '\n[Send to Players](!pcnote --' + option + ')';
                    }

                    let regex;
                    if (match && match[1]) {
                        regex = new RegExp(`^${match[1]}`, 'i');
                    }

                    let message = '';
                    let whom = '';

                    if (option === 'avatar') {
                        (msg.selected || [])
                        .map(o => getObj('graphic', o._id))
                            .filter(g => undefined !== g)
                            .map(t => getObj('character', t.get('represents')))
                            .filter(c => undefined !== c)
                            .forEach(c => {
                                message = "";
                                whom = c.get('name');
                                            if (secondOption === 'notitle'){whom = '';}
                                sendChat(whom, messagePrefix + '&{template:' + template + '}{{' + title + '=' + whom + '}} {{' + theText + '=' + message + playerButton + '}}');
                            });
                    } else {

                        if (option.match(/^imag(e|es|e[1-9])/)) {

                            (msg.selected || [])
                            .map(o => getObj('graphic', o._id))
                                .filter(g => undefined !== g)
                                .map(t => getObj('character', t.get('represents')))
                                .filter(c => undefined !== c)
                                .forEach(c => c.get('bio', (val) => {
                                    if (null !== val && 'null' !== val && val.length > 0) {
                                        if (regex) {
                                            message = _.filter(
                                                decodeUnicode(val).split(/(?:[\n\r]+|
)/),
                                                (l) => regex.test(l.replace(/<[^>]*>/g, ''))
                                            ).join('\r');
                                        } else {
                                            message = decodeUnicode(val);
                                        }
                                        if (option === "images") {
                                            artwork = message.match(/\/g)
                                        } else {
                                            artwork = message.match(/\/g);
                                            artwork = String(artwork);

                                            imageIndex = option.match(/\d+/g);

                                            if (isNaN(imageIndex) || !imageIndex) {
                                                imageIndex = 1
                                            }

                                            if (imageIndex > (artwork.split(",")).length) {
                                                imageIndex = 1
                                            }

                                            imageIndex = imageIndex - 1; //corrects from human readable

                                            artwork = artwork.split(",")[imageIndex];

                                        }
                                        log("artwork string =" + artwork);
                                        if ((''+artwork).length > 3) {
                                            message = artwork;
                                        } else {
                                            message = 'No artwork exists for this character.';
                                        }

                                        whom = c.get('name');
                                        //Sends the final message
                                            if (secondOption === 'notitle'){whom = '';}
                                        sendChat(whom, messagePrefix + '&{template:' + template + '}{{' + title + '=' + whom + '}} {{' + theText + '=' + message + playerButton + '}}');

                                    }
                                }));
                        } else {

                            if ((option === 'bio') || (option === 'charnote')) {
                                let suboption = (option === 'charnote') ? 'gmnotes' : 'bio';

                                (msg.selected || [])
                                .map(o => getObj('graphic', o._id))
                                    .filter(g => undefined !== g)
                                    .map(t => getObj('character', t.get('represents')))
                                    .filter(c => undefined !== c)
                                    .forEach(c => c.get(suboption, (val) => {
                                        if (null !== val && 'null' !== val && val.length > 0) {
                                            if (regex) {
                                                message = _.filter(
                                                    decodeUnicode(val).split(/(?:[\n\r]+|
)/),
                                                    (l) => regex.test(l.replace(/<[^>]*>/g, ''))
                                                ).join('\r');
                                            } else {
                                                message = decodeUnicode(val);
                                            }
                                            whom = c.get('name');
                                            //Sends the final message
                                            if (secondOption === 'notitle'){whom = '';}
                                            sendChat(whom, messagePrefix + '&{template:' + template + '}{{' + title + '=' + whom + '}} {{' + theText + '=' + message + playerButton + '}}');

                                        }
                                    }));
                            } else {
                                (msg.selected || [])
                                .map(o => getObj('graphic', o._id))
                                    .filter(g => undefined !== g)
                                    .filter((o) => o.get('gmnotes').length > 0)
                                    .forEach(o => {
                                        if (regex) {
                                            message = _.filter(unescape(decodeUnicode(o.get('gmnotes'))).split(/(?:[\n\r]+|
)/), (l) => regex.test(l)).join('\r');
                                        } else {
                                            message = unescape(decodeUnicode(o.get('gmnotes')));
                                        }
                                        whom = o.get('name');

                                    });
                                //Sends the final message
                                            if (secondOption === 'notitle'){whom = '';}
                                sendChat(whom, messagePrefix + '&{template:' + template + '}{{' + title + '=' + whom + '}} {{' + theText + '=' + message + playerButton + '}}');

                            }

                            [
                                `### REPORT###`,
                                `THE MESSAGE =${message}`,
                                `command = ${command}`,
                                `option = ${option}`,
                                `secondOption = ${secondOption}`,
                                `messagePrefix = ${messagePrefix}`,
                                `whom = ${whom}`,
                                `message =${message}`
                            ].forEach(m => log(m));
                        }
                    }
                }
            }
        }
    });
});
<commit_msg>Update Supernotes.js<commit_after>on('ready', function() {
    if (!_.has(state, 'Supernotes')) {
        state.Supernotes = {
            sheet: 'Default',
            template: 'default',
            title: 'name',
            theText: '',
            sendToPlayers: true

        };
        message = 'Welcome to Supernotes! If this is your first time running it, the script is set to use the Default Roll Template. You can choose a different sheet template below, as well as decide whether you want the script to display a "Send to Players" footer at the end of every GM message. It is currently set to true.

[Default Template - any sheet](!gmnote --config|default)
[D&D 5th Edition by Roll20](!gmnote --config|dnd5e)
[DnD 5e Shaped](!gmnote --config|5eshaped)
[Pathfinder by Roll20](!gmnote --config|pfofficial)
[Pathfinder Community](!gmnote --config|pfcommunity)
[Pathfinder 2e by Roll20](!gmnote --config|pf2e)
[Starfinder by Roll20](!gmnote --config|starfinder)

[Toggle Send to Players](!gmnote --config|sendtoPlayers)';
        sendChat('Supernotes', '/w gm &{template:' + state.Supernotes.template + '}{{' + state.Supernotes.title + '=' + 'Config' + '}} {{' + state.Supernotes.theText + '=' + message + '}}');
    }
});

on('ready', () => {

    const decodeUnicode = (str) => str.replace(/%u[0-9a-fA-F]{2,4}/g, (m) => String.fromCharCode(parseInt(m.slice(2), 16)));

    const version = '0.0.8';
    log('Supernotes v' + version + ' is ready!  To set the template of choice or to toggle the send to players option, Use the command !gmnote --config');

    on('chat:message', function(msg) {
        if ('api' === msg.type && msg.content.match(/^!(gm|pc|self)note\b/)) {
            let match = msg.content.match(/^!gmnote-(.*)$/);

            //define command
            let command = msg.content.split(/\s+--/)[0];
let sender = msg.who
log(sender);
            let messagePrefix = '/w gm ';
            if (command === '!pcnote') {
                messagePrefix = '';
            }

           if (command === '!selfnote') {
                messagePrefix = '/w '+sender + ' ';
            }

            //define option
            let option = msg.content.split(/\s+--/)[1];
            let secondOption = msg.content.split(/\s+--/)[2];
            if (option === 'notitle'){
                option = secondOption;
                secondOption = 'notitle';}

            const template = state.Supernotes.template;
            const title = state.Supernotes.title;
            const theText = state.Supernotes.theText;
            const sendToPlayers = state.Supernotes.sendToPlayers;

 if (option !== undefined && option.includes('config')) {
                let templateChoice = option.split('|')[1]

                if (templateChoice === undefined) {
                    message = 'Current sheet template:
' + state.Supernotes.sheet + '
Send to Players:
' + state.Supernotes.sendToPlayers + '

Choose a template for Supernotes to use.

[Default Template - any sheet](!gmnote --config|default)
[D&D 5th Edition by Roll20](!gmnote --config|dnd5e)
[DnD 5e Shaped](!gmnote --config|5eshaped)
[Pathfinder Community](!gmnote --config|pfcommunity)
[Pathfinder by Roll20](!gmnote --config|pfofficial)
[Pathfinder 2e by Roll20](!gmnote --config|pf2e)
[Starfinder by Roll20](!gmnote --config|starfinder)

[Toggle Send to Players](!gmnote --config|sendtoPlayers)'
                    sendChat('Supernotes', messagePrefix + '&{template:' + template + '}{{' + title + '=' + 'Config' + '}} {{' + theText + '=' + message + '}}');
                }

                switch (templateChoice) {
                    case 'default':
                        state.Supernotes.sheet = 'Default';
                        state.Supernotes.template = 'default';
                        state.Supernotes.title = 'name';
                        state.Supernotes.theText = '';
                        sendChat('Supernotes', '/w gm Supernotes set to Default roll template');
                        break;
                    case 'dnd5e':
                        state.Supernotes.sheet = 'D&D 5th Edition by Roll20';
                        state.Supernotes.template = 'npcaction';
                        state.Supernotes.title = 'rname';
                        state.Supernotes.theText = 'description';
                        sendChat('Supernotes', '/w gm Supernotes set to ' + state.Supernotes.sheet);
                        break;
                    case '5eshaped':
                        state.Supernotes.sheet = 'DnD 5e Shaped';
                        state.Supernotes.template = '5e-shaped';
                        state.Supernotes.title = 'title';
                        state.Supernotes.theText = 'text_big';
                        sendChat('Supernotes', '/w gm Supernotes set to ' + state.Supernotes.sheet);
                        break;
                    case 'pfcommunity':
                        state.Supernotes.sheet = 'Pathfinder Community';
                        state.Supernotes.template = 'pf_generic';
                        state.Supernotes.title = 'name';
                        state.Supernotes.theText = 'description';
                        sendChat('Supernotes', '/w gm Supernotes set to ' + state.Supernotes.sheet);
                        break;
                    case 'pfofficial':
                        state.Supernotes.sheet = 'Pathfinder by Roll20';
                        state.Supernotes.template = 'npc';
                        state.Supernotes.title = 'name';
                        state.Supernotes.theText = 'descflag=1}} {{desc';
                        sendChat('Supernotes', '/w gm Supernotes set to ' + state.Supernotes.sheet);
                        break;
                    case 'pf2e':
                        state.Supernotes.sheet = 'Pathefinder 2e';
                        state.Supernotes.template = 'rolls';
                        state.Supernotes.title = 'header';
                        state.Supernotes.theText = 'desc;
                        sendChat('Supernotes', '/w gm Supernotes set to ' + state.Supernotes.sheet);
                        break;
                    case 'starfinder':
                        state.Supernotes.sheet = 'Starfinder';
                        state.Supernotes.template = 'sf_generic';
                        state.Supernotes.title = 'title';
                        state.Supernotes.theText = 'buttons0';
                        sendChat('Supernotes', '/w gm Supernotes set to ' + state.Supernotes.sheet);
                        break;
                    case 'sendtoPlayers':
                        if (state.Supernotes.sendToPlayers) {
                            state.Supernotes.sendToPlayers = false
                        } else {
                            state.Supernotes.sendToPlayers = true
                        };
                        sendChat('Supernotes', '/w gm Send to Players set to ' + state.Supernotes.sendToPlayers);
                        break;
                }
            } else {
                if (option !== undefined && option.includes('help')) {
                    message = 'Supernotes pulls the contents from a token's GM Notes field. If the token represents a character, you can optionally pull in the Bio or GM notes from the character, as well as the avatar, or extract just the image from the bio field. The user can decide whether to whisper the notes to the GM or broadcast them to all players. Finally, there is the option to add a footer to notes whispered to the GM. This footer creates a chat button to give the option of sending the notes on to the players.
This script as written is optimized for the D&D 5th Edition by Roll20 sheet, but can be adapted easily suing the Configuration section below.

Commands:
!gmnote whispers the note to the GM
!pcnote sends the note to all players

Paramaters

--token Pulls notes from the selected token's gm notes field. This is optional. If it is missing, the script assumes --token

--charnote Pulls notes from the gm notes field of the character assigned to a token.

--bio Pulls notes from the bio field of the character assigned to a token.

--avatar Pulls the image from the avatar field of the character assigned to a token.

--image Pulls first image from the bio field of the character assigned to a token, if any exists. Otherwise returns notice that no artwork is available

--images Pulls all images from the bio field of the character assigned to a token, if any exist. Otherwise returns notice that no artwork is available

--image[number] Pulls indexed image from the bio field of the character assigned to a token, if any exist. --image1 will pull the first image, --image2 the second and so on. Otherwise returns first image if available. If no images are available, returns notice that no artwork is available.

--help Displays help.

--config Returns a configuration dialog box that allows you to set which sheet's roll template to use, and to toggle the "Send to Players" footer.

Configuration
When first installed, Supernotes is configured for the default roll template. It will display a config dialog box at startup that will allow you to choose a roll template based on your character sheet of choice, as well as the option  to toggle whether you want the "Send to Players" footer button to appear.
You will need to edit the code of the script to create a custom configuration. The pre-installed sheets are:

Default Template
D&D 5th Edition by Roll20
5e Shaped
Pathfinder by Roll20
Pathfinder Community
Pathfinder 2e by Roll20
Starfinder
';
                    sendChat('Supernotes', messagePrefix + '&{template:' + template + '}{{' + title + '=' + 'Supernotes Help' + '}} {{' + theText + '=' + message + '}}');

                } else {
                    if (!(option + '').match(/^(bio|charnote|avatar|imag(e|es|e[1-9]))/)) {
                        option = 'token';
                    }

                    let playerButton = '';
                    if (sendToPlayers && (command === '!gmnote'||command ===  '!selfnote')) {
                        playerButton = '\n[Send to Players](!pcnote --' + option + ')';
                    }

                    let regex;
                    if (match && match[1]) {
                        regex = new RegExp(`^${match[1]}`, 'i');
                    }

                    let message = '';
                    let whom = '';

                    if (option === 'avatar') {
                        (msg.selected || [])
                        .map(o => getObj('graphic', o._id))
                            .filter(g => undefined !== g)
                            .map(t => getObj('character', t.get('represents')))
                            .filter(c => undefined !== c)
                            .forEach(c => {
                                message = "";
                                whom = c.get('name');
                                            if (secondOption === 'notitle'){whom = '';}
                                sendChat(whom, messagePrefix + '&{template:' + template + '}{{' + title + '=' + whom + '}} {{' + theText + '=' + message + playerButton + '}}');
                            });
                    } else {

                        if (option.match(/^imag(e|es|e[1-9])/)) {

                            (msg.selected || [])
                            .map(o => getObj('graphic', o._id))
                                .filter(g => undefined !== g)
                                .map(t => getObj('character', t.get('represents')))
                                .filter(c => undefined !== c)
                                .forEach(c => c.get('bio', (val) => {
                                    if (null !== val && 'null' !== val && val.length > 0) {
                                        if (regex) {
                                            message = _.filter(
                                                decodeUnicode(val).split(/(?:[\n\r]+|
)/),
                                                (l) => regex.test(l.replace(/<[^>]*>/g, ''))
                                            ).join('\r');
                                        } else {
                                            message = decodeUnicode(val);
                                        }
                                        if (option === "images") {
                                            artwork = message.match(/\/g)
                                        } else {
                                            artwork = message.match(/\/g);
                                            artwork = String(artwork);

                                            imageIndex = option.match(/\d+/g);

                                            if (isNaN(imageIndex) || !imageIndex) {
                                                imageIndex = 1
                                            }

                                            if (imageIndex > (artwork.split(",")).length) {
                                                imageIndex = 1
                                            }

                                            imageIndex = imageIndex - 1; //corrects from human readable

                                            artwork = artwork.split(",")[imageIndex];

                                        }
                                        log("artwork string =" + artwork);
                                        if ((''+artwork).length > 3) {
                                            message = artwork;
                                        } else {
                                            message = 'No artwork exists for this character.';
                                        }

                                        whom = c.get('name');
                                        //Sends the final message
                                            if (secondOption === 'notitle'){whom = '';}
                                        sendChat(whom, messagePrefix + '&{template:' + template + '}{{' + title + '=' + whom + '}} {{' + theText + '=' + message + playerButton + '}}');

                                    }
                                }));
                        } else {

                            if ((option === 'bio') || (option === 'charnote')) {
                                let suboption = (option === 'charnote') ? 'gmnotes' : 'bio';

                                (msg.selected || [])
                                .map(o => getObj('graphic', o._id))
                                    .filter(g => undefined !== g)
                                    .map(t => getObj('character', t.get('represents')))
                                    .filter(c => undefined !== c)
                                    .forEach(c => c.get(suboption, (val) => {
                                        if (null !== val && 'null' !== val && val.length > 0) {
                                            if (regex) {
                                                message = _.filter(
                                                    decodeUnicode(val).split(/(?:[\n\r]+|
)/),
                                                    (l) => regex.test(l.replace(/<[^>]*>/g, ''))
                                                ).join('\r');
                                            } else {
                                                message = decodeUnicode(val);
                                            }
                                            whom = c.get('name');
                                            //Sends the final message
                                            if (secondOption === 'notitle'){whom = '';}
                                            sendChat(whom, messagePrefix + '&{template:' + template + '}{{' + title + '=' + whom + '}} {{' + theText + '=' + message + playerButton + '}}');

                                        }
                                    }));
                            } else {
                                (msg.selected || [])
                                .map(o => getObj('graphic', o._id))
                                    .filter(g => undefined !== g)
                                    .filter((o) => o.get('gmnotes').length > 0)
                                    .forEach(o => {
                                        if (regex) {
                                            message = _.filter(unescape(decodeUnicode(o.get('gmnotes'))).split(/(?:[\n\r]+|
)/), (l) => regex.test(l)).join('\r');
                                        } else {
                                            message = unescape(decodeUnicode(o.get('gmnotes')));
                                        }
                                        whom = o.get('name');

                                    });
                                //Sends the final message
                                            if (secondOption === 'notitle'){whom = '';}
                                sendChat(whom, messagePrefix + '&{template:' + template + '}{{' + title + '=' + whom + '}} {{' + theText + '=' + message + playerButton + '}}');

                            }

                            [
                                `### REPORT###`,
                                `THE MESSAGE =${message}`,
                                `command = ${command}`,
                                `option = ${option}`,
                                `secondOption = ${secondOption}`,
                                `messagePrefix = ${messagePrefix}`,
                                `whom = ${whom}`,
                                `message =${message}`
                            ].forEach(m => log(m));
                        }
                    }
                }
            }
        }
    });
});
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { EditorState } from 'prosemirror-state';
import { EditorView } from 'prosemirror-view';
import history from 'prosemirror-history';
import {
  blockQuoteRule, orderedListRule, bulletListRule, codeBlockRule, headingRule,
  inputRules, allInputRules,
} from 'prosemirror-inputrules';
import { keymap } from 'prosemirror-keymap';
import { schema, defaultMarkdownParser, defaultMarkdownSerializer } from 'prosemirror-markdown';
import { baseKeymap, setBlockType, toggleMark } from 'prosemirror-commands';
import { buildKeymap } from './keymap';
import Toolbar from '../Toolbar';
import styles from './index.css';

function buildInputRules(schema) {
  let result = [], type;
  if (type = schema.nodes.blockquote) result.push(blockQuoteRule(type));
  if (type = schema.nodes.ordered_list) result.push(orderedListRule(type));
  if (type = schema.nodes.bullet_list) result.push(bulletListRule(type));
  if (type = schema.nodes.code_block) result.push(codeBlockRule(type));
  if (type = schema.nodes.heading) result.push(headingRule(type, 6));
  return result;
}

export default class Editor extends Component {
  constructor(props) {
    super(props);
    this.state = {};
  }

  componentDidMount() {
    this.view = new EditorView(this.ref, {
      state: EditorState.create({
        doc: defaultMarkdownParser.parse(this.props.value || ''),
        schema,
        plugins: [
          inputRules({
            rules: allInputRules.concat(buildInputRules(schema)),
          }),
          keymap(buildKeymap(schema)),
          keymap(baseKeymap),
          history.history(),
          keymap({
            'Mod-z': history.undo,
            'Mod-y': history.redo,
          }),
        ],
      }),
      onAction: this.handleAction,
    });
  }

  handleAction = (action) => {
    const newState = this.view.state.applyAction(action);
    switch (action.type) {
      case 'selection':
        this.handleSelection(newState);
      default:
        const md = defaultMarkdownSerializer.serialize(newState.doc);
        this.props.onChange(md);
    }
    this.view.updateState(newState);
    this.view.focus();
  };

  handleSelection = (state) => {
    const { selection } = state;
    if (selection.from === selection.to) {
      const pos = this.view.coordsAtPos(selection.from);
      const editorPos = this.view.content.getBoundingClientRect();
      const selectionPosition = { top: pos.top - editorPos.top, left: pos.left - editorPos.left };
      this.setState({ showToolbar: false, selectionPosition });
    } else {
      this.setState({ showToolbar: true });
    }
  };

  handleRef = (ref) => {
    this.ref = ref;
  };

  handleHeader = level => (
    () => {
      const command = setBlockType(schema.nodes.heading, { level });
      command(this.view.state, this.handleAction);
    }
  );

  handleBold = () => {
    const command = toggleMark(schema.marks.strong);
    command(this.view.state, this.handleAction);
  };

  handleItalic = () => {
    const command = toggleMark(schema.marks.em);
    command(this.view.state, this.handleAction);
  };

  handleToggle = () => {
    this.props.onMode('raw');
  };

  render() {
    const { showToolbar, selectionPosition } = this.state;

    return (

      <Toolbar
        isOpen={showToolbar}
        selectionPosition={selectionPosition}
        onH1={this.handleHeader(1)}
        onH2={this.handleHeader(2)}
        onBold={this.handleBold}
        onItalic={this.handleItalic}
        onLink={this.handleLink}
        onToggleMode={this.handleToggle}
      />

);
  }
}
<commit_msg>Make headers buttons toggle headers<commit_after>import React, { Component } from 'react';
import { EditorState } from 'prosemirror-state';
import { EditorView } from 'prosemirror-view';
import history from 'prosemirror-history';
import {
  blockQuoteRule, orderedListRule, bulletListRule, codeBlockRule, headingRule,
  inputRules, allInputRules,
} from 'prosemirror-inputrules';
import { keymap } from 'prosemirror-keymap';
import { schema, defaultMarkdownParser, defaultMarkdownSerializer } from 'prosemirror-markdown';
import { baseKeymap, setBlockType, toggleMark } from 'prosemirror-commands';
import { buildKeymap } from './keymap';
import Toolbar from '../Toolbar';
import styles from './index.css';

function buildInputRules(schema) {
  let result = [], type;
  if (type = schema.nodes.blockquote) result.push(blockQuoteRule(type));
  if (type = schema.nodes.ordered_list) result.push(orderedListRule(type));
  if (type = schema.nodes.bullet_list) result.push(bulletListRule(type));
  if (type = schema.nodes.code_block) result.push(codeBlockRule(type));
  if (type = schema.nodes.heading) result.push(headingRule(type, 6));
  return result;
}

export default class Editor extends Component {
  constructor(props) {
    super(props);
    this.state = {};
  }

  componentDidMount() {
    this.view = new EditorView(this.ref, {
      state: EditorState.create({
        doc: defaultMarkdownParser.parse(this.props.value || ''),
        schema,
        plugins: [
          inputRules({
            rules: allInputRules.concat(buildInputRules(schema)),
          }),
          keymap(buildKeymap(schema)),
          keymap(baseKeymap),
          history.history(),
          keymap({
            'Mod-z': history.undo,
            'Mod-y': history.redo,
          }),
        ],
      }),
      onAction: this.handleAction,
    });
  }

  handleAction = (action) => {
    const newState = this.view.state.applyAction(action);
    switch (action.type) {
      case 'selection':
        this.handleSelection(newState);
      default:
        const md = defaultMarkdownSerializer.serialize(newState.doc);
        this.props.onChange(md);
    }
    this.view.updateState(newState);
    this.view.focus();
  };

  handleSelection = (state) => {
    const { selection } = state;
    if (selection.from === selection.to) {
      const pos = this.view.coordsAtPos(selection.from);
      const editorPos = this.view.content.getBoundingClientRect();
      const selectionPosition = { top: pos.top - editorPos.top, left: pos.left - editorPos.left };
      this.setState({ showToolbar: false, selectionPosition });
    } else {
      this.setState({ showToolbar: true });
    }
  };

  handleRef = (ref) => {
    this.ref = ref;
  };

  handleHeader = level => (
    () => {
      const state = this.view.state;
      const { $from, to, node } = state.selection;
      let nodeType = schema.nodes.heading;
      let attrs = { level };
      let inHeader = node && node.hasMarkup(nodeType, attrs);
      if (!inHeader) {
        inHeader = to <= $from.end() && $from.parent.hasMarkup(nodeType, attrs);
      }
      if (inHeader) {
        nodeType = schema.nodes.paragraph;
        attrs = {};
      }

      const command = setBlockType(nodeType, { level });
      command(state, this.handleAction);
    }
  );

  handleBold = () => {
    const command = toggleMark(schema.marks.strong);
    command(this.view.state, this.handleAction);
  };

  handleItalic = () => {
    const command = toggleMark(schema.marks.em);
    command(this.view.state, this.handleAction);
  };

  handleToggle = () => {
    this.props.onMode('raw');
  };

  render() {
    const { showToolbar, selectionPosition } = this.state;

    return (

      <Toolbar
        isOpen={showToolbar}
        selectionPosition={selectionPosition}
        onH1={this.handleHeader(1)}
        onH2={this.handleHeader(2)}
        onBold={this.handleBold}
        onItalic={this.handleItalic}
        onLink={this.handleLink}
        onToggleMode={this.handleToggle}
      />

);
  }
}
<|endoftext|>


<commit_before>$(document).ready(
		function() {
			var button = $('Add Diagram')
					.appendTo($('#more'));
			button.click(function() {
				$.ajax({
					headers : {
						Accept : "application/json; charset=utf-8",
					},
					type : 'GET',
					url : '/c3po/properties',
					timeout : 5000,
					async : false,
					success : function(oData) {
						showPopup(oData);

					}
				});
			});

		});

function showPopup(properties) {
	$("#overlay").addClass('activeoverlay');

	var popup = $('#filterpopup');
	popup.children('.popupreason').text('Please select a property');
	var config = popup.children('.popupconfig');

	var sel = $('<select>').appendTo($(config));
	$(sel).append($('<option>').text("").attr('value', ''));
	$.each(properties, function(i, value) {
		$(sel).append($('<option>').text(value).attr('value', value));
	});

	popup.css({
		'display' : 'block',
		'z-index' : 11
	});

	$('.popupconfig select').change(function() {
		$.ajax({
			type : 'GET',
			url : '/c3po/property?name=' + $(this).val(),
			timeout : 5000,
			success : function(oData) {
				showOptions(oData.type);
			}
		});
	});
};

function showOptions(type) {
	if (type == "STRING" || type == "BOOL" || type == "DATE") {
		var property = $('.popupconfig select').val();
		$.ajax({
			type : 'GET',
			url : '/c3po/overview/graph?property=' + property,
			timeout : 5000,
			success : function(oData) {
				hidePopupDialog();
				var hist = [];
				$.each(oData.keys, function(i, k) {
					hist.push([ oData.keys[i], parseInt(oData.values[i]) ]);
				});
				var id = oData.property;
				var data = {};
				data[id] = hist;
				drawGraphs(data);

			}
		});

	} else {
		showIntegerPropertyDialog('applyIntegerHistogramSelection()');
	}
}

function applyIntegerHistogramSelection() {
	var selects = $('.popupconfig').children('select');
	var property = $('.popupconfig').children('select:first').val();
	var alg = $('.popupconfig').children('select:last').val();
	var width = -1;
	if (alg == "fixed") {
		width = $('.popupconfig input:first').val();
	}

	$.ajax({
		type : 'GET',
		url : '/c3po/overview/graph?property=' + property + "&alg=" + alg
				+ "&width=" + width,
		timeout : 5000,
		success : function(oData) {
			var hist = [];
			$.each(oData.keys, function(i, k) {
				hist.push([ oData.keys[i], parseInt(oData.values[i]) ]);
			});
			var id = oData.property;
			var data = {};
			data[id] = hist;
			$('#' + id).remove(); // remove the old graph if exist
			drawGraphs(data, oData.options);
			hidePopupDialog();
		}
	});
};

function getBarChart(ttl) {
	var options = {
		title : ttl,
		seriesDefaults : {
			renderer : $.jqplot.BarRenderer,
			// Show point labels to the right ('e'ast) of each bar.
			// edgeTolerance of -15 allows labels flow outside the grid
			// up to 15 pixels. If they flow out more than that, they
			// will be hidden.
			pointLabels : {
				show : true,
				location : 'n',
				edgeTolerance : -15
			},
			// Rotate the bar shadow as if bar is lit from top right.
			shadowAngle : 70,
			// Here's where we tell the chart it is oriented horizontally.
			rendererOptions : {
				barDirection : 'vertical',
				barWidth : '12'
			},
			color : '#639B00'
		},
		axesDefaults : {
			tickRenderer : $.jqplot.CanvasAxisTickRenderer,
			tickOptions : {
				angle : -30,
				fontSize : '8pt'
			}
		},
		axes : {
			// Use a category axis on the x axis and use our custom ticks.
			xaxis : {
				renderer : $.jqplot.CategoryAxisRenderer,
				tickOptions : {
					formatter : function(format, val) {
						if (val.length > 30) {
							val = val.substring(0, 25) + '...';
						}

						// val = (val.replace(/\.0/g, ""));
						return val;
					}
				}
			},
			// Pad the y axis just a little so bars can get close to, but
			// not touch, the grid boundaries. 1.2 is the default padding.
			yaxis : {
				pad : 1.05,
				tickOptions : {
					formatString : '%d',
				}
			}
		},
		highlighter : {
			show : true,
			tooltipLocation : 'n',
			showTooltip : true,
			useAxesFormatters : true,
			sizeAdjust : 0.5,
			tooltipAxes : 'y',
			bringSeriesToFront : true,
			tooltipOffset : 30,
		},
		cursor : {
			style : 'pointer', // A CSS spec for the cursor type to change the
								// cursor to when over plot.
			show : true,
			showTooltip : false, // show a tooltip showing cursor position.
			useAxesFormatters : true, // wether to use the same formatter and
										// formatStrings
		// as used by the axes, or to use the formatString
		// specified on the cursor with sprintf.
		}

	};

	return options;
};

function getPieChart(ttl) {
	var options = {
		title : ttl,
		seriesDefaults : {
			renderer : $.jqplot.PieRenderer,
			rendererOptions : {
				showDataLabels : true
			}
		},
		legend : {
			show : true,
			location : 'e'
		}
	};

	return options;
};

function prettifyTitle(title) {
	title = title.replace(/_/g, " ");
	return title.replace(/\w\S*/g, function(txt) {
		return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
	});
};

function drawGraphs(data, options) {
	var idx = 0;
	var graphsdiv = $('#graphs');
	$.each(data, function(i, d) {
		var container;
		var clazz;
		if (idx % 2 == 0) {
			container = $('
').appendTo(graphsdiv);
			clazz = "dia_left";
		} else if (idx % 2 == 1) {
			container = graphsdiv.children('.span-24:last');
			clazz = "dia_right";
		}

		if (d.length > 30) {
			container = $('
').appendTo(graphsdiv);
			clazz = "dia_full";
			idx++; // if full length skip to next row left
		}

		container.append('
');
		$('#' + i).bind(
				'jqplotDataClick',
				function(ev, seriesIndex, pointIndex, data) {
					startSpinner();
					var url = '/c3po/filter?filter=' + i + '&value='
							+ pointIndex + '&type=graph';

					if (options) {
						var type = options['type'];
						var alg = options['alg'];
						var width = options['width'];

						if (type == 'INTEGER') {
							url += '&alg=' + alg;

							if (width) {
								url += '&width=' + width;
							}
						}
					}
					$.post(url, function(data) {
						window.location = '/c3po/overview';
					});
				});
		$.jqplot(i, [ d ], getBarChart(prettifyTitle(i)));

		if (idx == 0) {
			idx++; // if first row skip the right and go to next row...
		}
		idx++;
	})
};<commit_msg>fixes #29<commit_after>$(document).ready(
		function() {
			var button = $('Add Diagram')
					.appendTo($('#more'));
			button.click(function() {
				$.ajax({
					headers : {
						Accept : "application/json; charset=utf-8",
					},
					type : 'GET',
					url : '/c3po/properties',
					timeout : 5000,
					async : false,
					success : function(oData) {
						showPopup(oData);

					}
				});
			});

		});

function showPopup(properties) {
	$("#overlay").addClass('activeoverlay');

	var popup = $('#filterpopup');
	popup.children('.popupreason').text('Please select a property');
	var config = popup.children('.popupconfig');

	var sel = $('<select>').appendTo($(config));
	$(sel).append($('<option>').text("").attr('value', ''));
	$.each(properties, function(i, value) {
		$(sel).append($('<option>').text(value).attr('value', value));
	});

	popup.css({
		'display' : 'block',
		'z-index' : 11
	});

	$('.popupconfig select').change(function() {
		$.ajax({
			type : 'GET',
			url : '/c3po/property?name=' + $(this).val(),
			timeout : 5000,
			success : function(oData) {
				showOptions(oData.type);
			}
		});
	});
};

function showOptions(type) {
	if (type == "STRING" || type == "BOOL" || type == "DATE") {
		var property = $('.popupconfig select').val();
		hidePopupDialog();
		startSpinner();
		$.ajax({
			type : 'GET',
			url : '/c3po/overview/graph?property=' + property,
			timeout : 5000,
			success : function(oData) {
				stopSpinner();
				var hist = [];
				$.each(oData.keys, function(i, k) {
					hist.push([ oData.keys[i], parseInt(oData.values[i]) ]);
				});
				var id = oData.property;
				var data = {};
				data[id] = hist;
				drawGraphs(data);
				//scroll to bottom of page.

			}
		});

	} else {
		showIntegerPropertyDialog('applyIntegerHistogramSelection()');
	}
}

function applyIntegerHistogramSelection() {
	var selects = $('.popupconfig').children('select');
	var property = $('.popupconfig').children('select:first').val();
	var alg = $('.popupconfig').children('select:last').val();
	var width = -1;
	if (alg == "fixed") {
		width = $('.popupconfig input:first').val();
	}

	hidePopupDialog();
	startSpinner();
	$.ajax({
		type : 'GET',
		url : '/c3po/overview/graph?property=' + property + "&alg=" + alg
				+ "&width=" + width,
		timeout : 5000,
		success : function(oData) {
			var hist = [];
			$.each(oData.keys, function(i, k) {
				hist.push([ oData.keys[i], parseInt(oData.values[i]) ]);
			});
			var id = oData.property;
			var data = {};
			data[id] = hist;
			$('#' + id).remove(); // remove the old graph if exist
			drawGraphs(data, oData.options);
			stopSpinner();
			//scroll to bottom of page.
		}
	});
};

function getBarChart(ttl) {
	var options = {
		title : ttl,
		seriesDefaults : {
			renderer : $.jqplot.BarRenderer,
			// Show point labels to the right ('e'ast) of each bar.
			// edgeTolerance of -15 allows labels flow outside the grid
			// up to 15 pixels. If they flow out more than that, they
			// will be hidden.
			pointLabels : {
				show : true,
				location : 'n',
				edgeTolerance : -15
			},
			// Rotate the bar shadow as if bar is lit from top right.
			shadowAngle : 70,
			// Here's where we tell the chart it is oriented horizontally.
			rendererOptions : {
				barDirection : 'vertical',
				barWidth : '12'
			},
			color : '#639B00'
		},
		axesDefaults : {
			tickRenderer : $.jqplot.CanvasAxisTickRenderer,
			tickOptions : {
				angle : -30,
				fontSize : '8pt'
			}
		},
		axes : {
			// Use a category axis on the x axis and use our custom ticks.
			xaxis : {
				renderer : $.jqplot.CategoryAxisRenderer,
				tickOptions : {
					formatter : function(format, val) {
						if (val.length > 30) {
							val = val.substring(0, 25) + '...';
						}

						// val = (val.replace(/\.0/g, ""));
						return val;
					}
				}
			},
			// Pad the y axis just a little so bars can get close to, but
			// not touch, the grid boundaries. 1.2 is the default padding.
			yaxis : {
				pad : 1.05,
				tickOptions : {
					formatString : '%d',
				}
			}
		},
		highlighter : {
			show : true,
			tooltipLocation : 'n',
			showTooltip : true,
			useAxesFormatters : true,
			sizeAdjust : 0.5,
			tooltipAxes : 'y',
			bringSeriesToFront : true,
			tooltipOffset : 30,
		},
		cursor : {
			style : 'pointer', // A CSS spec for the cursor type to change the
								// cursor to when over plot.
			show : true,
			showTooltip : false, // show a tooltip showing cursor position.
			useAxesFormatters : true, // wether to use the same formatter and
										// formatStrings
		// as used by the axes, or to use the formatString
		// specified on the cursor with sprintf.
		}

	};

	return options;
};

function getPieChart(ttl) {
	var options = {
		title : ttl,
		seriesDefaults : {
			renderer : $.jqplot.PieRenderer,
			rendererOptions : {
				showDataLabels : true
			}
		},
		legend : {
			show : true,
			location : 'e'
		}
	};

	return options;
};

function prettifyTitle(title) {
	title = title.replace(/_/g, " ");
	return title.replace(/\w\S*/g, function(txt) {
		return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
	});
};

function drawGraphs(data, options) {
	var idx = 0;
	var graphsdiv = $('#graphs');
	$.each(data, function(i, d) {
		var container;
		var clazz;
		if (idx % 2 == 0) {
			container = $('
').appendTo(graphsdiv);
			clazz = "dia_left";
		} else if (idx % 2 == 1) {
			container = graphsdiv.children('.span-24:last');
			clazz = "dia_right";
		}

		if (d.length > 30) {
			container = $('
').appendTo(graphsdiv);
			clazz = "dia_full";
			idx++; // if full length skip to next row left
		}

		container.append('
');
		$('#' + i).bind(
				'jqplotDataClick',
				function(ev, seriesIndex, pointIndex, data) {
					startSpinner();
					var url = '/c3po/filter?filter=' + i + '&value='
							+ pointIndex + '&type=graph';

					if (options) {
						var type = options['type'];
						var alg = options['alg'];
						var width = options['width'];

						if (type == 'INTEGER') {
							url += '&alg=' + alg;

							if (width) {
								url += '&width=' + width;
							}
						}
					}
					$.post(url, function(data) {
						window.location = '/c3po/overview';
					});
				});
		$.jqplot(i, [ d ], getBarChart(prettifyTitle(i)));

		if (idx == 0) {
			idx++; // if first row skip the right and go to next row...
		}
		idx++;
	})
};<|endoftext|>


<commit_before>// When comparing groups' names we do not know what was initial sort order (and we would like to keep it fixed)
// Furthermore, we also do not know which table's (if there are multiple tables on the page) groups we are at
// So we make a list of all groups from all tables joined together and use this to compare groups' names
// There should be no be equally named groups in different tables
var allGroups = [];

jQuery.fn.dataTableExt.aTypes.push(
	function (sData) {
		if (/^\s*$/.test(sData.replace(/<.*?>/g, ""))) {
			// Nothing except HTML tags are in data, we will try to use alt attribute
			return 'html-alt';
		}
		return null;
	},
	function (sData) {
		// We use valid HTML data where this characters should be escaped in text
		if (/[<>]/.test(sData)) {
			return 'html';
		}
		return null;
	},
	function (sData) {
		if (/^(\d{1,3}\.){3}\d{1,3}(\/\d{1,2})?$/.test(sData)) {
			return 'ip-address';
		}
		return null;
	},
	function (sData) {
		// This code is duplicated in reverse in conversion.py file. Keep them in sync.
		if (/^\d+(\.\d+)?\s+(KB|MB|GB)$/.test(sData)) {
			return 'byte-size';
		}
		return null;
	}
);

function compare(a, b) {
	return ((a < b) ? -1 : ((a > b) ? 1 : 0));
}

function getAlt(el) {
	var el = $(el);
	var alt = el.attr('alt') || el.find('[alt]').attr('alt') || "";
	return alt.toLowerCase();
}

jQuery.fn.dataTableExt.oSort['html-alt-asc'] = function (a, b) {
	return compare(getAlt(a), getAlt(b));
};

jQuery.fn.dataTableExt.oSort['html-alt-desc'] = function (a, b) {
	return jQuery.fn.dataTableExt.oSort['html-alt-asc'](b, a);
};

// This code is duplicated in reverse in conversion.py file. Keep them in sync.
function toKbytes(n) {
	var v = parseFloat(n);
	if (/MB/.test(n)) {
		v *= 1024.0;
	}
	else if (/GB/.test(n)) {
		v *= 1048576.0;
	}
	return v;
}

jQuery.fn.dataTableExt.oSort['byte-size-asc'] = function (a, b) {
	return compare(toKbytes(a), toKbytes(b))
};

jQuery.fn.dataTableExt.oSort['byte-size-desc'] = function (a, b) {
	return jQuery.fn.dataTableExt.oSort['byte-size-asc'](b, a);
};

jQuery.fn.dataTableExt.oSort['ip-address-asc'] = function (a, b) {
	var as = a.split(/[./]/);
	var bs = b.split(/[./]/);
	for (var i = 0; i < as.length; i++) {
		if (i >= bs.length) {
			return 1;
		}
		var comp = as[i] - bs[i];
		if (comp != 0) {
			return comp;
		}
	}
	if (i < bs.length) {
		return -1;
	}
	return 0;
};

jQuery.fn.dataTableExt.oSort['ip-address-desc'] = function (a, b) {
	return jQuery.fn.dataTableExt.oSort['ip-address-asc'](b, a);
};

jQuery.fn.dataTableExt.oSort['group-sort-asc'] = function (a, b) {
	return compare($.inArray(a, allGroups), $.inArray(b, allGroups));
};

jQuery.fn.dataTableExt.oSort['group-sort-desc'] = function (a, b) {
	return jQuery.fn.dataTableExt.oSort['group-sort-asc'](b, a);
};

function groupDrawCallback(table) {
	return function (oSettings) {
		if (oSettings.aiDisplay.length == 0) {
			return;
		}

		var trs = $(table).find('tbody tr');
		var colspan = trs.eq(0).find('td').length;
		var lastGroup = "";
		trs.each(function (i) {
			var displayIndex = oSettings._iDisplayStart + i;
			var group = oSettings.aoData[oSettings.aiDisplay[displayIndex]]._aData[0];
			if (group != lastGroup) {
				$("<tr />").addClass("section_title").append(
					$("<td />").attr("colspan", colspan).html(group)
				).insertBefore($(this));
				lastGroup = group;
			}
		});
	};
}

$(document).ready(function() {
	if (typeof tablesConfig == "undefined") {
		tablesConfig = [];
	}
	$('table.listing:has(thead)').each(function (t) {
		var sections = [];
		var config = $.extend({
			"entryName": "entries",
			"sortColumn": []
		}, tablesConfig[t]);
		var entryName = config.entryName;
		var sortColumn = config.sortColumn;

		$(this).find('tbody tr').each(function (i) {
			if ($(this).is('.section_title')) {
				var content = $(this).find('td').html();
				sections.push(content);
				allGroups.push(content);
				$(this).remove();
			}
			else if (sections.length != 0) {
				$(this).prepend($("<td />").html(sections[sections.length - 1]));
			}
		});
		if (sections.length != 0) {
			$(this).find('thead tr').prepend($("<th />"));
			$.each(sortColumn, function (i, val) {
				val[0]++;
			});
		}

		var columns = [];
		$(this).find('thead th').each(function (i) {
			if ((i == 0) && (sections.length != 0)) {
				columns.push({
					"bVisible": false,
					"bSearchable": true,
					"bSortable": true,
					"sType": 'group-sort'
				});
			}
			else if (/^\s*$/.test($(this).text())) {
				// We ignore columns with empty header
				columns.push({
					"bVisible": true,
					"bSearchable": false,
					"bSortable": false
				});
			}
			else {
				columns.push(null);
			}
		});

		if ($(this).find('tbody td:not([colspan])').length > 0) {
			$(this).dataTable({
				"bPaginate": false,
				"bLengthChange": true,
				"bFilter": true,
				"bSort": true,
				"bInfo": true,
				"bAutoWidth": false,
				"bProcessing": false,
				"bSortClasses": false,
				"bStateSave": false,
				"bServerSide": false,
				"aoColumns": columns,
				"aaSortingFixed": (sections.length != 0 ? [[ 0, 'asc' ]] : null),
				"aaSorting": sortColumn,
				"fnDrawCallback": (sections.length != 0 ? groupDrawCallback(this) : null),
				"sDom": 'tif<"clear">',
				"oLanguage": {
					"sZeroRecords": "No matching " + entryName + " found",
					"sInfo": "_TOTAL_ " + entryName + " shown",
					"sInfoEmpty": "0 " + entryName + " shown",
					"sInfoFiltered": "(from _MAX_ all " + entryName + ")",
					"sInfoPostFix": "",
					"sSearch": "Filter:"
				}
			}).fnSettings().oPreviousSearch.bEscapeRegex = false;
		}
	});
});
<commit_msg>Some more DataTables JavaScript fixes. Regex filtering does still not work properly.<commit_after>// When comparing groups' names we do not know what was initial sort order (and we would like to keep it fixed)
// Furthermore, we also do not know which table's (if there are multiple tables on the page) groups we are at
// So we make a list of all groups from all tables joined together and use this to compare groups' names
// There should be no be equally named groups in different tables
var allGroups = [];

jQuery.fn.dataTableExt.aTypes.push(
	function (sData) {
		if (/^\s*$/.test(sData.replace(/<.*?>/g, ""))) {
			// Nothing except HTML tags are in data, we will try to use alt attribute
			return 'html-alt';
		}
		return null;
	},
	function (sData) {
		// We use valid HTML data where this characters should be escaped in text
		if (/[<>]/.test(sData)) {
			return 'html';
		}
		return null;
	},
	function (sData) {
		if (/^(\d{1,3}\.){3}\d{1,3}(\/\d{1,2})?$/.test(sData)) {
			return 'ip-address';
		}
		return null;
	},
	function (sData) {
		// This code is duplicated in reverse in conversion.py file. Keep them in sync.
		if (/^\d+(\.\d+)?\s+(KB|MB|GB)$/.test(sData)) {
			return 'byte-size';
		}
		return null;
	}
);

function compare(a, b) {
	return ((a < b) ? -1 : ((a > b) ? 1 : 0));
}

function getAlt(el) {
	var el = $(el);
	var alt = el.attr('alt') || el.find('[alt]').attr('alt') || "";
	return alt.toLowerCase();
}

jQuery.fn.dataTableExt.oSort['html-alt-asc'] = function (a, b) {
	return compare(getAlt(a), getAlt(b));
};

jQuery.fn.dataTableExt.oSort['html-alt-desc'] = function (a, b) {
	return jQuery.fn.dataTableExt.oSort['html-alt-asc'](b, a);
};

// This code is duplicated in reverse in conversion.py file. Keep them in sync.
function toKbytes(n) {
	var v = parseFloat(n);
	if (/MB/.test(n)) {
		v *= 1024.0;
	}
	else if (/GB/.test(n)) {
		v *= 1048576.0;
	}
	return v;
}

jQuery.fn.dataTableExt.oSort['byte-size-asc'] = function (a, b) {
	return compare(toKbytes(a), toKbytes(b))
};

jQuery.fn.dataTableExt.oSort['byte-size-desc'] = function (a, b) {
	return jQuery.fn.dataTableExt.oSort['byte-size-asc'](b, a);
};

jQuery.fn.dataTableExt.oSort['ip-address-asc'] = function (a, b) {
	var as = a.split(/[./]/);
	var bs = b.split(/[./]/);
	for (var i = 0; i < as.length; i++) {
		if (i >= bs.length) {
			return 1;
		}
		var comp = as[i] - bs[i];
		if (comp != 0) {
			return comp;
		}
	}
	if (i < bs.length) {
		return -1;
	}
	return 0;
};

jQuery.fn.dataTableExt.oSort['ip-address-desc'] = function (a, b) {
	return jQuery.fn.dataTableExt.oSort['ip-address-asc'](b, a);
};

jQuery.fn.dataTableExt.oSort['group-sort-asc'] = function (a, b) {
	return compare($.inArray(a, allGroups), $.inArray(b, allGroups));
};

jQuery.fn.dataTableExt.oSort['group-sort-desc'] = function (a, b) {
	return jQuery.fn.dataTableExt.oSort['group-sort-asc'](b, a);
};

function groupDrawCallback(table) {
	return function (oSettings) {
		if (oSettings.aiDisplay.length == 0) {
			return;
		}

		var trs = $(table).find('tbody tr');
		var colspan = trs.eq(0).find('td').length;
		var lastGroup = "";
		trs.each(function (i) {
			var displayIndex = oSettings._iDisplayStart + i;
			var group = oSettings.aoData[oSettings.aiDisplay[displayIndex]]._aData[0];
			if (group != lastGroup) {
				$("<tr />").addClass("section_title").append(
					$("<td />").attr("colspan", colspan).html(group)
				).insertBefore($(this));
				lastGroup = group;
			}
		});
	};
}

$(document).ready(function() {
	if (typeof tablesConfig == "undefined") {
		tablesConfig = [];
	}
	$('table.listing:has(thead)').each(function (t) {
		var sections = [];
		var config = $.extend({
			"entryName": "entries",
			"sortColumn": []
		}, tablesConfig[t]);
		var entryName = config.entryName;
		var sortColumn = config.sortColumn;

		$(this).find('tbody tr').each(function (i) {
			if ($(this).is('.section_title')) {
				var content = $(this).find('td').html();
				sections.push(content);
				allGroups.push(content);
				$(this).remove();
			}
			else if (sections.length != 0) {
				$(this).prepend($("<td />").html(sections[sections.length - 1]));
			}
		});
		if (sections.length != 0) {
			$(this).find('thead tr').prepend($("<th />"));
		}

		var columns = [];
		$(this).find('thead th').each(function (i) {
			if ((i == 0) && (sections.length != 0)) {
				columns.push({
					"bVisible": false,
					"bSearchable": true,
					"bSortable": true,
					"sType": 'group-sort'
				});
			}
			else if (/^\s*$/.test($(this).text())) {
				// We ignore columns with empty header
				columns.push({
					"bVisible": true,
					"bSearchable": false,
					"bSortable": false
				});
			}
			else {
				columns.push({});
			}
		});

		$.each(sortColumn, function (i, val) {
			if (sections.length != 0) {
				val[0]++;
			}
			if (val[1] == "desc") {
				columns[val[0]].asSorting = ["desc", "asc"];
			}
		});

		if ($(this).find('tbody td:not([colspan])').length > 0) {
			$(this).dataTable({
				"bPaginate": false,
				"bLengthChange": true,
				"bFilter": true,
				"bSort": true,
				"oSearch": {
					"sSearch": "",
					"bEscapeRegex": false
				},
				"bInfo": true,
				"bAutoWidth": false,
				"bProcessing": false,
				"bSortClasses": false,
				"bStateSave": false,
				"bServerSide": false,
				"aoColumns": columns,
				"aaSortingFixed": (sections.length != 0 ? [[ 0, 'asc' ]] : null),
				"aaSorting": sortColumn,
				"fnDrawCallback": (sections.length != 0 ? groupDrawCallback(this) : null),
				"sDom": 'tif<"clear">',
				"oLanguage": {
					"sZeroRecords": "No matching " + entryName + " found",
					"sInfo": "_TOTAL_ " + entryName + " shown",
					"sInfoEmpty": "0 " + entryName + " shown",
					"sInfoFiltered": "(from _MAX_ all " + entryName + ")",
					"sInfoPostFix": "",
					"sSearch": "Filter:"
				}
			});
		}
	});
});
<|endoftext|>


<commit_before>module.exports = function (app, utils, urls, url, Users, Slices, script_dir) {
    function makeTarfile(sliceName) {
	return sliceName;
    }

    function makeExpiryDate() {
	var expiration = new Date() // gets doday
        var two_weeks = 1000 * 3600 * 24 * 7 * 2; // ms/sec * secs/hour * hours/day * days/week * 2 weeks
        expiration.setTime(expiration.getTime() + two_weeks)
        return expiration;
    }

    // invoke a remote command.  If the command exits with 0, invoke callBack, which should
    // be a function foo(req, res, callBackArgStruct, results), where results are the data
    // that came back from command.  On error invoke errorCallBack, which takes (req, res, error)

    var invokeCommand = function(req, res, cmdName, argList, callBack, callBackArgStruct, errorCallback) {
        var spawn = require('child_process').spawn;
        var cmd = spawn(script_dir + '/' + cmdName, argList);
        var error = "";
        var result = "";
        var data_received = false;
        cmd.stdout.on('data', function (data) {
            // console.log('stdout: ' + data);
            result = JSON.parse(data);
            data_received = true;
        });
        // when data is received on stderr, we have a problem and log it.  Should do something more
        // intelligent on exit...
        cmd.stderr.on('data', function (data) {
            console.log('Error in ' + cmdName +': ' + data);
            error = error + data;
        });
        // when the command finishes, either handle the error or do the callback
        cmd.on('close', function (code) {
            console.log('child process exited with code ' + code);
            if(code > 0) {
                errorCallback(req, res, "Error in subprocess " + cmdName + " " + argList + ": " + error)
            } else {
                callBack(req, res, callBackArgStruct, result)
            }
        });
    }

    var deleteSliceFromDBOnError = function(req, res, errorMessage) {
       Slices.remove({user:req.session.user}, function(err, result) {
        if(err) {
            utils.handleError(req, res, "Double Error, requires administrator attention: " + errorMessage + " : " + err)
        } else {
            utils.handleError(req, res, errorMessage)
        }
       })
    }
    var redirectToUser = function(req, res) {
        res.redirect('/user')
    }

    // get the next slice number.  used only for debugging
    app.get('/slice/next', function (req, res) {
        res.end('Next slice number is ' + next_slice)
    })

    app.get('/slice/get', function (req, res) {
        Slices.nextCount(function(err, nextSliceNum) {
            if (err) {
                var message  = "Error in getting the next Slice Number: " + err
                console.log(message);
                utils.render_error_page(req, res,  message);
            } else {
                var sliceName = utils.makeSliceName(nextSliceNum)
                var tarFile = makeTarfile(sliceName)
                Slices.create({user:req.session.user,
                              tarfile:makeTarfile(sliceName),
                              expires:makeExpiryDate()
                              },
                              function(err, slice) {
                                if (err) {
                                    var message  = "Error in creating the Slice: " + sliceName + ": " + err;
                                    console.log(message)
                                    utils.render_error_page(req, res, message)
                                } else {
                                    console.log("Slice " + sliceName + " entered for user " + req.session.user)
                                    invokeCommand(req, res, 'createSlice.sh', [sliceName, tarFile, 'foo'], redirectToUser, {}, deleteSliceFromDBOnError) // need to fix the imagename
                                }
                              });
            }
        });
    });

    // free a slicelet.  Just deletes the slicelet from the db
    app.get('/slice/free', function (req, res) {
        console.log(req.url);
        Slices.find({user:req.session.user}, function(err, slices) {
            if(err) {
                utils.handleError("Error in finding slice for user " + req.session.user + ": " + err)
            } else if (slices.length == 0) {
                utils.handleError("No slices found for user " + req.session.user)
            } else {
                var sliceName = utils.makeSliceName(slices[0].sliceNum)
                var tarfile = slices[0].tarfile;
                Slices.remove({user:req.session.user}, function(err) {
                    if(err) {
                        utils.handleError("Error removing slice for user " + req.session.user + " from the database: " + err)
                    } else {
                        invokeCommand(req, res, 'deleteSlice.sh', [sliceName, tarfile], redirectToUser, {}, utils.handleError)
                    }
                })
            }
        })
    });
    //
    // Renew a slicelet.  Just calls makeExpiryDate to set the session expiration two weeks into the
    // future, updates the slice record, then renders the dashboard.
    app.get('/slice/renew', function (req, res) {
        Slices.findOne({user:req.session.user}, function(err, doc) {
            if (err) {
                var message = "Error renewing slice for user " + req.session.user + ": " + err
                console.log(message)
                utils.render_error_page(req, res, message)
            } else {
                doc.expires = makeExpiryDate();
                doc.save(function(err, slice, numberAffected) {
                    if (err ) {
                        var message = "Error renewing slice for user " + req.session.user + ": " + err
                        console.log(message)
                        utils.render_error_page(req, res, message)
                    } else {
                        console.log("Slice for user " + req.session.user + " renewed ")
                        res.redirect('/user')
                    }
                });
            }
        });
    });

    // Callback for download.  Fortunately, this is simple, as node.js provides a
    // download primitive.  We need to error-check this better.  In particular, we
    // need to check that the file actually exists!
    app.get('/slice/download', function (req, res) {
        if (req.session.filename == null) {
            var error_message = "No filename set on call to /download ";
            utils.render_error_page(req, res, error_message, "");
        } else {
            console.log(req.session.filename);
            res.download(req.session.filename);
        }
    });
}<commit_msg>fixed typo<commit_after>module.exports = function (app, utils, urls, url, Users, Slices, script_dir) {
    function makeTarfile(sliceName) {
	return sliceName;
    }

    function makeExpiryDate() {
	var expiration = new Date() // gets doday
        var two_weeks = 1000 * 3600 * 24 * 7 * 2; // ms/sec * secs/hour * hours/day * days/week * 2 weeks
        expiration.setTime(expiration.getTime() + two_weeks)
        return expiration;
    }

    // invoke a remote command.  If the command exits with 0, invoke callBack, which should
    // be a function foo(req, res, callBackArgStruct, results), where results are the data
    // that came back from command.  On error invoke errorCallBack, which takes (req, res, error)

    var invokeCommand = function(req, res, cmdName, argList, callBack, callBackArgStruct, errorCallback) {
        var spawn = require('child_process').spawn;
        console.log("Invoking command " + script_dir + "/" + cmdName)
        var cmd = spawn(script_dir + '/' + cmdName, argList);
        var error = "";
        var result = "";
        var data_received = false;
        cmd.stdout.on('data', function (data) {
            // console.log('stdout: ' + data);
            result = JSON.parse(data);
            data_received = true;
        });
        // when data is received on stderr, we have a problem and log it.  Should do something more
        // intelligent on exit...
        cmd.stderr.on('data', function (data) {
            console.log('Error in ' + cmdName +': ' + data);
            error = error + data;
        });
        // when the command finishes, either handle the error or do the callback
        cmd.on('close', function (code) {
            console.log('child process exited with code ' + code);
            if(code > 0) {
                errorCallback(req, res, "Error in subprocess " + cmdName + " " + argList + ": " + error)
            } else {
                callBack(req, res, callBackArgStruct, result)
            }
        });
    }

    var deleteSliceFromDBOnError = function(req, res, errorMessage) {
       Slices.remove({user:req.session.user}, function(err, result) {
        if(err) {
            utils.handleError(req, res, "Double Error, requires administrator attention: " + errorMessage + " : " + err)
        } else {
            utils.handleError(req, res, errorMessage)
        }
       })
    }
    var redirectToUser = function(req, res) {
        res.redirect('/user')
    }

    // get the next slice number.  used only for debugging
    app.get('/slice/next', function (req, res) {
        res.end('Next slice number is ' + next_slice)
    })

    app.get('/slice/get', function (req, res) {
        Slices.nextCount(function(err, nextSliceNum) {
            if (err) {
                var message  = "Error in getting the next Slice Number: " + err
                console.log(message);
                utils.render_error_page(req, res,  message);
            } else {
                var sliceName = utils.makeSliceName(nextSliceNum)
                var tarFile = makeTarfile(sliceName)
                Slices.create({user:req.session.user,
                              tarfile:makeTarfile(sliceName),
                              expires:makeExpiryDate()
                              },
                              function(err, slice) {
                                if (err) {
                                    var message  = "Error in creating the Slice: " + sliceName + ": " + err;
                                    console.log(message)
                                    utils.render_error_page(req, res, message)
                                } else {
                                    console.log("Slice " + sliceName + " entered for user " + req.session.user)
                                    invokeCommand(req, res, 'createSlice.sh', [sliceName, tarFile, 'foo'], redirectToUser, {}, deleteSliceFromDBOnError) // need to fix the imagename
                                }
                              });
            }
        });
    });

    // free a slicelet.  Just deletes the slicelet from the db
    app.get('/slice/free', function (req, res) {
        console.log(req.url);
        Slices.find({user:req.session.user}, function(err, slices) {
            if(err) {
                utils.handleError("Error in finding slice for user " + req.session.user + ": " + err)
            } else if (slices.length == 0) {
                utils.handleError("No slices found for user " + req.session.user)
            } else {
                var sliceName = utils.makeSliceName(slices[0].sliceNum)
                var tarfile = slices[0].tarfile;
                Slices.remove({user:req.session.user}, function(err) {
                    if(err) {
                        utils.handleError("Error removing slice for user " + req.session.user + " from the database: " + err)
                    } else {
                        invokeCommand(req, res, 'deleteSlice.sh', [sliceName, tarfile], redirectToUser, {}, utils.handleError)
                    }
                })
            }
        })
    });
    //
    // Renew a slicelet.  Just calls makeExpiryDate to set the session expiration two weeks into the
    // future, updates the slice record, then renders the dashboard.
    app.get('/slice/renew', function (req, res) {
        Slices.findOne({user:req.session.user}, function(err, doc) {
            if (err) {
                var message = "Error renewing slice for user " + req.session.user + ": " + err
                console.log(message)
                utils.render_error_page(req, res, message)
            } else {
                doc.expires = makeExpiryDate();
                doc.save(function(err, slice, numberAffected) {
                    if (err ) {
                        var message = "Error renewing slice for user " + req.session.user + ": " + err
                        console.log(message)
                        utils.render_error_page(req, res, message)
                    } else {
                        console.log("Slice for user " + req.session.user + " renewed ")
                        res.redirect('/user')
                    }
                });
            }
        });
    });

    // Callback for download.  Fortunately, this is simple, as node.js provides a
    // download primitive.  We need to error-check this better.  In particular, we
    // need to check that the file actually exists!
    app.get('/slice/download', function (req, res) {
        if (req.session.filename == null) {
            var error_message = "No filename set on call to /download ";
            utils.render_error_page(req, res, error_message, "");
        } else {
            console.log(req.session.filename);
            res.download(req.session.filename);
        }
    });
}<|endoftext|>


<commit_before>"use strict";
define([], function(){
	var FocusDirective =  function ($parse) {
			return{
				link : function(scope, element,attrs) {
					scope.$watch($parse(attrs.focus), function(value) {
						if (value === true)
							element[0].focus();
					});
				}
			}
        };
	FocusDirective.$inject = ['$parse'];
	return {
		focus: FocusDirective
	};
});<commit_msg>Implement timeout on focus directive<commit_after>"use strict";
define([], function(){
	var FocusDirective =  function ($timeout,$parse) {
			return{
				link : function(scope, element,attrs) {
					scope.$watch($parse(attrs.focus), function(value) {
						if (value === true)
							$timeout(function(){element[0].focus();});
					});
				}
			}
        };
	FocusDirective.$inject = ['$timeout','$parse'];
	return {
		focus: FocusDirective
	};
});<|endoftext|>


<commit_before>import React from 'react';
import composeNode from '../../utils/composeNode';
import Textfield from '../../components/form/Textfield';
import Spinner from  '../../components/form/Spinner';
import Select from '../../components/form/Select';
import Payload from '../../components/form/Payload';
import { connect } from 'react-redux';
import {reducer} from './reducer';
import { bindActionCreators } from 'redux';
import { bindNodeIds } from '../../utils/utils';
import * as Actions from './actions';
import {REPEAT_OPTIONS, INTERVAL_OPTIONS, TIMEUNIT_OPTIONS} from './constants';

import './style.css';

class Node extends React.Component {

       constructor(props){
            super(props);
            const id = props.selected.id;
            Object.assign(  this,
              ...bindActionCreators(bindNodeIds(Actions, id), props.dispatch),
            );
       }

       render() {
          //local is all of the stuff in its reducer
          const {local} = this.props;
          const {repeatOption, payloadMenu, boolMenu, selectedPayload, selectedBool} = local;
          const nameprops = Object.assign({}, this.props, {name:"name"});

          const payloadprops = {
              payloadMenu: payloadMenu,
              boolMenu: boolMenu,
              togglePayloadMenu: this.togglePayloadMenu,
              toggleBoolMenu: this.toggleBoolMenu,
              selectPayload: this.selectPayload,
              selectedPayload: selectedPayload,
              selectBool: this.selectBool,
              selectedBool: selectedBool,
          }

          const repeatprops = {
            options: REPEAT_OPTIONS,
            onSelect: this.intervalChanged,
            style: {width:'73%'},
          }

          const intervalprops = {
            options: INTERVAL_OPTIONS,
            onSelect: this.unitsChanged,
            style: {width: 100},
          }

          const timeintervalunitprops = {
            options: TIMEUNIT_OPTIONS,
            onSelect: this.timeIntervalUnitsChanged,
            style: {width:90}
          }

          switch (repeatOption){

            case "none":

              options =

                          <input type="checkbox" id="node-input-once" style={{display: 'inline-block', width: 'auto', verticalAlign: 'top'}}/>
                          inject once at start?

              break;

            case "interval":

              options =

                            every
                            <Spinner />
                            <Select  {...intervalprops}/>

                            <input type="checkbox" id="node-input-once" style={{display: 'inline-block', width: 'auto', verticalAlign: 'top'}}/>
                            inject once at start?

                break;

            case "interval-time":

               options =

                    <Select {...timeintervalunitprops} />
                    minutes

                    between
                    <select id="inject-time-interval-time-start" className="inject-time-times"></select>
                    and
                    <select id="inject-time-interval-time-end" className="inject-time-times"></select>

on

                              <input type='checkbox' checked value='1'/>Monday
                              <input type='checkbox' checked value='2'/>Tuesday
                              <input type='checkbox' checked value='3'/>Wednesday

                              <input type='checkbox' checked value='4'/> Thursday
                              <input type='checkbox' checked value='5'/> Friday
                              <input type='checkbox' checked value='6'/> Saturday

                              <input type='checkbox' checked value='0'/> Sunday

                break;

            case "time":
                options =

                          at<input id="inject-time-time" value="12:00"/>

on

                                      <input type='checkbox' checked value='1'/> Monday
                                      <input type='checkbox' checked value='2'/> Tuesday
                                      <input type='checkbox' checked value='3'/> Wednesday

                                      <input type='checkbox' checked value='4'/> Thursday
                                      <input type='checkbox' checked value='5'/> Friday
                                      <input type='checkbox' checked value='6'/> Saturday

                                      <input type='checkbox' checked value='0'/> Sunday

                  break;

              default:
                 options = null;

          }

          return

                               Payload

                          <Payload {...payloadprops}/>

                           topic
                          <input type="text" id="node-input-topic" style={{width: '70%'}}/>

                           repeat
                          <Select {...repeatprops}/>
                          <input type="hidden" id="node-input-repeat"/>
                          <input type="hidden" id="node-input-crontab"/>

                      {options}

                        <Textfield {...nameprops}/>

                          Note: "interval between times" and "at a specific time" will use cron. See info box for details.

       }

}

export default composeNode(Node, 'inject',{

        category: 'input',

        color:"#a6bbcf",

        defaults: {
            name: {value:""},
            topic: {value:""},
            payload: {value:"", validate:function(v) {
                return true
            }},
            payloadType: {value:"date"},
            repeat: {value:""},
            crontab: {value:""},
            once: {value:false}
        },

        inputs:0,

        outputs:1,

        icon: "inject.png",

        label: function() {

            if (this.name) {
                return this.name;
            }
            else if (["string","str","num","bool","json"].indexOf(this.payloadType) != -1){
                if ((this.topic !== "") && ((this.topic.length + this.payload.length) <= 32)) {
                    return this.topic + ":" + this.payload;
                } else if (this.payload.length > 0 && this.payload.length < 24) {
                    return this.payload;
                } else {
                    return this._("inject.inject");
                }
            } else if (this.payloadType === 'date') {
                return this._("inject.timestamp")
            } else if (this.payloadType === 'flow' && this.payload.length < 19) {
                return 'flow.'+this.payload;
            } else if (this.payloadType === 'global' && this.payload.length < 17) {
                return 'global.'+this.payload;
            } else {
                return this._("inject.inject");
            }
        },

        labelStyle: function() {
            return this.name?"node_label_italic":"";
        },

        button: {
            onclick: function() {

            }
        },
   }, reducer
);<commit_msg>cp commit<commit_after>import React from 'react';
import composeNode from '../../utils/composeNode';
import Textfield from '../../components/form/Textfield';
import Spinner from  '../../components/form/Spinner';
import Select from '../../components/form/Select';
import Payload from '../../components/form/Payload';
import { connect } from 'react-redux';
import {reducer} from './reducer';
import { bindActionCreators } from 'redux';
import { bindNodeIds } from '../../utils/utils';
import * as Actions from './actions';
import {REPEAT_OPTIONS, INTERVAL_OPTIONS, TIMEUNIT_OPTIONS} from './constants';

import './style.css';

class Node extends React.Component {

       constructor(props){
            super(props);
            const id = props.selected.id;
            Object.assign(  this,
              ...bindActionCreators(bindNodeIds(Actions, id), props.dispatch),
            );
       }

       render() {
          //local is all of the stuff in its reducer
          const {local} = this.props;
          const {repeatOption, payloadMenu, boolMenu, selectedPayload, selectedBool} = local;
          const nameprops = Object.assign({}, this.props, {name:"name"});

          const payloadprops = {
              payloadMenu: payloadMenu,
              boolMenu: boolMenu,
              togglePayloadMenu: this.togglePayloadMenu,
              toggleBoolMenu: this.toggleBoolMenu,
              selectPayload: this.selectPayload,
              selectedPayload: selectedPayload,
              selectBool: this.selectBool,
              selectedBool: selectedBool,
          }

          const repeatprops = {
            options: REPEAT_OPTIONS,
            onSelect: this.intervalChanged,
            style: {width:'73%'},
          }

          const intervalprops = {
            options: INTERVAL_OPTIONS,
            onSelect: this.unitsChanged,
            style: {width: 100},
          }

          const timeintervalunitprops = {
            options: TIMEUNIT_OPTIONS,
            onSelect: this.timeIntervalUnitsChanged,
            style: {width:90}
          }

          let options = null;

          switch (repeatOption){

            case "none":

              options =

                          <input type="checkbox" id="node-input-once" style={{display: 'inline-block', width: 'auto', verticalAlign: 'top'}}/>
                          inject once at start?

              break;

            case "interval":

              options =

                            every
                            <Spinner />
                            <Select  {...intervalprops}/>

                            <input type="checkbox" id="node-input-once" style={{display: 'inline-block', width: 'auto', verticalAlign: 'top'}}/>
                            inject once at start?

                break;

            case "interval-time":

               options =

                    <Select {...timeintervalunitprops} />
                    minutes

                    between
                    <select id="inject-time-interval-time-start" className="inject-time-times"></select>
                    and
                    <select id="inject-time-interval-time-end" className="inject-time-times"></select>

on

                              <input type='checkbox' checked value='1'/>Monday
                              <input type='checkbox' checked value='2'/>Tuesday
                              <input type='checkbox' checked value='3'/>Wednesday

                              <input type='checkbox' checked value='4'/> Thursday
                              <input type='checkbox' checked value='5'/> Friday
                              <input type='checkbox' checked value='6'/> Saturday

                              <input type='checkbox' checked value='0'/> Sunday

                break;

            case "time":
                options =

                          at<input id="inject-time-time" value="12:00"/>

on

                                      <input type='checkbox' checked value='1'/> Monday
                                      <input type='checkbox' checked value='2'/> Tuesday
                                      <input type='checkbox' checked value='3'/> Wednesday

                                      <input type='checkbox' checked value='4'/> Thursday
                                      <input type='checkbox' checked value='5'/> Friday
                                      <input type='checkbox' checked value='6'/> Saturday

                                      <input type='checkbox' checked value='0'/> Sunday

                  break;

              default:
                 options = null;

          }

          return

                               Payload

                          <Payload {...payloadprops}/>

                           topic
                          <input type="text" id="node-input-topic" style={{width: '70%'}}/>

                           repeat
                          <Select {...repeatprops}/>
                          <input type="hidden" id="node-input-repeat"/>
                          <input type="hidden" id="node-input-crontab"/>

                      {options}

                        <Textfield {...nameprops}/>

                          Note: "interval between times" and "at a specific time" will use cron. See info box for details.

       }

}

export default composeNode(Node, 'inject',{

        category: 'input',

        color:"#a6bbcf",

        defaults: {
            name: {value:""},
            topic: {value:""},
            payload: {value:"", validate:function(v) {
                return true
            }},
            payloadType: {value:"date"},
            repeat: {value:""},
            crontab: {value:""},
            once: {value:false}
        },

        inputs:0,

        outputs:1,

        icon: "inject.png",

        label: function() {

            if (this.name) {
                return this.name;
            }
            else if (["string","str","num","bool","json"].indexOf(this.payloadType) != -1){
                if ((this.topic !== "") && ((this.topic.length + this.payload.length) <= 32)) {
                    return this.topic + ":" + this.payload;
                } else if (this.payload.length > 0 && this.payload.length < 24) {
                    return this.payload;
                } else {
                    return this._("inject.inject");
                }
            } else if (this.payloadType === 'date') {
                return this._("inject.timestamp")
            } else if (this.payloadType === 'flow' && this.payload.length < 19) {
                return 'flow.'+this.payload;
            } else if (this.payloadType === 'global' && this.payload.length < 17) {
                return 'global.'+this.payload;
            } else {
                return this._("inject.inject");
            }
        },

        labelStyle: function() {
            return this.name?"node_label_italic":"";
        },

        button: {
            onclick: function() {

            }
        },
   }, reducer
);<|endoftext|>