<commit_before>const fs = require('fs-extra');
const util = require('util');
const Promise = require("bluebird");
const _ = require('underscore');
const Asana = require('asana');
const request = require('request');
const path = require('path');

const opts = require('nomnom')
        .help('Copy Asana tasks in the project to another project')
        .options({
            config: {
                help: 'Specify Config File',
                string: '-c PATH, --config PATH',
                'default': 'config.json'
            },
            from: {
                help: 'Project name'
            },
            to: {
                help: 'Project name'
            },
            section: {
                help: 'Section name'
            }
        })
        .parse();

const fetch = function (result) {
    return _.isFunction(result.fetch) ? result.fetch() : [ result ];
};

const fetchImage = function (url) {
    return new Promise(function (resolve, reject) {
        request.get({
            url: url,
            encoding: null
        }, function (err, res, body) {
            if (err || res.statusCode !== 200) {
                reject(err || res.statusCode);
                return;
            }

            if (body) {
                resolve(body);
            } else {
                resolve(null);
            }
        });
    });
};

fs.readJson(opts.config).then(config => {
    const client = Asana.Client.create().useAccessToken(config.asana.personal_access_token);

    const uploadImageToAsana = function (taskId, file, filename) {
        return new Promise(function (resolve, reject) {
            request.post({
                url: `https://app.asana.com/api/1.0/tasks/${taskId}/attachments`,
                headers: {
                    Authorization: `Bearer ${config.asana.personal_access_token}`
                },
                formData: {
                    file: {
                        value: file,
                        options: {
                            filename: filename
                        }
                    }
                }
            }, function (err, res, body) {
                if (err || res.statusCode !== 200) {
                    reject(err || res.statusCode);
                    return;
                }

                if (body) {
                    try {
                        body = JSON.parse(body);
                    } catch (e) {}
                }

                resolve(body);
            });
        });
    };

    if (!config.asana.workspace) {
        console.log('You should select your workspace in asana.');
        console.log('<id>: <name>');

        return client.workspaces.findAll().then(fetch).then(workspaces => {
            _.each(workspaces, workspace => {
                console.log(`${workspace.id}: ${workspace.name}`);
            });

            throw Promise.CancellationError;
        });
    }

    if (!config.asana.team) {
        return client.teams.findByOrganization(config.asana.workspace).then(fetch).then(teams => {
            console.log('You should select a team in asana.');
            console.log('<id>: <name>');

            _.each(teams, team => {
                console.log(`${team.id}: ${team.name}`);
            });

            throw Promise.CancellationError;
        });
    }

    if (!opts.from || !opts.to) {
        console.log('You should select origin and target projects. (from,to)');

        return client.projects.findByTeam(config.asana.team).then(fetch).then(result => {
            console.log(result);
        });
    }

    const taskOptions = {
        opt_fields: ['name', 'attachments', 'assignee', 'followers', 'created_at', 'completed', 'notes', 'parent', 'subtasks', 'tags'].join(',')
    };

    // test 579942885784874
    // return client.tasks.findById(579942885784874, taskOptions).then(fetch).then(result => {
    return client.tasks.findByProject(opts.from, taskOptions).then(fetch).then(result => {
        const createTask = function createTask(data, parentTask) {
            const insertData = {
                assignee: !_.isEmpty(data.assignee) ? data.assignee.id : null,
                followers: !_.isEmpty(data.followers) ? _.pluck(data.followers, 'id') : null,
                name: data.name,
                notes: data.notes,
                tags: !_.isEmpty(data.tags) ? _.pluck(data.tags, 'id') : []
            };

            let promise = Promise.resolve();

            if (parentTask) {
                insertData.workspace = opts.workspace;

                promise = client.tasks.addSubtask(parentTask.id, insertData);
            } else {
                _.extend(insertData, {
                    memberships: [{
                        project: opts.to
                    }],
                    projects: [ opts.to ] // projects 혹은 workspace를 명시해줘야 한다
                });

                promise = client.tasks.create(insertData);
            }

            return promise.then(result => {
                const task = result;
                const promises = [];

                if (!_.isEmpty(data.subtasks)) {
                    promises.push(client.tasks.subtasks(data.id, taskOptions).then(fetch).then(result => {
                        return Promise.mapSeries(result, data => {
                            return createTask(data, task);
                        });
                    }));
                }

                if (!_.isEmpty(data.attachments)) {
                    promises.push(client.attachments.findByTask(data.id, {
                        opt_fields: ['name', 'view_url'].join(',')
                    }).then(fetch).then(result => {
                        return Promise.mapSeries(result, attachment => {
                            return fetchImage(attachment.view_url).then(image => {
                                return uploadImageToAsana(task.id, image, attachment.name);
                            }).catch(reason => {
                                console.log('Failed to upload attachment', reason);
                            })
                        });
                    }));
                }

                if (!_.isEmpty(data.stories)) {
                    promises.push(client.stories.findByTask(data.id).then(fetch).then(result => {
                        return Promise.mapSeries(result, story => {
                            return client.tasks.addComment(task.id, {
                                text: `${story.created_by.name}: ${story.text}`
                            });
                        });
                    }));
                }

                if (!_.isEmpty(promises)) {
                    return Promise.all(promises);
                } else {
                    return;
                }
            });
        };

        return Promise.mapSeries(result, item => {
            return createTask(item).then(() => {
                console.log(`${item.id} task copied.`);
            });
        });
    });

    // Prepare asana data to avoid duplicated
        // Executes in order
        // return Promise.mapSeries(files, function (file) {
            // // Creates tasks
            // return Promise.mapSeries(filteredCards, card => {
            //     return client.tasks.create({
            //         assignee: card.idMembers.length ? convertMap(_.first(card.idMembers), config.member) : null,
            //         due_at: card.due,
            //         followers: card.idMembers.length > 1 ? convertMap(card.idMembers, config.member) : [],
            //         name: card.name,
            //         notes: card.desc,
            //         memberships: [{
            //             project: projectData.id,
            //             section: convertMap(card.idList, listToSectionMap)
            //         }],
            //         tags: card.idLabels.length ? convertMap(card.idLabels, labelToTagMap) : [],
            //         projects: [ projectData.id ]
            //     }).then(result => {
            //         var promises = [];
            //         var taskData = result;
            //         cardToTaskMap[card.id] = result.id;
            //         countTask++;

            //         if (countTask % 10 === 0) {
            //             console.log(`${countTask}...`);
            //         }

            //         if (card.idChecklists.length) {
            //             promises.push(
            //                 Promise.mapSeries(convertMap(card.idChecklists.reverse(), checklistMap), checklist => {
            //                     return Promise.mapSeries(checklist.checkItems.reverse(), item => {
            //                         return client.tasks.addSubtask(taskData.id, {
            //                             name: item.name,
            //                             completed: item.state !== 'incomplete'
            //                         });
            //                     }).then(function () {
            //                         return client.tasks.addSubtask(taskData.id, {
            //                             name: `${checklist.name}:`
            //                         });
            //                     });
            //                 })
            //             );
            //         }

            //         if (parseInt(card.badges.comments, 10) > 0) {
            //             promises.push(
            //                 // Trello export has limitation for count of actions as 1000. so we need to request directly trello API.
            //                 trello.getAsync(`/1/cards/${card.id}/actions?limit=1000`).then(result => {
            //                     var comments = _.filter(result, action => {
            //                         return action.type === 'commentCard';
            //                     });

            //                     return Promise.mapSeries(comments.reverse(), comment => {
            //                         var member = convertMap(comment.idMemberCreator, config.member);
            //                         var text = comment.data.text;
            //                         var memberName = member ? convertMap(member, userMap) : comment.memberCreator.fullName;

            //                         text = `${memberName}: ${text} from Trello`;

            //                         return client.tasks.addComment(taskData.id, {
            //                             text: text
            //                         });
            //                     });
            //                 })
            //             );
            //         }

            //         if (card.attachments.length) {
            //             promises.push(
            //                 Promise.mapSeries(card.attachments, attachment => {
            //                     return fetchImage(attachment.url).then(image => {
            //                         return uploadImageToAsana(taskData.id, image, path.basename(attachment.url));
            //                     }).catch(reason => {
            //                         console.log('Failed to upload attachment', reason);
            //                     });
            //                 })
            //             );
            //         }

            //         return Promise.all(promises);
            //     });
            // });
        // });
}).catch(reason => {
    console.error(util.inspect(reason, null, 4));
}).catch(Promise.CancellationError, function (reason) {
    // nothing to do
});
<commit_msg>시작 task 지정 가능하도록 수정<commit_after>const fs = require('fs-extra');
const util = require('util');
const Promise = require("bluebird");
const _ = require('underscore');
const Asana = require('asana');
const request = require('request');
const path = require('path');

const opts = require('nomnom')
        .help('Copy Asana tasks in the project to another project')
        .options({
            config: {
                help: 'Specify Config File',
                string: '-c PATH, --config PATH',
                'default': 'config.json'
            },
            from: {
                help: 'Project name'
            },
            to: {
                help: 'Project name'
            },
            section: {
                help: 'Section name'
            },
            start: {
                help: 'Start task id'
            }
        })
        .parse();

const fetch = function (result) {
    return _.isFunction(result.fetch) ? result.fetch() : [ result ];
};

const fetchImage = function (url) {
    return new Promise(function (resolve, reject) {
        request.get({
            url: url,
            encoding: null
        }, function (err, res, body) {
            if (err || res.statusCode !== 200) {
                reject(err || res.statusCode);
                return;
            }

            if (body) {
                resolve(body);
            } else {
                resolve(null);
            }
        });
    });
};

fs.readJson(opts.config).then(config => {
    const client = Asana.Client.create().useAccessToken(config.asana.personal_access_token);

    const uploadImageToAsana = function (taskId, file, filename) {
        return new Promise(function (resolve, reject) {
            request.post({
                url: `https://app.asana.com/api/1.0/tasks/${taskId}/attachments`,
                headers: {
                    Authorization: `Bearer ${config.asana.personal_access_token}`
                },
                formData: {
                    file: {
                        value: file,
                        options: {
                            filename: filename
                        }
                    }
                }
            }, function (err, res, body) {
                if (err || res.statusCode !== 200) {
                    reject(err || res.statusCode);
                    return;
                }

                if (body) {
                    try {
                        body = JSON.parse(body);
                    } catch (e) {}
                }

                resolve(body);
            });
        });
    };

    if (!config.asana.workspace) {
        console.log('You should select your workspace in asana.');
        console.log('<id>: <name>');

        return client.workspaces.findAll().then(fetch).then(workspaces => {
            _.each(workspaces, workspace => {
                console.log(`${workspace.id}: ${workspace.name}`);
            });

            throw Promise.CancellationError;
        });
    }

    if (!config.asana.team) {
        return client.teams.findByOrganization(config.asana.workspace).then(fetch).then(teams => {
            console.log('You should select a team in asana.');
            console.log('<id>: <name>');

            _.each(teams, team => {
                console.log(`${team.id}: ${team.name}`);
            });

            throw Promise.CancellationError;
        });
    }

    if (!opts.from || !opts.to) {
        console.log('You should select origin and target projects. (from,to)');

        return client.projects.findByTeam(config.asana.team).then(fetch).then(result => {
            console.log(result);
        });
    }

    const taskOptions = {
        opt_fields: ['name', 'attachments', 'assignee', 'followers', 'created_at', 'completed', 'notes', 'parent', 'subtasks', 'tags'].join(',')
    };

    // test 579942885784874
    // return client.tasks.findById(579942885784874, taskOptions).then(fetch).then(result => {
    return client.tasks.findByProject(opts.from, taskOptions).then(fetch).then(result => {
        const createTask = function createTask(data, parentTask) {
            const insertData = {
                assignee: !_.isEmpty(data.assignee) ? data.assignee.id : null,
                followers: !_.isEmpty(data.followers) ? _.pluck(data.followers, 'id') : [],
                name: data.name,
                notes: data.notes,
                tags: !_.isEmpty(data.tags) ? _.pluck(data.tags, 'id') : []
            };

            let promise = Promise.resolve();

            if (parentTask) {
                insertData.workspace = opts.workspace;

                promise = client.tasks.addSubtask(parentTask.id, insertData);
            } else {
                _.extend(insertData, {
                    memberships: [{
                        project: opts.to
                    }],
                    projects: [ opts.to ] // projects 혹은 workspace를 명시해줘야 한다
                });

                promise = client.tasks.create(insertData);
            }

            return promise.then(result => {
                const task = result;
                const promises = [];

                if (!_.isEmpty(data.subtasks)) {
                    promises.push(client.tasks.subtasks(data.id, taskOptions).then(fetch).then(result => {
                        return Promise.mapSeries(result, data => {
                            return createTask(data, task);
                        });
                    }));
                }

                if (!_.isEmpty(data.attachments)) {
                    promises.push(client.attachments.findByTask(data.id, {
                        opt_fields: ['name', 'view_url'].join(',')
                    }).then(fetch).then(result => {
                        return Promise.mapSeries(result, attachment => {
                            return fetchImage(attachment.view_url).then(image => {
                                return uploadImageToAsana(task.id, image, attachment.name);
                            }).catch(reason => {
                                console.log('Failed to upload attachment', reason);
                            })
                        });
                    }));
                }

                if (!_.isEmpty(data.stories)) {
                    promises.push(client.stories.findByTask(data.id).then(fetch).then(result => {
                        return Promise.mapSeries(result, story => {
                            return client.tasks.addComment(task.id, {
                                text: `${story.created_by.name}: ${story.text}`
                            });
                        });
                    }));
                }

                if (!_.isEmpty(promises)) {
                    return Promise.all(promises);
                } else {
                    return;
                }
            });
        };

        if (opts.start) {
            _.some(result, (v, i) => {
                // type 비교를 안함
                if (v.id == opts.start) {
                    result = result.slice(i);
                    console.log(`${v.id} 이후부터 시작합니다.`);
                    return true;
                }
            });
        }

        return Promise.mapSeries(result, item => {
            return createTask(item).then(() => {
                console.log(`${item.id} task copied.`);
            });
        });
    });
}).catch(reason => {
    console.error(util.inspect(reason, null, 4));
}).catch(Promise.CancellationError, function (reason) {
    // nothing to do
});
<|endoftext|>


<commit_before>/**
 * Module in ES6 do not populate the global namespace.
 * For e.g. with ES5 HelloMsg will go with window object but with ES6
 * HelloMsg is scope to this module.
 *
 * By default in ES6 module are in strict mode.
 */
// let HelloMsg = 'Hello World!';
// console.log(HelloMsg);

/**
 * Its common practice to have class name as Capital
 */
class Person {
  /**
   * constructor gets called at the time of instance creation.
   * It used to initialize member variables and function, do not perform
   * any heavy operations in constructor
   */
  constructor(fname, lname) {
    /**
     * this.fname & this.lname are class properties.
     * these properties value are different for each instance.
     */
    this.fname = fname;
    this.lname = lname;

  }

  /**
   * coding is class method.
   */
  coding() {
    return this.fname + ' ' + this.lname + ' is coding!';
  }

  static training() {
    return 'Training is in Progress!';
  }
};

/**
 * Static properties (this is same way in ES5)
 */
Person.department = 'Engineering';

/**
 * Class are functions
 */
console.log('Type of Person class: ', typeof Person); // function

/**
 * We can create instance of class. so that we can access member variables and method.
 */
let person1 = new Person();

/**
 * Instance are object.
 */
console.log('Type of person1 instance: ', typeof person1); // object

/**
 * So, person1 is instance of Person class.
 */
console.log('person1 is instance of Person class: ', person1 instanceof Person); // true

/**
 * Pass parameters to class constructor.
 */
let person2 = new Person('Ashwin', 'Hegde');

/**
 * Get the passed parameters with the help of class instance.
 * using (.) way
 */
console.log('Class Properties using (.): ', person2.fname + ' ' + person2.lname);

/**
 * Get the passed parameters with the help of class instance.
 * using [string] way
 */
console.log('Class Properties using [string]: ', person2['fname'] + ' ' + person2['lname']);

/**
 * Access static properties with Class and Instance
 */
console.log('Static Properties using Class: ', Person.department);

console.log('Static Properties using Instance: ', person2.department);

/**
 * Access class methods
 */
console.log(person2.coding());

/**
 * Access class static methods using Class and Instance
 */
console.log(Person.training());

/**
 * This will be error, as static method cannot be access with instance
 */
// console.log(person2.training());
<commit_msg>Update class eg with get, set<commit_after>/**
 * Module in ES6 do not populate the global namespace.
 * For e.g. with ES5 HelloMsg will go with window object but with ES6
 * HelloMsg is scope to this module.
 *
 * By default in ES6 module are in strict mode.
 */
// let HelloMsg = 'Hello World!';
// console.log(HelloMsg);

/**
 * Its common practice to have class name as Capital
 */
class Person {
  /**
   * constructor gets called at the time of instance creation.
   * It used to initialize member variables and function, do not perform
   * any heavy operations in constructor
   */
  constructor(fname, lname) {
    /**
     * this.fname & this.lname are class properties.
     * these properties value are different for each instance.
     */
    this.fname = fname;
    this.lname = lname;

    /**
     * This are not private variables in JavaScript.
     * We can use _<var-name> convension to represent private variables
     */
    this._fullName = fname + ' ' + lname;
  }

  /**
   * By using getter function we can return the private variable.
   */
  get fullName() {
    return this._fullName;
  }

  set fullName(name) {
    this._fullName = name;
  }

  /**
   * coding is class method.
   */
  coding() {
    return this.fname + ' ' + this.lname + ' is coding!';
  }

  /**
   * training is class static method. It only exist to class and not to instance
   */
  static training() {
    /**
     * class properties cannot be access with static methods
     */
    console.log('Access static properties with static method: ', this.department);
    return this.fname + ' ' + this.lname + ' is training!';
  }
};

/**
 * Static properties (this is same way in ES5)
 */
Person.department = 'Engineering';

/**
 * Class are functions
 */
console.log('Type of Person class: ', typeof Person); // function

/**
 * We can create instance of class. so that we can access member variables and method.
 */
let person1 = new Person();

/**
 * Instance are object.
 */
console.log('Type of person1 instance: ', typeof person1); // object

/**
 * So, person1 is instance of Person class.
 */
console.log('person1 is instance of Person class: ', person1 instanceof Person); // true

/**
 * Pass parameters to class constructor.
 */
let person2 = new Person('Ashwin', 'Hegde');

/**
 * Get the passed parameters with the help of class instance.
 * using (.) way
 */
console.log('Class Properties using (.): ', person2.fname + ' ' + person2.lname);

/**
 * Get the passed parameters with the help of class instance.
 * using [string] way
 */
console.log('Class Properties using [string]: ', person2['fname'] + ' ' + person2['lname']);

/**
 * Access static properties with Class and Instance.
 */
console.log('Static Properties using Class: ', Person.department);
console.log('Static Properties using Instance: ', person2.department);

/**
 * Access class methods
 */
console.log(person2.coding());

/**
 * Access class static methods using Class and Instance.
 */
console.log(Person.training());

/**
 * This will be error, as static method cannot be access with instance.
 */
// console.log(person2.training());

/**
 * Access getter function like a property instead of function.
 */
console.log('Using GET: ', person2.fullName);

/**
 * Access setter function.
 */
person2._fullName = 'Kumar Kundan';
console.log('Using SET: ', person2.fullName);
<|endoftext|>


<commit_before>//colResizable - by Alvaro Prieto Lauroba - MIT & GPL
(function(a){function h(b){var c=a(this).data(q),d=m[c.t],e=d.g[c.i];e.ox=b.pageX;e.l=e[I]()[H];i[D](E+q,f)[D](F+q,g);P[z](x+"*{cursor:"+d.opt.dragCursor+K+J);e[B](d.opt.draggingClass);l=e;if(d.c[c.i].l)for(b=0;b<d.ln;b++)c=d.c[b],c.l=j,c.w=c[u]();return j}function g(b){i.unbind(E+q).unbind(F+q);a("head :last-child").remove();if(l){l[A](l.t.opt.draggingClass);var f=l.t,g=f.opt.onResize;l.x&&(e(f,l.i,1),d(f),g&&(b[G]=f[0],g(b)));f.p&&O&&c(f);l=k}}function f(a){if(l){var b=l.t,c=a.pageX-l.ox+l.l,f=b.opt.minWidth,g=l.i,h=1.5*b.cs+f+b.b,i=g==b.ln-1?b.w-h:b.g[g+1][I]()[H]-b.cs-f,f=g?b.g[g-1][I]()[H]+b.cs+f:h,c=s.max(f,s.min(i,c));l.x=c;l.css(H,c+p);if(b.opt.liveDrag&&(e(b,g),d(b),c=b.opt.onDrag))a[G]=b[0],c(a)}return j}function e(a,b,c){var d=l.x-l.l,e=a.c[b],f=a.c[b+1],g=e.w+d,d=f.w-d;e[u](g+p);f[u](d+p);a.cg.eq(b)[u](g+p);a.cg.eq(b+1)[u](d+p);if(c)e.w=g,f.w=d}function d(a){a.gc[u](a.w);for(var b=0;b<a.ln;b++){var c=a.c[b];a.g[b].css({left:c.offset().left-a.offset()[H]+c.outerWidth()+a.cs/2+p,height:a.opt.headerOnly?a.c[0].outerHeight():a.outerHeight()})}}function c(a,b){var c,d=0,e=0,f=[];if(b)if(a.cg[C](u),a.opt.flush)O[a.id]="";else{for(c=O[a.id].split(";");e<a.ln;e++)f[y](100*c[e]/c[a.ln]+"%"),b.eq(e).css(u,f[e]);for(e=0;ethead>tr>",f='">
',g=">tbody>tr:first>",i=">tr:first>",j="td",k="th",l=b.find(e+k+","+e+j);l.length||(l=b.find(g+k+","+i+k+","+g+j+","+i+j));b.cg=b.find("col");b.ln=l.length;b.p&&O&&O[b.id]&&c(b,l);l.each(function(c){var d=a(this),e=a(b.gc[z](w+"CRG"+f)[0].lastChild);e.t=b;e.i=c;e.c=d;d.w=d[u]();b.g[y](e);b.c[y](d);d[u](d.w)[C](u);if(c<b.ln-1)e.mousedown(h)[z](b.opt.gripInnerHtml)[z](w+q+'" style="cursor:'+b.opt.hoverCursor+f);else e[B]("CRL")[A]("CRG");e.data(q,{i:c,t:b[v](o)})});b.cg[C](u);d(b);b.find("td, th").not(l).not(N+"th, table td").each(function(){a(this)[C](u)})}var i=a(document),j=!1,k=null,l=k,m=[],n=0,o="id",p="px",q="CRZ",r=parseInt,s=Math,t=a.browser.msie,u="width",v="attr",w='<div class="',x="",K="!important;",L=":0px"+K,M="resize",N="table",O,P=a("head")[z](x+".CRZ{table-layout:fixed;}.CRZ td,.CRZ th{padding-"+H+L+"padding-right"+L+"overflow:hidden}.CRC{height:0px;"+I+":relative;}.CRG{margin-left:-5px;"+I+":absolute;z-index:5;}.CRG .CRZ{"+I+":absolute;background-color:red;filter:alpha(opacity=1);opacity:0;width:10px;height:100%;top:0px}.CRL{"+I+":absolute;width:1px}.CRD{ border-left:1px dotted black"+J);try{O=sessionStorage}catch(Q){}a(window)[D](M+"."+q,function(){for(a in m){var a=m[a],b,c=0;a[A](q);if(a.w!=a[u]()){a.w=a[u]();for(b=0;b<a.ln;b++)c+=a.c[b].w;for(b=0;b<a.ln;b++)a.c[b].css(u,s.round(1e3*a.c[b].w/c)/10+"%").l=1}d(a[B](q))}});a.fn.extend({colResizable:function(c){c=a.extend({draggingClass:"CRD",gripInnerHtml:"",liveDrag:j,minWidth:15,headerOnly:j,hoverCursor:"e-"+M,dragCursor:"e-"+M,postbackSafe:j,flush:j,marginLeft:k,marginRight:k,disable:j,onDrag:k,onResize:k},c);return this.each(function(){var d=c,e=a(this);if(d.disable){if(e=e[v](o),(d=m[e])&&d.is(N))d[A](q).gc.remove(),delete m[e]}else{var f=e.id=e[v](o)||q+n++;e.p=d.postbackSafe;if(e.is(N)&&!m[f])e[B](q)[v](o,f).before(w+'CRC"/>'),e.opt=d,e.g=[],e.c=[],e.w=e[u](),e.gc=e.prev(),d.marginLeft&&e.gc.css("marginLeft",d.marginLeft),d.marginRight&&e.gc.css("marginRight",d.marginRight),e.cs=r(t?this.cellSpacing||this.currentStyle.borderSpacing:e.css("border-spacing"))||2,e.b=r(t?this.border||this.currentStyle.borderLeftWidth:e.css("border-"+H+"-"+u))||1,m[f]=e,b(e)}})}})})(jQuery)<commit_msg>Update colResizable-1.3.min.js<commit_after>//colResizable - by Alvaro Prieto Lauroba - MIT & GPL
(function(a){function h(b){var c=a(this).data(q),d=m[c.t],e=d.g[c.i];e.ox=b.pageX;e.l=e[I]()[H];i[D](E+q,f)[D](F+q,g);P[z](x+"*{cursor:"+d.opt.dragCursor+K+J);e[B](d.opt.draggingClass);l=e;if(d.c[c.i].l)for(b=0;b<d.ln;b++)c=d.c[b],c.l=j,c.w=c[u]();return j}function g(b){i.unbind(E+q).unbind(F+q);a("head :last-child").remove();if(l){l[A](l.t.opt.draggingClass);var f=l.t,g=f.opt.onResize;l.x&&(e(f,l.i,1),d(f),g&&(b[G]=f[0],g(b)));f.p&&O&&c(f);l=k}}function f(a){if(l){var b=l.t,c=a.pageX-l.ox+l.l,f=b.opt.minWidth,g=l.i,h=1.5*b.cs+f+b.b,i=g==b.ln-1?b.w-h:b.g[g+1][I]()[H]-b.cs-f,f=g?b.g[g-1][I]()[H]+b.cs+f:h,c=s.max(f,s.min(i,c));l.x=c;l.css(H,c+p);if(b.opt.liveDrag&&(e(b,g),d(b),c=b.opt.onDrag))a[G]=b[0],c(a)}return j}function e(a,b,c){var d=l.x-l.l,e=a.c[b],f=a.c[b+1],g=e.w+d,d=f.w-d;e[u](g+p);f[u](d+p);a.cg.eq(b)[u](g+p);a.cg.eq(b+1)[u](d+p);if(c)e.w=g,f.w=d}function d(a){a.gc[u](a.w);for(var b=0;b<a.ln;b++){var c=a.c[b];a.g[b].css({left:c.offset().left-a.offset()[H]+c.outerWidth(false)+a.cs/2+p,height:a.opt.headerOnly?a.c[0].outerHeight(false):a.outerHeight(false)})}}function c(a,b){var c,d=0,e=0,f=[];if(b)if(a.cg[C](u),a.opt.flush)O[a.id]="";else{for(c=O[a.id].split(";");e<a.ln;e++)f[y](100*c[e]/c[a.ln]+"%"),b.eq(e).css(u,f[e]);for(e=0;ethead>tr>",f='">
',g=">tbody>tr:first>",i=">tr:first>",j="td",k="th",l=b.find(e+k+","+e+j);l.length||(l=b.find(g+k+","+i+k+","+g+j+","+i+j));b.cg=b.find("col");b.ln=l.length;b.p&&O&&O[b.id]&&c(b,l);l.each(function(c){var d=a(this),e=a(b.gc[z](w+"CRG"+f)[0].lastChild);e.t=b;e.i=c;e.c=d;d.w=d[u]();b.g[y](e);b.c[y](d);d[u](d.w)[C](u);if(c<b.ln-1)e.mousedown(h)[z](b.opt.gripInnerHtml)[z](w+q+'" style="cursor:'+b.opt.hoverCursor+f);else e[B]("CRL")[A]("CRG");e.data(q,{i:c,t:b[v](o)})});b.cg[C](u);d(b);b.find("td, th").not(l).not(N+"th, table td").each(function(){a(this)[C](u)})}var i=a(document),j=!1,k=null,l=k,m=[],n=0,o="id",p="px",q="CRZ",r=parseInt,s=Math,t=a.browser.msie,u="width",v="attr",w='<div class="',x="",K="!important;",L=":0px"+K,M="resize",N="table",O,P=a("head")[z](x+".CRZ{table-layout:fixed;}.CRZ td,.CRZ th{padding-"+H+L+"padding-right"+L+"overflow:hidden}.CRC{height:0px;"+I+":relative;}.CRG{margin-left:-5px;"+I+":absolute;z-index:5;}.CRG .CRZ{"+I+":absolute;background-color:red;filter:alpha(opacity=1);opacity:0;width:10px;height:100%;top:0px}.CRL{"+I+":absolute;width:1px}.CRD{ border-left:1px dotted black"+J);try{O=sessionStorage}catch(Q){}a(window)[D](M+"."+q,function(){for(a in m){var a=m[a],b,c=0;a[A](q);if(a.w!=a[u]()){a.w=a[u]();for(b=0;b<a.ln;b++)c+=a.c[b].w;for(b=0;b<a.ln;b++)a.c[b].css(u,s.round(1e3*a.c[b].w/c)/10+"%").l=1}d(a[B](q))}});a.fn.extend({colResizable:function(c){c=a.extend({draggingClass:"CRD",gripInnerHtml:"",liveDrag:j,minWidth:15,headerOnly:j,hoverCursor:"e-"+M,dragCursor:"e-"+M,postbackSafe:j,flush:j,marginLeft:k,marginRight:k,disable:j,onDrag:k,onResize:k},c);return this.each(function(){var d=c,e=a(this);if(d.disable){if(e=e[v](o),(d=m[e])&&d.is(N))d[A](q).gc.remove(),delete m[e]}else{var f=e.id=e[v](o)||q+n++;e.p=d.postbackSafe;if(e.is(N)&&!m[f])e[B](q)[v](o,f).before(w+'CRC"/>'),e.opt=d,e.g=[],e.c=[],e.w=e[u](),e.gc=e.prev(),d.marginLeft&&e.gc.css("marginLeft",d.marginLeft),d.marginRight&&e.gc.css("marginRight",d.marginRight),e.cs=r(t?this.cellSpacing||this.currentStyle.borderSpacing:e.css("border-spacing"))||2,e.b=r(t?this.border||this.currentStyle.borderLeftWidth:e.css("border-"+H+"-"+u))||1,m[f]=e,b(e)}})}})})(jQuery)
<|endoftext|>


<commit_before>"use strict";
const config = require("../config");
const utils = require("../src/utils");
const getBug = require('../src/getBug');

let modCommands = {
  pattern: /!ping|!bug|!restart|!getuser|!getrepro|!getnumber|!stats|!getreports|!allrepros|!backup/i,
  execute: function(bot, channelID, userTag, userID, command, msg, trello, db) {
    let messageSplit = msg.content.split(' ');
    messageSplit.shift();
    let recievedMessage = messageSplit.join(' ');
    let contentMessage = recievedMessage.match(/(\d*)\s*\|\s*([\s\S]*)/i);
      switch (command.toLowerCase()) {
        case "!ping":
          utils.botReply(bot, userID, channelID, "Pong! <:greenTick:" + config.emotes.greenTick + ">", command, msg.id, false);
        break;

        case "!bug":
          getBug(bot, channelID, userTag, userID, command, msg, trello, db);
          //DM person everything about a report
          break;

        case "!restart":
          bot.createMessage(config.channels.modLogChannel, ":large_blue_diamond: Restart command used");
          bot.deleteMessage(channelID, msg.id).then(() => {
            process.exit();
            //restart the bot
          });
          break;

        case "!getuser":
          db.all("SELECT * FROM users WHERE userid = ?", [recievedMessage], function(error, data) {
            //bot.getDMChannel(userID).then((dmChannel) => {
            //  bot.createMessage(dmChannel.id, data);
            //}).catch((error) => {console.log(error);})
            console.log(data);
          });
          break;

        case "!getrepro":
          db.all("SELECT * FROM reportQueueInfo WHERE id = ?", [recievedMessage], function(error, data) {
            console.log(data);
          });
          break;

        case "!getnumber":
          db.get("SELECT cantRepro, canRepro, id FROM reports WHERE id = ?", [recievedMessage], function(error, data) {
            console.log(data);
          });
          break;

        case "!stats":

          break;

        case "!getreports":
          db.all("SELECT * FROM reports", function(err, data) {
            console.log(data);
          });
          break;

        case "!allrepros":
          db.all("SELECT * FROM reportQueueInfo", function(err, data) {
            console.log(data);
          });
          break;

        case "!backup":
          let now = new Date();
          let thisCycle = dateFormat(now, "UTC:mm-dd-yyyy-HH-MM");
          let bufferString = fs.readFileSync('./data/data.sqlite');

          bot.createMessage(config.channels.modLogChannel, null, {file: bufferString, name: "Backup-" + thisCycle + ".sqlite"});
          break;

      }
  },
  roles: [
    config.roles.adminRole,
    config.roles.devRole,
    config.roles.trelloModRole
    ],
  channels: [
    config.channels.allChannels
  ]
}
module.exports = modCommands;
<commit_msg>backup command for mods<commit_after>"use strict";
const config = require("../config");
const utils = require("../src/utils");
const getBug = require('../src/getBug');

let modCommands = {
  pattern: /!ping|!bug|!restart|!getuser|!getrepro|!getnumber|!stats|!backup/i,
  execute: function(bot, channelID, userTag, userID, command, msg, trello, db) {
    let messageSplit = msg.content.split(' ');
    messageSplit.shift();
    let recievedMessage = messageSplit.join(' ');
    let contentMessage = recievedMessage.match(/(\d*)\s*\|\s*([\s\S]*)/i);
      switch (command.toLowerCase()) {
        case "!ping":
          utils.botReply(bot, userID, channelID, "Pong! <:greenTick:" + config.emotes.greenTick + ">", command, msg.id, false);
        break;

        case "!bug":
          getBug(bot, channelID, userTag, userID, command, msg, trello, db);
          //DM person everything about a report
          break;

        case "!restart":
          bot.createMessage(config.channels.modLogChannel, ":large_blue_diamond: Restart command used");
          bot.deleteMessage(channelID, msg.id).then(() => {
            process.exit();
            //restart the bot
          });
          break;

        case "!getuser":
          db.all("SELECT * FROM users WHERE userid = ?", [recievedMessage], function(error, data) {
            //bot.getDMChannel(userID).then((dmChannel) => {
            //  bot.createMessage(dmChannel.id, data);
            //}).catch((error) => {console.log(error);})
            console.log(data);
          });
          break;

        case "!getrepro":
          db.all("SELECT * FROM reportQueueInfo WHERE id = ?", [recievedMessage], function(error, data) {
            console.log(data);
          });
          break;

        case "!getnumber":
          db.get("SELECT cantRepro, canRepro, id FROM reports WHERE id = ?", [recievedMessage], function(error, data) {
            console.log(data);
          });
          break;

        case "!stats":

          break;

        case "!backup":
          let now = new Date();
          let thisCycle = dateFormat(now, "UTC:mm-dd-yyyy-HH-MM");
          let bufferString = fs.readFileSync('./data/data.sqlite');

          bot.createMessage(config.channels.modLogChannel, null, {file: bufferString, name: "Backup-" + thisCycle + ".sqlite"});
          break;

      }
  },
  roles: [
    config.roles.adminRole,
    config.roles.devRole,
    config.roles.trelloModRole
    ],
  channels: [
    config.channels.allChannels
  ]
}
module.exports = modCommands;
<|endoftext|>


<commit_before>const { Command } = require('discord.js-commando');

const Redis = require('../../redis/Redis');
const Tag = require('../../postgreSQL/models/Tag');

const redis = new Redis();

module.exports = class TagSourceCommand extends Command {
	constructor(client) {
		super(client, {
			name: 'tag-source',
			aliases: ['source-tag'],
			group: 'tags',
			memberName: 'source',
			description: 'Displays a tags source.',
			guildOnly: true,
			throttling: {
				usages: 2,
				duration: 3
			},

			args: [
				{
					key: 'name',
					label: 'tagname',
					prompt: 'what tag source would you like to see?\n',
					type: 'string'
				}
			]
		});
	}

	async run(msg, args) {
		const name = args.name.toLowerCase();

		return this.findCached(msg, name, msg.guild.id);
	}

	async findCached(msg, name, guildID) {
		const cache = await redis.db.getAsync(`tag${name}${msg.guild.id}`);
		if (cache) {
			const tag = await Tag.findOne({ where: { name: name, guildID: guildID } });
			if (tag) tag.increment('uses');

			return msg.say(cache);
		}

		const tag = await Tag.findOne({ where: { name: name, guildID: guildID } });
		if (!tag) return msg.say(`A tag with the name **${name}** doesn't exist, ${msg.author}`);
		tag.increment('uses');

		return redis.db.setAsync(`tag${name}${msg.guild.id}`, tag.content)
			.then(() => {
				msg.say(tag.content);
			});
	}
};
<commit_msg>Fix tag source command<commit_after>const { Command } = require('discord.js-commando');

const Redis = require('../../redis/Redis');
const Tag = require('../../postgreSQL/models/Tag');

const redis = new Redis();

module.exports = class TagSourceCommand extends Command {
	constructor(client) {
		super(client, {
			name: 'tag-source',
			aliases: ['source-tag'],
			group: 'tags',
			memberName: 'source',
			description: 'Displays a tags source.',
			guildOnly: true,
			throttling: {
				usages: 2,
				duration: 3
			},

			args: [
				{
					key: 'name',
					label: 'tagname',
					prompt: 'what tag source would you like to see?\n',
					type: 'string'
				}
			]
		});
	}

	async run(msg, args) {
		const name = args.name.toLowerCase();

		return this.findCached(msg, name, msg.guild.id);
	}

	async findCached(msg, name, guildID) {
		const cache = await redis.db.getAsync(`tag${name}${msg.guild.id}`);

		if (!cache) {
			const tag = await Tag.findOne({ where: { name, guildID } });

			if (!tag) {
				return msg.say(`A tag with the name **${name}** doesn't exist, ${msg.author}`);
			}

			return redis.db.setAsync(`tag${name}${guildID}`, tag.content).then(() => {
				return msg.code('md', tag.content);
			});
		}

		return msg.code('md', cache);
	}
};
<|endoftext|>


<commit_before>var express = require('express'),
	processSegments = require('./controller');

var app = express.createServer();

app.configure(function(){
    app.use(express.methodOverride());
    app.use(express.bodyParser());
	app.use(express.cookieParser());
	app.use(express.session({ secret: "keyboard cat" }));
	app.use(express.static(__dirname + '/public'));
    app.use(app.router);
	app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});

app.listen(8000);

console.log("StreamUR listening on port 8000.");

app.get('/:segment', function(req, res, next){
	var segments = req.params.segment.split('.');

	processSegments(segments,
		//onSucess
		function(stream){
			stream.pipe(res);
		},
		//onError
		function(error){
			next(error, req, res, next);
		}
	);
});
<commit_msg>controller complete<commit_after>var express = require('express'),
	processSegments = require('./controller');

var app = express.createServer();

app.configure(function(){
    app.use(express.methodOverride());
    app.use(express.bodyParser());
	app.use(express.cookieParser());
	app.use(express.session({ secret: "keyboard cat" }));
	app.use(express.static(__dirname + '/public'));
    app.use(app.router);
	app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});

app.listen(8000);

console.log("StreamUR listening on port 8000.");

app.get('/:segment', function(req, res, next){
	var segments = req.params.segment.split('.');

	var stream = processSegments(segments,
		//onError
		function(error){
			next(error, req, res, next);
		}
	);

	stream.pipe(res);
});
<|endoftext|>


<commit_before>/**
 * Functions for the rendering, parsing and validation of forms.
 *
 * @module
 */

/**
 * Module dependencies
 */

var core = require('./core'),
    utils = require('./utils'),
    fieldset = require('./fieldset'),
    render = require('./render'),
    _ = require('./underscore')._;

/**
 * Form object, presents fields and parses responses.
 *
 * #### Options ####
 *
 *

 *

 *      exclude
 *      Array
 *      a list of field names to exclude
 *

 *

 *      fields
 *      Array
 *
 *          a subset of fields to use (inverse of excluded)
 *
 *

 *

 *
 * @name Form(fields | type, [doc])
 * @param {Object} fields  - an object literal containing fields or a Type
 * @param {Object} doc     - (optional) the original document being edited
 * @param {Object} options - (optional) see available options above
 * @constructor
 * @api public
 */

var Form = exports.Form = function Form(fields, doc, options) {
    this.options = options || {};

    this.values = null;
    if (doc) {
        this.values = JSON.parse(JSON.stringify(doc)); /* Copy */
        this.initial_doc = doc;
    }
    if (fields && fields.fields) {
        this.type = fields;
        this.fields = this.type.fields;
    }
    else {
        this.fields = fields;
    }
    /*if (utils.constructorName(fields) === 'Type') {
        this.type = fields;
        this.fields = this.type.field;
    }
    else {
        this.fields = fields;
    }*/
};

/**
 * Overrides values in doc_a with values in doc_b, only when a field is present
 * for that value. This means properties not in fields (or in excluded fields)
 * are retained, while properties which are covered by the fieldset are
 * replaced.
 *
 * This is used when updating the form's values with a request when its been
 * initiated with a previous document. You shouldn't normally need to call this
 * directly.
 *
 * Returns the updated doc_a object.
 *
 * @name override(excludes, field_subset, fields, doc_a, doc_b, path)
 * @param {Array | null} excludes
 * @param {Array | null} field_subset
 * @param {Object} Fields
 * @param {Object} doc_a
 * @param {Object} doc_b
 * @param {Array} path
 * @returns {Object}
 * @api public
 */

exports.override = function (excludes, field_subset, fields, doc_a, doc_b, path) {
    fields = fields || {};
    doc_a = doc_a || {};

    var fields_module = require('./fields');
    var exclude_paths = (excludes || []).map(function (p) {
        return p.split('.');
    });
    var subset_paths = (field_subset || []).map(function (p) {
        return p.split('.');
    });

    var keys = _.keys(doc_b);

    _.each(keys, function (k) {
        var f = fields[k];
        var b = doc_b[k];
        var f_path = path.concat([k]);

        if (typeof b !== 'object' ||
            f instanceof fields_module.Field ||
            f instanceof fields_module.Embedded ||
            f instanceof fields_module.EmbeddedList) {

            if (excludes) {
                for (var i = 0; i < exclude_paths.length; i++) {
                    if (utils.isSubPath(exclude_paths[i], f_path)) {
                        return;
                    }
                }
            }
            if (field_subset) {
                var in_subset = false;
                for (var j = 0; j < subset_paths.length; j++) {
                    if (utils.isSubPath(subset_paths[j], f_path)) {
                        in_subset = true;
                    }
                }
                if (!in_subset) {
                    return;
                }
            }
            doc_a[k] = b;
        }
        else {
            doc_a[k] = exports.override(
                excludes, field_subset, fields[k], doc_a[k], b, f_path
            );
        }
    });
    return doc_a;
};

/**
 * Parses a request and validates the result, binding values and errors to
 * the form instance.
 *
 * @name Form.validate(req)
 * @param {Object} req
 * @returns {Form}
 * @api public
 */

Form.prototype.validate = function (/*optional*/req) {
    if (!req) {
        req = utils.currentRequest();
    }

    /* This is the request payload:
        This contains all of the form fields that are used by
        formValuesToTree and parseRaw, and must be copied first. */

    this.raw = (req.form || {});

    var type_class = require('./types').Type;
    var tree = exports.formValuesToTree(this.raw);

    this.values = exports.override(
        this.options.exclude,
        this.options.fields,
        this.fields,
        this.values || fieldset.createDefaults(this.fields, req) || {},
        exports.parseRaw(this.fields, tree),
        []
    );

    this.errors = fieldset.validate(
        this.fields, this.values, this.values, this.raw, [], false
    );

    if (this.type) {
        if (this.type instanceof type_class) {
            // run top level permissions first
            var type_errs = this.type.authorizeTypeLevel(
                this.values, this.initial_doc, req.userCtx
            );
            if (type_errs.length) {
                this.errors = this.errors.concat(type_errs);
            }
            else {
                // if no top-level permissions errors, check each field
                this.errors = this.errors.concat(
                    this.type.authorize(
                        this.values, this.initial_doc, req.userCtx
                    )
                );
            }
        } else {
            /* Programmer error: display a useful diagnostic message */
            throw new Error(
                'Encountered a type object that is not an instance of' +
                    ' `Type`; check lib/types.js for proper instansiation'
            );
        }

    }
    else {
        this.errors = this.errors.concat(fieldset.authFieldSet(
            this.fields, this.values, this.initial_doc, this.values,
            this.initial_doc, req.userCtx, [], true
        ));
    }

    // clear field properties on errors for excluded fields
    var excludes = this.options.exclude;
    if (excludes) {
        var excl_paths = _.map(excludes, function (p) {
            return p.split('.');
        });
        this.errors = _.map(this.errors, function (e) {
            if (!e.field) {
                return e;
            }
            for (var i = 0, len = excl_paths.length; i < len; i++) {
                var path = excl_paths[i];
                if (utils.isSubPath(path, e.field)) {
                    e.message = e.field.join('.') + ': ' + (
                        e.message || e.toString()
                    );
                    delete e.field;
                    return e;
                }
            }
            return e;
        });
    }

    // clear field properties on errors not in fields subset
    var field_subset = this.options.fields;
    if (field_subset) {
        var subset_paths = _.map(field_subset, function (p) {
            return p.split('.');
        });
        this.errors = _.map(this.errors, function (e) {
            if (!e.field) {
                return e;
            }
            for (var i = 0, len = subset_paths.length; i < len; i++) {
                var path = subset_paths[i];
                if (!utils.isSubPath(path, e.field)) {
                    e.message = e.field.join('.') + ': ' + (
                        e.message || e.toString()
                    );
                    delete e.field;
                    return e;
                }
            }
            return e;
        });
    }

    return this;
};

/**
 * After a form has called validate, this function will return true if the form
 * is valid, false otherwise.
 *
 * @name Form.isValid()
 * @returns {Boolean}
 * @api public
 */

Form.prototype.isValid = function () {
    return !(this.errors && this.errors.length);
};

/**
 * Filters an array of errors, returning only those below a specific field path
 *
 * @param {Array} errs
 * @param {Array} path
 * @returns {Array}
 */

var errsBelowPath = function (errs, path) {
    if (!path || !path.length) {
        return errs;
    }
    return _.filter(errs, function (e) {
        if (!e.field) {
            return false;
        }
        return utils.isSubPath(path, e.field);
    });
};

/**
 * Filters a list of errors, returning only those without a field property.
 * This is used to populate the errors at the top of the form, which apply
 * generally, or cannot be attributed to a single field.
 *
 * @param {Array} errs
 * @returns {Array}
 */

var errsWithoutFields = function (errs) {
    return _.filter(errs, function (e) {
        return !e.field;
    });
};

/**
 * Converts current form to a HTML string, using an optional renderer class.
 *
 * @name Form.toHTML(req, [RendererClass])
 * @param {Object} req Kanso request object; null for most recent. (optional)
 * @param {Renderer} RendererClass (optional)
 * @param {Object} options An object containing widget options, which
 *          will ultimately be provided to each widget's toHTML method.
 * @param {Boolean} create_defaults (optional) Set this to true if you've
 *          provided a document in {doc}, but would still like default
 *          values to be merged in to it via createDefaults. For a field f,
 *          the default value is added to {doc} if and only if doc[f]
 *          is undefined, null, or not present. Defaults to off.
 * @returns {String}
 * @returns {String}
 * @api public
 */

Form.prototype.toHTML = function (/* optional */ req,
                                  /* optional */ RendererClass,
                                  /* optional */ options,
                                  /* optional */ create_defaults) {
    if (!req) {
        req = utils.currentRequest();
    }
    var values = this.values;

    options = options || {};
    options.operation = options.operation || (values ? 'update': 'add');

    if (create_defaults) {
        values = _.defaults(
            values, fieldset.createDefaults(this.fields, req)
        );
    } else if (!values) {
        values = fieldset.createDefaults(this.fields, req);
    }

    RendererClass = (RendererClass || render.defaultRenderer());
    var renderer = new RendererClass();
    return (
        renderer.start(
            errsWithoutFields(this.errors)
        ) +
        this.renderFields(
            renderer, this.fields, values, this.raw, this.errors, [], options
        ) +
        renderer.end() +
        render.scriptTagForEvent('renderFinish')
    );
};

/**
 * Filters an array of errors, returning only those below a specific field path
 *
 * @param {Array} errs
 * @param {Array} path
 * @returns {Array}
 */

var errsBelowPath = function (errs, path) {
    return _.filter(errs, function (e) {
        for (var i = 0, len = path.length; i < len; ++i) {
            if (path[i] !== e.field[i]) {
                return false;
            }
        }
        return true;
    });
};

/**
 * Iterates over fields and sub-objects calling the correct renderer function on
 * each. Returns a HTML representation of the fields. Used internally by the
 * toHTML method, you should not need to call this function directly.
 *
 * @name Form.renderFields(renderer, fields, values, raw, err, path)
 * @param {Object} renderer
 * @param {Object} fields
 * @param {Object} values
 * @param {Array} errs
 * @param {Array} path
 * @param {Object} options An object containing widget options, which
 *          will ultimately be provided to each widget's toHTML method.
 * @returns {String}
 * @api public
 */

Form.prototype.renderFields = function (renderer, fields, values,
                                        raw, errs, path, options) {
    fields = fields || {};
    values = values || {};
    raw = raw || {};
    errs = errs || [];
    path = path || [];

    var that = this;
    var excludes = this.options.exclude;
    var field_subset = this.options.fields;
    var keys = _.keys(fields);

    var fields_module = require('./fields');

    return _.reduce(keys, function (html, k) {

        var f_path = path.concat([k]);

        if (excludes) {
            if (_.indexOf(excludes, f_path.join('.')) !== -1) {
                return html;
            }
        }
        if (field_subset) {
            if (_.indexOf(field_subset, f_path.join('.')) === -1) {
                return html;
            }
        }

        var f_errs = errsBelowPath(errs, f_path);
        var f = fields[k];

        if (f instanceof fields_module.Field ||
            f instanceof fields_module.Embedded ||
            f instanceof fields_module.EmbeddedList) {

            return html + renderer.field(
                f,
                f_path,
                values[k],
                (raw[k] === undefined) ? values[k]: raw[k],
                f_errs,
                (options || {})
            );
        }
        else if (f instanceof Object) {
            return html + (k ? renderer.beginGroup(f_path) : '') +
                that.renderFields(
                    renderer,
                    f,
                    values[k],
                    (raw[k] === undefined) ? values[k]: raw[k],
                    errs,
                    f_path,
                    (options || {})
                ) + (k ? renderer.endGroup(f_path) : '');
        } else {
            throw new Error(
                'The field type `' + (typeof f) + '` is not supported.'
            );
        }
    }, '');
};

/**
 * Transforms a flat object from a request query to a proper
 * hierarchy of properties.
 *
 *
{'one.two': 'val'} --> {one: {two: 'val'}}

 *
 * @name formValuesToTree(form)
 * @param {Object} query
 * @api public
 */

exports.formValuesToTree = function (form) {
    var tree = {};
    for (var k in form) {
        utils.setPropertyPath(tree, k.split('.'), form[k]);
    }
    return tree;
};

/**
 * Transforms a raw query object from formValuesToTree to a
 * document which follows the schema for the given type.
 *
 * @name parseRaw(fields, raw)
 * @param {Object} fields
 * @param {Object} raw
 * @returns {Object}
 * @api public
 */

exports.parseRaw = function (fields, raw) {
    var doc = {};
    raw = raw || {};
    var fields_module = require('./fields');

    for (var k in fields) {
        var f = fields[k];
        var r = raw[k];

        if (f instanceof fields_module.Field) {
            if (!f.isEmpty(r)) {
                doc[k] = f.parse(r);
            }
            else if (!f.omit_empty) {
                doc[k] = undefined;
            }
        }
        else if (f instanceof fields_module.Embedded) {
            if (!f.isEmpty(r)) {
                if (typeof r === 'string') {
                    if (r !== '') {
                        doc[k] = JSON.parse(r);
                    } else {
                        doc[k] = {};
                    }
                }
                else {
                    doc[k] = exports.parseRaw(f.type.fields, r);
                }
            }
        }
        else if (f instanceof fields_module.EmbeddedList) {
            doc[k] = [];
            for (var i in r) {
                if (typeof r[i] === 'string') {
                    if (r[i] !== '') {
                        doc[k][i] = JSON.parse(r[i]);
                    } else {
                        doc[k][i] = {};
                    }
                }
                else {
                    doc[k][i] = exports.parseRaw(f.type.fields, r[i]);
                }
            }
            if (!doc[k].length && f.omit_empty) {
                delete doc[k];
            }
        }
        else if (f instanceof Object) {
            doc[k] = exports.parseRaw(f, r);
        } else {
            throw new Error(
                'The field type `' + (typeof f) + '` is not supported.'
            );
        }
    }
    return doc;
};

<commit_msg>replace some Array.map calls with underscore methods for IE compatability<commit_after>/**
 * Functions for the rendering, parsing and validation of forms.
 *
 * @module
 */

/**
 * Module dependencies
 */

var core = require('./core'),
    utils = require('./utils'),
    fieldset = require('./fieldset'),
    render = require('./render'),
    _ = require('./underscore')._;

/**
 * Form object, presents fields and parses responses.
 *
 * #### Options ####
 *
 *

 *

 *      exclude
 *      Array
 *      a list of field names to exclude
 *

 *

 *      fields
 *      Array
 *
 *          a subset of fields to use (inverse of excluded)
 *
 *

 *

 *
 * @name Form(fields | type, [doc])
 * @param {Object} fields  - an object literal containing fields or a Type
 * @param {Object} doc     - (optional) the original document being edited
 * @param {Object} options - (optional) see available options above
 * @constructor
 * @api public
 */

var Form = exports.Form = function Form(fields, doc, options) {
    this.options = options || {};

    this.values = null;
    if (doc) {
        this.values = JSON.parse(JSON.stringify(doc)); /* Copy */
        this.initial_doc = doc;
    }
    if (fields && fields.fields) {
        this.type = fields;
        this.fields = this.type.fields;
    }
    else {
        this.fields = fields;
    }
    /*if (utils.constructorName(fields) === 'Type') {
        this.type = fields;
        this.fields = this.type.field;
    }
    else {
        this.fields = fields;
    }*/
};

/**
 * Overrides values in doc_a with values in doc_b, only when a field is present
 * for that value. This means properties not in fields (or in excluded fields)
 * are retained, while properties which are covered by the fieldset are
 * replaced.
 *
 * This is used when updating the form's values with a request when its been
 * initiated with a previous document. You shouldn't normally need to call this
 * directly.
 *
 * Returns the updated doc_a object.
 *
 * @name override(excludes, field_subset, fields, doc_a, doc_b, path)
 * @param {Array | null} excludes
 * @param {Array | null} field_subset
 * @param {Object} Fields
 * @param {Object} doc_a
 * @param {Object} doc_b
 * @param {Array} path
 * @returns {Object}
 * @api public
 */

exports.override = function (excludes, field_subset, fields, doc_a, doc_b, path) {
    fields = fields || {};
    doc_a = doc_a || {};

    var fields_module = require('./fields');
    var exclude_paths = _.map((excludes || []), function (p) {
        return p.split('.');
    });
    var subset_paths = _.map((field_subset || []), function (p) {
        return p.split('.');
    });

    var keys = _.keys(doc_b);

    _.each(keys, function (k) {
        var f = fields[k];
        var b = doc_b[k];
        var f_path = path.concat([k]);

        if (typeof b !== 'object' ||
            f instanceof fields_module.Field ||
            f instanceof fields_module.Embedded ||
            f instanceof fields_module.EmbeddedList) {

            if (excludes) {
                for (var i = 0; i < exclude_paths.length; i++) {
                    if (utils.isSubPath(exclude_paths[i], f_path)) {
                        return;
                    }
                }
            }
            if (field_subset) {
                var in_subset = false;
                for (var j = 0; j < subset_paths.length; j++) {
                    if (utils.isSubPath(subset_paths[j], f_path)) {
                        in_subset = true;
                    }
                }
                if (!in_subset) {
                    return;
                }
            }
            doc_a[k] = b;
        }
        else {
            doc_a[k] = exports.override(
                excludes, field_subset, fields[k], doc_a[k], b, f_path
            );
        }
    });
    return doc_a;
};

/**
 * Parses a request and validates the result, binding values and errors to
 * the form instance.
 *
 * @name Form.validate(req)
 * @param {Object} req
 * @returns {Form}
 * @api public
 */

Form.prototype.validate = function (/*optional*/req) {
    if (!req) {
        req = utils.currentRequest();
    }

    /* This is the request payload:
        This contains all of the form fields that are used by
        formValuesToTree and parseRaw, and must be copied first. */

    this.raw = (req.form || {});

    var type_class = require('./types').Type;
    var tree = exports.formValuesToTree(this.raw);

    this.values = exports.override(
        this.options.exclude,
        this.options.fields,
        this.fields,
        this.values || fieldset.createDefaults(this.fields, req) || {},
        exports.parseRaw(this.fields, tree),
        []
    );

    this.errors = fieldset.validate(
        this.fields, this.values, this.values, this.raw, [], false
    );

    if (this.type) {
        if (this.type instanceof type_class) {
            // run top level permissions first
            var type_errs = this.type.authorizeTypeLevel(
                this.values, this.initial_doc, req.userCtx
            );
            if (type_errs.length) {
                this.errors = this.errors.concat(type_errs);
            }
            else {
                // if no top-level permissions errors, check each field
                this.errors = this.errors.concat(
                    this.type.authorize(
                        this.values, this.initial_doc, req.userCtx
                    )
                );
            }
        } else {
            /* Programmer error: display a useful diagnostic message */
            throw new Error(
                'Encountered a type object that is not an instance of' +
                    ' `Type`; check lib/types.js for proper instansiation'
            );
        }

    }
    else {
        this.errors = this.errors.concat(fieldset.authFieldSet(
            this.fields, this.values, this.initial_doc, this.values,
            this.initial_doc, req.userCtx, [], true
        ));
    }

    // clear field properties on errors for excluded fields
    var excludes = this.options.exclude;
    if (excludes) {
        var excl_paths = _.map(excludes, function (p) {
            return p.split('.');
        });
        this.errors = _.map(this.errors, function (e) {
            if (!e.field) {
                return e;
            }
            for (var i = 0, len = excl_paths.length; i < len; i++) {
                var path = excl_paths[i];
                if (utils.isSubPath(path, e.field)) {
                    e.message = e.field.join('.') + ': ' + (
                        e.message || e.toString()
                    );
                    delete e.field;
                    return e;
                }
            }
            return e;
        });
    }

    // clear field properties on errors not in fields subset
    var field_subset = this.options.fields;
    if (field_subset) {
        var subset_paths = _.map(field_subset, function (p) {
            return p.split('.');
        });
        this.errors = _.map(this.errors, function (e) {
            if (!e.field) {
                return e;
            }
            for (var i = 0, len = subset_paths.length; i < len; i++) {
                var path = subset_paths[i];
                if (!utils.isSubPath(path, e.field)) {
                    e.message = e.field.join('.') + ': ' + (
                        e.message || e.toString()
                    );
                    delete e.field;
                    return e;
                }
            }
            return e;
        });
    }

    return this;
};

/**
 * After a form has called validate, this function will return true if the form
 * is valid, false otherwise.
 *
 * @name Form.isValid()
 * @returns {Boolean}
 * @api public
 */

Form.prototype.isValid = function () {
    return !(this.errors && this.errors.length);
};

/**
 * Filters an array of errors, returning only those below a specific field path
 *
 * @param {Array} errs
 * @param {Array} path
 * @returns {Array}
 */

var errsBelowPath = function (errs, path) {
    if (!path || !path.length) {
        return errs;
    }
    return _.filter(errs, function (e) {
        if (!e.field) {
            return false;
        }
        return utils.isSubPath(path, e.field);
    });
};

/**
 * Filters a list of errors, returning only those without a field property.
 * This is used to populate the errors at the top of the form, which apply
 * generally, or cannot be attributed to a single field.
 *
 * @param {Array} errs
 * @returns {Array}
 */

var errsWithoutFields = function (errs) {
    return _.filter(errs, function (e) {
        return !e.field;
    });
};

/**
 * Converts current form to a HTML string, using an optional renderer class.
 *
 * @name Form.toHTML(req, [RendererClass])
 * @param {Object} req Kanso request object; null for most recent. (optional)
 * @param {Renderer} RendererClass (optional)
 * @param {Object} options An object containing widget options, which
 *          will ultimately be provided to each widget's toHTML method.
 * @param {Boolean} create_defaults (optional) Set this to true if you've
 *          provided a document in {doc}, but would still like default
 *          values to be merged in to it via createDefaults. For a field f,
 *          the default value is added to {doc} if and only if doc[f]
 *          is undefined, null, or not present. Defaults to off.
 * @returns {String}
 * @returns {String}
 * @api public
 */

Form.prototype.toHTML = function (/* optional */ req,
                                  /* optional */ RendererClass,
                                  /* optional */ options,
                                  /* optional */ create_defaults) {
    if (!req) {
        req = utils.currentRequest();
    }
    var values = this.values;

    options = options || {};
    options.operation = options.operation || (values ? 'update': 'add');

    if (create_defaults) {
        values = _.defaults(
            values, fieldset.createDefaults(this.fields, req)
        );
    } else if (!values) {
        values = fieldset.createDefaults(this.fields, req);
    }

    RendererClass = (RendererClass || render.defaultRenderer());
    var renderer = new RendererClass();
    return (
        renderer.start(
            errsWithoutFields(this.errors)
        ) +
        this.renderFields(
            renderer, this.fields, values, this.raw, this.errors, [], options
        ) +
        renderer.end() +
        render.scriptTagForEvent('renderFinish')
    );
};

/**
 * Filters an array of errors, returning only those below a specific field path
 *
 * @param {Array} errs
 * @param {Array} path
 * @returns {Array}
 */

var errsBelowPath = function (errs, path) {
    return _.filter(errs, function (e) {
        for (var i = 0, len = path.length; i < len; ++i) {
            if (path[i] !== e.field[i]) {
                return false;
            }
        }
        return true;
    });
};

/**
 * Iterates over fields and sub-objects calling the correct renderer function on
 * each. Returns a HTML representation of the fields. Used internally by the
 * toHTML method, you should not need to call this function directly.
 *
 * @name Form.renderFields(renderer, fields, values, raw, err, path)
 * @param {Object} renderer
 * @param {Object} fields
 * @param {Object} values
 * @param {Array} errs
 * @param {Array} path
 * @param {Object} options An object containing widget options, which
 *          will ultimately be provided to each widget's toHTML method.
 * @returns {String}
 * @api public
 */

Form.prototype.renderFields = function (renderer, fields, values,
                                        raw, errs, path, options) {
    fields = fields || {};
    values = values || {};
    raw = raw || {};
    errs = errs || [];
    path = path || [];

    var that = this;
    var excludes = this.options.exclude;
    var field_subset = this.options.fields;
    var keys = _.keys(fields);

    var fields_module = require('./fields');

    return _.reduce(keys, function (html, k) {

        var f_path = path.concat([k]);

        if (excludes) {
            if (_.indexOf(excludes, f_path.join('.')) !== -1) {
                return html;
            }
        }
        if (field_subset) {
            if (_.indexOf(field_subset, f_path.join('.')) === -1) {
                return html;
            }
        }

        var f_errs = errsBelowPath(errs, f_path);
        var f = fields[k];

        if (f instanceof fields_module.Field ||
            f instanceof fields_module.Embedded ||
            f instanceof fields_module.EmbeddedList) {

            return html + renderer.field(
                f,
                f_path,
                values[k],
                (raw[k] === undefined) ? values[k]: raw[k],
                f_errs,
                (options || {})
            );
        }
        else if (f instanceof Object) {
            return html + (k ? renderer.beginGroup(f_path) : '') +
                that.renderFields(
                    renderer,
                    f,
                    values[k],
                    (raw[k] === undefined) ? values[k]: raw[k],
                    errs,
                    f_path,
                    (options || {})
                ) + (k ? renderer.endGroup(f_path) : '');
        } else {
            throw new Error(
                'The field type `' + (typeof f) + '` is not supported.'
            );
        }
    }, '');
};

/**
 * Transforms a flat object from a request query to a proper
 * hierarchy of properties.
 *
 *
{'one.two': 'val'} --> {one: {two: 'val'}}

 *
 * @name formValuesToTree(form)
 * @param {Object} query
 * @api public
 */

exports.formValuesToTree = function (form) {
    var tree = {};
    for (var k in form) {
        utils.setPropertyPath(tree, k.split('.'), form[k]);
    }
    return tree;
};

/**
 * Transforms a raw query object from formValuesToTree to a
 * document which follows the schema for the given type.
 *
 * @name parseRaw(fields, raw)
 * @param {Object} fields
 * @param {Object} raw
 * @returns {Object}
 * @api public
 */

exports.parseRaw = function (fields, raw) {
    var doc = {};
    raw = raw || {};
    var fields_module = require('./fields');

    for (var k in fields) {
        var f = fields[k];
        var r = raw[k];

        if (f instanceof fields_module.Field) {
            if (!f.isEmpty(r)) {
                doc[k] = f.parse(r);
            }
            else if (!f.omit_empty) {
                doc[k] = undefined;
            }
        }
        else if (f instanceof fields_module.Embedded) {
            if (!f.isEmpty(r)) {
                if (typeof r === 'string') {
                    if (r !== '') {
                        doc[k] = JSON.parse(r);
                    } else {
                        doc[k] = {};
                    }
                }
                else {
                    doc[k] = exports.parseRaw(f.type.fields, r);
                }
            }
        }
        else if (f instanceof fields_module.EmbeddedList) {
            doc[k] = [];
            for (var i in r) {
                if (typeof r[i] === 'string') {
                    if (r[i] !== '') {
                        doc[k][i] = JSON.parse(r[i]);
                    } else {
                        doc[k][i] = {};
                    }
                }
                else {
                    doc[k][i] = exports.parseRaw(f.type.fields, r[i]);
                }
            }
            if (!doc[k].length && f.omit_empty) {
                delete doc[k];
            }
        }
        else if (f instanceof Object) {
            doc[k] = exports.parseRaw(f, r);
        } else {
            throw new Error(
                'The field type `' + (typeof f) + '` is not supported.'
            );
        }
    }
    return doc;
};

<|endoftext|>


<commit_before>var fields_module = require('./fields'),
    Field = fields_module.Field,
    types = require('./types'),
    Type = types.Type,
    utils = require('./utils');

var Form = exports.Form = function (obj, doc) {
    this.fields = (obj instanceof Type) ? obj.fields: obj;
    if (doc) {
        this.values = doc;
    }
};

Form.prototype.validate = function (req) {
    this.values = exports.parseRequest(this.fields, req);
    var validation_errors = types.validateFields(
        this.fields, this.values, this.values, [], false
    );
    var required_errors = types.checkRequired(this.fields, this.values, []);
    this.errors = required_errors.concat(validation_errors);
    return this;
};

Form.prototype.toHTML = function (iterator) {
    iterator = iterator || exports.render.div;
    return exports.renderFields(
        iterator, this.fields, this.values, this.errors, []
    );
};

Form.prototype.isValid = function () {
    return (!this.errors || this.errors.length === 0);
};

exports.parseRequest = function (fields, req) {
    var values = {};
    for (var k in req.form) {
        var f = utils.getPropertyPath(fields, k.split('.'));
        if (f instanceof Field) {
            var val = req.form[k];
            // has a value or omit_empty option is false
            if ((val !== undefined && val !== '') || !f.omit_empty) {
                val = f.parse(val);
                utils.setPropertyPath(values, k.split('.'), val);
            }
        }
        else {
            utils.setPropertyPath(values, k.split('.'), req.form[k]);
        }
    }
    return values;
};

exports.getErrors = function (errors, path) {
    if (!errors || !errors.length) {
        return [];
    }
    var errs = [];
    var field_name = path.join('.');
    for (var i = 0; i < errors.length; i++) {
        if (errors[i].field.join('.') === field_name) {
            errs.push(errors[i]);
        }
    }
    return errs;
};

exports.renderFields = function (iterator, fields, values, errors, path) {
    var html = '';
    for (var k in fields) {
        if (fields.hasOwnProperty(k)) {
            var field = fields[k];
            var field_path = path.concat([k]);
            var errs = exports.getErrors(errors, field_path);
            if (field instanceof Field) {
                var name = field_path.join('.');
                var val;
                if (values) {
                    val = utils.getPropertyPath(values, field_path);
                }
                else if (field.default_value) {
                    val = field.default_value;
                }
                else {
                    val = undefined;
                }
                html += iterator(name, field, val, errs);
            }
            else if (utils.isArray(field)) {
                // TODO: handle arrays
                throw new Error('not implemented');
            }
            else {
                var subvalues = utils.getPropertyPath(values, field_path);
                // sub-object, recurse through and check for more fields
                html += exports.renderFields(
                    iterator, field, subvalues, errors, field_path
                );
            }
        }
    }
    return html;
};

/**
 * iterator functions for use with renderFields
 */

var wrapWith = function (tag) {
    return function (name, field, value, errors) {
        var html = '<' + tag +
            ' class="' + field.classes(errors).join(' ') + '">';

        if (field.widget.type === 'hidden') {
            return field.widget.toHTML(name, value);
        }
        else if (field.widget.type === 'multipleCheckbox' ||
           field.widget.type === 'multipleRadio') {
            html += '<fieldset>' +
                '<legend>' + field.labelText(name) + '</legend>' +
                field.errorHTML() +
                field.widget.toHTML(name, value) +
            '</fieldset>';
        }
        else {
            html += field.errorHTML(errors) +
                field.labelHTML(name) +
                field.widget.toHTML(name, value);
        }
        return html + '</' + tag + '>';
    };
};

exports.render = {
    div: wrapWith('div'),
    p: wrapWith('p'),
    li: wrapWith('li'),
    table: function (name, field, value, errors) {
        // TODO: handle multipleCheckbox and multipleRadio fields
        if (field.widget.type === 'hidden') {
            return field.widget.toHTML(name, value);
        }
        return '
' +
            '' + field.labelHTML(name) + '	' +
            '' +
                field.errorHTML(errors) +
                field.widget.toHTML(name, value) +
            '	' +
        '
';
    }
};
<commit_msg>change table rendering of forms to show errors in an additional column<commit_after>var fields_module = require('./fields'),
    Field = fields_module.Field,
    types = require('./types'),
    Type = types.Type,
    utils = require('./utils');

var Form = exports.Form = function (obj, doc) {
    this.fields = (obj instanceof Type) ? obj.fields: obj;
    if (doc) {
        this.values = doc;
    }
};

Form.prototype.validate = function (req) {
    this.values = exports.parseRequest(this.fields, req);
    var validation_errors = types.validateFields(
        this.fields, this.values, this.values, [], false
    );
    var required_errors = types.checkRequired(this.fields, this.values, []);
    this.errors = required_errors.concat(validation_errors);
    return this;
};

Form.prototype.toHTML = function (iterator) {
    iterator = iterator || exports.render.div;
    return exports.renderFields(
        iterator, this.fields, this.values, this.errors, []
    );
};

Form.prototype.isValid = function () {
    return (!this.errors || this.errors.length === 0);
};

exports.parseRequest = function (fields, req) {
    var values = {};
    for (var k in req.form) {
        var f = utils.getPropertyPath(fields, k.split('.'));
        if (f instanceof Field) {
            var val = req.form[k];
            // has a value or omit_empty option is false
            if ((val !== undefined && val !== '') || !f.omit_empty) {
                val = f.parse(val);
                utils.setPropertyPath(values, k.split('.'), val);
            }
        }
        else {
            utils.setPropertyPath(values, k.split('.'), req.form[k]);
        }
    }
    return values;
};

exports.getErrors = function (errors, path) {
    if (!errors || !errors.length) {
        return [];
    }
    var errs = [];
    var field_name = path.join('.');
    for (var i = 0; i < errors.length; i++) {
        if (errors[i].field.join('.') === field_name) {
            errs.push(errors[i]);
        }
    }
    return errs;
};

exports.renderFields = function (iterator, fields, values, errors, path) {
    var html = '';
    for (var k in fields) {
        if (fields.hasOwnProperty(k)) {
            var field = fields[k];
            var field_path = path.concat([k]);
            var errs = exports.getErrors(errors, field_path);
            if (field instanceof Field) {
                var name = field_path.join('.');
                var val;
                if (values) {
                    val = utils.getPropertyPath(values, field_path);
                }
                else if (field.default_value) {
                    val = field.default_value;
                }
                else {
                    val = undefined;
                }
                html += iterator(name, field, val, errs);
            }
            else if (utils.isArray(field)) {
                // TODO: handle arrays
                throw new Error('not implemented');
            }
            else {
                var subvalues = utils.getPropertyPath(values, field_path);
                // sub-object, recurse through and check for more fields
                html += exports.renderFields(
                    iterator, field, subvalues, errors, field_path
                );
            }
        }
    }
    return html;
};

/**
 * iterator functions for use with renderFields
 */

var wrapWith = function (tag) {
    return function (name, field, value, errors) {
        var html = '<' + tag +
            ' class="' + field.classes(errors).join(' ') + '">';

        if (field.widget.type === 'hidden') {
            return field.widget.toHTML(name, value);
        }
        else if (field.widget.type === 'multipleCheckbox' ||
           field.widget.type === 'multipleRadio') {
            html += '<fieldset>' +
                '<legend>' + field.labelText(name) + '</legend>' +
                field.errorHTML() +
                field.widget.toHTML(name, value) +
            '</fieldset>';
        }
        else {
            html += field.errorHTML(errors) +
                field.labelHTML(name) +
                field.widget.toHTML(name, value);
        }
        return html + '</' + tag + '>';
    };
};

exports.render = {
    div: wrapWith('div'),
    p: wrapWith('p'),
    li: wrapWith('li'),
    table: function (name, field, value, errors) {
        // TODO: handle multipleCheckbox and multipleRadio fields
        if (field.widget.type === 'hidden') {
            return field.widget.toHTML(name, value);
        }
        return '
' +
            '' + field.labelHTML(name) + '	' +
            '' +
                field.widget.toHTML(name, value) +
            '	' +
            '' +
                field.errorHTML(errors) +
            '	' +
        '
';
    }
};
<|endoftext|>


<commit_before>import { handleActions } from 'redux-actions';
import { replace } from 'react-router-redux'

import * as model from './model'
import { getTestRun } from '../testRun/redux';
import { getFeature, getScenarios } from '../feature/redux';

// Actions

const PREFIX = 'SCENARIO';

const GET_SCENARIO = `${PREFIX}/GET_SCENARIO`;
const GET_SCENARIO_FULFILED = `${GET_SCENARIO}_FULFILLED`;

const GET_SCENARIO_HISTORY = `${PREFIX}/GET_SCENARIO_HISTORY`;
const GET_SCENARIO_HISTORY_FULFILED = `${GET_SCENARIO_HISTORY}_FULFILLED`;

const GET_SCENARIO_COMMENTS = `${PREFIX}/GET_SCENARIO_COMMENTS`;
const GET_SCENARIO_COMMENTS_FULFILED = `${GET_SCENARIO_COMMENTS}_FULFILLED`;

const UPDATE_SCENARIO_STATE = `${PREFIX}/UPDATE_SCENARIO_STATE`;
//const UPDATE_SCENARIO_STATE_FULFILED = `${UPDATE_SCENARIO_STATE}_FULFILLED`;

const ADD_SCENARIO_COMMENT = `${PREFIX}/ADD_SCENARIO_COMMENT`;

const DELETE_SCENARIO = `${PREFIX}/DELETE_SCENARIO`;

// Action creators

export function loadScenarioPage({ scenarioId }) {
  return async dispatch => {

    const scenarioResult$ = dispatch(getScenario({ scenarioId }));
    const historyResult$ = dispatch(getScenarioHistory({ scenarioId }));
    const commentsResult$ = dispatch(getScenarioComments({ scenarioId }));

    const scenarioResult = await scenarioResult$;
    const scenario = scenarioResult.value;
    const { testRunId, featureId } = scenario;

    const testRunResult$ = dispatch(getTestRun({ testRunId }));
    const featureResult$ = dispatch(getFeature({ featureId }));
    const sameFeatureScenariosResult$ = dispatch(getScenarios({ featureId }));

    await Promise.all([
      scenarioResult$,
      historyResult$,
      commentsResult$,
      testRunResult$,
      featureResult$,
      sameFeatureScenariosResult$,
    ]);

    return null;
  };
}

export function getScenario({ scenarioId }) {
  return {
    type: GET_SCENARIO,
    payload: model.getScenario({ scenarioId }),
    meta: {
      scenarioId,
    },
  };
}

export function getScenarioHistory({ scenarioId }) {
  return {
    type: GET_SCENARIO_HISTORY,
    payload: model.getScenarioHistory({ scenarioId }),
    meta: {
      scenarioId,
    },
  };
}

export function getScenarioComments({ scenarioId }) {
  return {
    type: GET_SCENARIO_COMMENTS,
    payload: model.getScenarioComments({ scenarioId }),
    meta: {
      scenarioId,
    },
  };
}

export function updateScenarioState({ scenarioId, newState }) {
  return {
    type: UPDATE_SCENARIO_STATE,
    payload: model.updateScenarioState({ scenarioId, newState }),
    meta: {
      scenarioId,
    },
  };
}

export function addScenarioComment({ scenarioId, comment }) {
  return {
    type: ADD_SCENARIO_COMMENT,
    payload: model.addScenarioComment({ scenarioId, comment }),
    meta: {
      scenarioId,
    },
  };
}

export function deleteScenario({ scenarioId }) {
  return {
    type: DELETE_SCENARIO,
    payload: model.deleteScenario({ scenarioId }),
    meta: {
      scenarioId,
    },
  };
}

export function updateScenarioStateAndComment({ scenarioId, newState, comment }) {
  return dispatch => {
    const updateScenarioState$ = dispatch(updateScenarioState({
      scenarioId,
      newState,
    }));

    let addComment$ = Promise.resolve(null);
    if (comment) {
      addComment$ = dispatch(addScenarioComment({ scenarioId, comment }));
    }

    return Promise.all([updateScenarioState$, addComment$])
      .then(() => dispatch(loadScenarioPage({ scenarioId })))
      .then(() => null);
  }
}

export function addScenarioCommentAndReload({ scenarioId, comment }) {
  return dispatch => {
    const addComment$ = dispatch(addScenarioComment({ scenarioId, comment }));

    return addComment$
      .then(() => dispatch(loadScenarioPage({ scenarioId })))
      .then(() => null);
  };
}

export function deleteScenarioThenRedirect({ scenarioId }) {
  return (dispatch, getState) => {
    const deleteScenario$ = dispatch(deleteScenario({ scenarioId }));

    const featureId = getState().feature.feature.id;
    deleteScenario$.then(dispatch(replace(`/features/${featureId}`)));
  };
}

export function setNonReviewedStateThenReload({ scenarioId }) {
  return updateScenarioStateAndComment({
    scenarioId,
    newState: {
      reviewed: false,
    },
  });
}

export function setScenarioReviewedStateAndComment({ scenarioId, comment }) {
  return updateScenarioStateAndComment({
    scenarioId,
    newState: {
      reviewed: true,
    },
    comment,
  });
}

// Reducer

const initialState = {
  scenario: {
    info: {},
    allTags: [],
    changes: [],
    steps: [],
    background: {
      steps: [],
    },
    beforeActions: [],
    afterActions: [],
  },
  history: [],
  comments: [],
};

export const scenario = handleActions({

  [GET_SCENARIO_FULFILED]: (state, action) => ({
    ...state,
    scenario: action.payload,
  }),

  [GET_SCENARIO_HISTORY_FULFILED]: (state, action) => ({
    ...state,
    history: action.payload,
  }),

  [GET_SCENARIO_COMMENTS_FULFILED]: (state, action) => ({
    ...state,
    comments: action.payload,
  }),

}, initialState);
<commit_msg>Use async / await<commit_after>import { handleActions } from 'redux-actions';
import { replace } from 'react-router-redux'

import * as model from './model'
import { getTestRun } from '../testRun/redux';
import { getFeature, getScenarios } from '../feature/redux';

// Actions

const PREFIX = 'SCENARIO';

const GET_SCENARIO = `${PREFIX}/GET_SCENARIO`;
const GET_SCENARIO_FULFILED = `${GET_SCENARIO}_FULFILLED`;

const GET_SCENARIO_HISTORY = `${PREFIX}/GET_SCENARIO_HISTORY`;
const GET_SCENARIO_HISTORY_FULFILED = `${GET_SCENARIO_HISTORY}_FULFILLED`;

const GET_SCENARIO_COMMENTS = `${PREFIX}/GET_SCENARIO_COMMENTS`;
const GET_SCENARIO_COMMENTS_FULFILED = `${GET_SCENARIO_COMMENTS}_FULFILLED`;

const UPDATE_SCENARIO_STATE = `${PREFIX}/UPDATE_SCENARIO_STATE`;
//const UPDATE_SCENARIO_STATE_FULFILED = `${UPDATE_SCENARIO_STATE}_FULFILLED`;

const ADD_SCENARIO_COMMENT = `${PREFIX}/ADD_SCENARIO_COMMENT`;

const DELETE_SCENARIO = `${PREFIX}/DELETE_SCENARIO`;

// Action creators

export function loadScenarioPage({ scenarioId }) {
  return async dispatch => {

    const scenarioResult$ = dispatch(getScenario({ scenarioId }));
    const historyResult$ = dispatch(getScenarioHistory({ scenarioId }));
    const commentsResult$ = dispatch(getScenarioComments({ scenarioId }));

    const scenarioResult = await scenarioResult$;
    const scenario = scenarioResult.value;
    const { testRunId, featureId } = scenario;

    const testRunResult$ = dispatch(getTestRun({ testRunId }));
    const featureResult$ = dispatch(getFeature({ featureId }));
    const sameFeatureScenariosResult$ = dispatch(getScenarios({ featureId }));

    await Promise.all([
      scenarioResult$,
      historyResult$,
      commentsResult$,
      testRunResult$,
      featureResult$,
      sameFeatureScenariosResult$,
    ]);

    return null;
  };
}

export function getScenario({ scenarioId }) {
  return {
    type: GET_SCENARIO,
    payload: model.getScenario({ scenarioId }),
    meta: {
      scenarioId,
    },
  };
}

export function getScenarioHistory({ scenarioId }) {
  return {
    type: GET_SCENARIO_HISTORY,
    payload: model.getScenarioHistory({ scenarioId }),
    meta: {
      scenarioId,
    },
  };
}

export function getScenarioComments({ scenarioId }) {
  return {
    type: GET_SCENARIO_COMMENTS,
    payload: model.getScenarioComments({ scenarioId }),
    meta: {
      scenarioId,
    },
  };
}

export function updateScenarioState({ scenarioId, newState }) {
  return {
    type: UPDATE_SCENARIO_STATE,
    payload: model.updateScenarioState({ scenarioId, newState }),
    meta: {
      scenarioId,
    },
  };
}

export function addScenarioComment({ scenarioId, comment }) {
  return {
    type: ADD_SCENARIO_COMMENT,
    payload: model.addScenarioComment({ scenarioId, comment }),
    meta: {
      scenarioId,
    },
  };
}

export function deleteScenario({ scenarioId }) {
  return {
    type: DELETE_SCENARIO,
    payload: model.deleteScenario({ scenarioId }),
    meta: {
      scenarioId,
    },
  };
}

export function updateScenarioStateAndComment({ scenarioId, newState, comment }) {
  return async dispatch => {
    await dispatch(updateScenarioState({
      scenarioId,
      newState,
    }));

    if (comment) {
      await dispatch(addScenarioComment({ scenarioId, comment }));
    }

    await dispatch(loadScenarioPage({ scenarioId }));

    return null;
  }
}

export function addScenarioCommentAndReload({ scenarioId, comment }) {
  return async dispatch => {
    await dispatch(addScenarioComment({ scenarioId, comment }));
    await dispatch(loadScenarioPage({ scenarioId }));

    return null;
  };
}

export function deleteScenarioThenRedirect({ scenarioId }) {
  return async (dispatch, getState) => {
    await dispatch(deleteScenario({ scenarioId }));

    const featureId = getState().feature.feature.id;
    await dispatch(replace(`/features/${featureId}`));

    return null;
  };
}

export function setNonReviewedStateThenReload({ scenarioId }) {
  return updateScenarioStateAndComment({
    scenarioId,
    newState: {
      reviewed: false,
    },
  });
}

export function setScenarioReviewedStateAndComment({ scenarioId, comment }) {
  return updateScenarioStateAndComment({
    scenarioId,
    newState: {
      reviewed: true,
    },
    comment,
  });
}

// Reducer

const initialState = {
  scenario: {
    info: {},
    allTags: [],
    changes: [],
    steps: [],
    background: {
      steps: [],
    },
    beforeActions: [],
    afterActions: [],
  },
  history: [],
  comments: [],
};

export const scenario = handleActions({

  [GET_SCENARIO_FULFILED]: (state, action) => ({
    ...state,
    scenario: action.payload,
  }),

  [GET_SCENARIO_HISTORY_FULFILED]: (state, action) => ({
    ...state,
    history: action.payload,
  }),

  [GET_SCENARIO_COMMENTS_FULFILED]: (state, action) => ({
    ...state,
    comments: action.payload,
  }),

}, initialState);
<|endoftext|>