<commit_before>app.title = '评测记录';
app.links = [];

component.data = function () {
    return {
        paging: {
            current: 1,
            count: 1
        },
        statuses: statuses,
        result: [],
        languages: languages,
        selectedStatus: null,
        selectedProblem: null,
        selectedSubmittor: null,
        selectedLanguage: null,
        selectedContest: {},
        selectedTime: null,
        submittorSearchResult: [],
        problemSearchResult: [],
        view: null
    };
};

component.watch = {
    selectedStatus: function () {
        this.loadStatuses();
    },
    selectedProblem: function () {
        this.loadStatuses();
    },
    selectedSubmittor: function () {
        this.loadStatuses();
    },
    selectedLanguage: function () {
        this.loadStatuses();
    },
    selectedContest: function () {
        this.loadStatuses();
    },
    selectedTime: function () {
        this.loadStatuses();
    },
    'paging.current': function () {
        this.loadStatuses();
    },
    view: function (newVal, oldVal) {
        var fields = getFields(newVal.__cacheInfo.params);
        if (fields.length == 0 || fields.length == 1 && fields[0] == 'page') {
            newVal.subscribe('judge');
        }
    },
    deep: true
};

component.created = function () {
    this.loadStatuses();
};

component.methods = {
    filterStatus: function (status) {
        $('[data-value="' + this.selectedStatus + '"]').removeClass('active');
        if (this.selectedStatus !== null && this.selectedStatus === status) {
            this.selectedStatus = null;
        } else {
            this.selectedStatus = status;
            $('[data-value="' + this.selectedStatus + '"]').addClass('active');
        }
        setTimeout(function () {
            $('.filter-outer').removeClass('active');
        }, 300);
    },
    filterLanguage: function (language) {
        $('[data-value="' + this.selectedLanguage + '"]').removeClass('active');
        if (this.selectedLanguage && this.selectedLanguage == language) {
            this.selectedLanguage = null;
        } else {
            this.selectedLanguage = language;
            $('[data-value="' + this.selectedLanguage + '"]').addClass('active');
        }
        setTimeout(function () {
            $('.filter-outer').removeClass('active');
        }, 300);
    },
    filterTime: function (start, end) {
        if (!start && !end) {
            this.selectedTime = null;
        } else {
            this.selectedTime = { start: start, end: end };
        }
    },
    searchSubmittor: function () {
        var val = $('.textbox-search-submittor').val();
        var self = this;
        if (!val) {
            self.submittorSearchResult = [];
            this.selectedSubmittor = null;
        } else {
            qv.createView('/api/user/all', { username: val }).fetch(x => {
                self.submittorSearchResult = x.data.result.map(y => {
                    return {
                        id: y.id,
                        username: y.userName,
                        avatarUrl: y.avatarUrl,
                        roleClass: null
                    }
                }).slice(0,5);
                qv.createView('/api/user/role', { usernames: self.submittorSearchResult.map(y => y.username).toString()}).fetch(y => {
                    for (var i = 0; i < self.submittorSearchResult.length; i++) {
                        self.submittorSearchResult[i].roleClass = ConvertUserRoleToCss(y.data[self.submittorSearchResult[i].username].role);
                    }
                });
            });
        }
    },
    selectSubmittor: function (username) {
        this.selectedSubmittor = username;
        $('.submit-filter').removeClass('active');
    },
    searchProblem: function () {
        var val = $('.textbox-search-problem').val();
        var self = this;
        if (!val) {
            self.problemSearchResult = [];
            self.selectedProblem = null;
        } else {
            qv.createView('/api/problem/all', { title: val }).fetch(x => {
                self.problemSearchResult = x.data.result.map(y => {
                    return {
                        id: y.id,
                        title: y.title
                    };
                }).slice(0, 5);
            });
        }
    },
    selectProblem: function (id, title) {
        this.selectedProblem = { id: id, title: title };
        $('.problem-filter').removeClass('active');
    },
    selectTimeRange: function () {
        this.selectedTime = {
            begin: $('.time-range-begin').val(),
            end: $('.time-range-end').val()
        };
        $('.time-filter').removeClass('active');
    },
    clearTimeRange: function () {
        this.selectedTime = null;
        $('.time-range-begin').val('')
        $('.time-range-end').val('')
        $('.time-filter').removeClass('active');
    },
    loadStatuses: function () {
        var self = this;
        if (self.view) {
            self.view.unsubscribe();
        }
        self.view = qv.createView('/api/judge/all', {
            problemid: self.selectedProblem ? self.selectedProblem.id : null,
            status: self.selectedStatus,
            userId: self.selectedSubmittor,
            contestId: self.selectedContest.id,
            language: self.selectedLanguage,
            begin: self.selectedTime && self.selectedTime.begin ? new Date(self.selectedTime.begin).toISOString() : null,
            end: self.selectedTime && self.selectedTime.end ? new Date(self.selectedTime.end).toISOString() : null,
            page: self.paging.current
        });
        self.view.fetch(x => {
            if (this.selectedContest.id) {
                app.links = [
                    {
                        text: '比赛列表',
                        to: '/contest'
                    },
                    {
                        text: this.selectedContest.title,
                        to: { name: '/contest/:id', path: '/contest/' + this.selectedContest.id, params: { id: this.selectedContest.id } }
                    }
                ];
            }

            self.paging.count = x.data.count;
            self.paging.current = x.data.current;
            self.result = x.data.result.map(y =>
            {
                var ret = clone(y);
                ret.result = formatJudgeResult(y.result);
                ret.resultClass = ConvertJudgeResultToCss(ret.result);
                ret.iconClass = ConvertJudgeResultToIconCss(ret.result);
                ret.userName = y.userId.substr(0, 8);
                ret.roleClass = null;
                ret.problemTitle = app.lookup.problem[ret.problemId];
                return ret;
            });

            if (self.result.length) {
                var cachedProblems = Object.getOwnPropertyNames(app.lookup.problem);
                var uncachedProblems = x.data.result.map(y => y.problemId).filter(y => !cachedProblems.some(z => z == y));
                if (uncachedProblems.length) {
                    qv.get('/api/problem/title', { problemids: uncachedProblems.toString() })
                        .then(y => {
                            for (var i = 0; i < self.result.length; i++) {
                                app.lookup.problem[self.result[i].problemId] = y.data[self.result[i].problemId].title;
                                self.result[i].problemTitle = app.lookup.problem[self.result[i].problemId];
                            }
                            self.$forceUpdate();
                        });
                }

                qv.createView('/api/user/role', { userids: x.data.result.map(y => y.userId).toString() })
                    .fetch(y => {
                        for (var i = 0; i < self.result.length; i++) {
                            self.result[i].userName = y.data[self.result[i].userId].username;
                            self.result[i].userRole = y.data[self.result[i].userId].role;
                            self.result[i].roleClass = ConvertUserRoleToCss(self.result[i].userRole);
                        }
                        self.$forceUpdate();
                    })
            }

            self.view.subscribe('judge');
        });
    }
};<commit_msg>Implement user look up dictionary<commit_after>app.title = '评测记录';
app.links = [];

component.data = function () {
    return {
        paging: {
            current: 1,
            count: 1
        },
        statuses: statuses,
        result: [],
        languages: languages,
        selectedStatus: null,
        selectedProblem: null,
        selectedSubmittor: null,
        selectedLanguage: null,
        selectedContest: {},
        selectedTime: null,
        submittorSearchResult: [],
        problemSearchResult: [],
        view: null
    };
};

component.watch = {
    selectedStatus: function () {
        this.loadStatuses();
    },
    selectedProblem: function () {
        this.loadStatuses();
    },
    selectedSubmittor: function () {
        this.loadStatuses();
    },
    selectedLanguage: function () {
        this.loadStatuses();
    },
    selectedContest: function () {
        this.loadStatuses();
    },
    selectedTime: function () {
        this.loadStatuses();
    },
    'paging.current': function () {
        this.loadStatuses();
    },
    view: function (newVal, oldVal) {
        var fields = getFields(newVal.__cacheInfo.params);
        if (fields.length == 0 || fields.length == 1 && fields[0] == 'page') {
            newVal.subscribe('judge');
        }
    },
    deep: true
};

component.created = function () {
    this.loadStatuses();
};

component.methods = {
    filterStatus: function (status) {
        $('[data-value="' + this.selectedStatus + '"]').removeClass('active');
        if (this.selectedStatus !== null && this.selectedStatus === status) {
            this.selectedStatus = null;
        } else {
            this.selectedStatus = status;
            $('[data-value="' + this.selectedStatus + '"]').addClass('active');
        }
        setTimeout(function () {
            $('.filter-outer').removeClass('active');
        }, 300);
    },
    filterLanguage: function (language) {
        $('[data-value="' + this.selectedLanguage + '"]').removeClass('active');
        if (this.selectedLanguage && this.selectedLanguage == language) {
            this.selectedLanguage = null;
        } else {
            this.selectedLanguage = language;
            $('[data-value="' + this.selectedLanguage + '"]').addClass('active');
        }
        setTimeout(function () {
            $('.filter-outer').removeClass('active');
        }, 300);
    },
    filterTime: function (start, end) {
        if (!start && !end) {
            this.selectedTime = null;
        } else {
            this.selectedTime = { start: start, end: end };
        }
    },
    searchSubmittor: function () {
        var val = $('.textbox-search-submittor').val();
        var self = this;
        if (!val) {
            self.submittorSearchResult = [];
            this.selectedSubmittor = null;
        } else {
            qv.createView('/api/user/all', { username: val }).fetch(x => {
                self.submittorSearchResult = x.data.result.map(y => {
                    return {
                        id: y.id,
                        username: y.userName,
                        avatarUrl: y.avatarUrl,
                        roleClass: app.lookup.user[y.id] ? app.lookup.user[y.id].class : undefined
                    }
                }).slice(0, 5);

                var cachedUsers = Object.getOwnPropertyNames(app.lookup.user);
                var uncachedUsers = self.submittorSearchResult.map(y => y.username).filter(y => !cachedUsers.some(z => z == y));
                if (uncachedUsers.length) {
                    qv.get('/api/user/role', { usernames: self.submittorSearchResult.map(y => y.username).toString() }).then(y => {
                        for (var z in y.data) {
                            app.lookup.user[z] = {
                                id: z.id,
                                avatar: y.data[z].avatarUrl,
                                name: y.data[z].username,
                                role: y.data[z].role,
                                class: ConvertUserRoleToCss(y.data[z].role)
                            };

                            app.lookup[y.data[z].username] = app.lookup.user[z];

                            var impactedResults = self.submittorSearchResult.filter(r => r.username == z);
                            for (var i in impactedResults) {
                                impactedResults[i].roleClass = app.lookup.user[z].class;
                            }
                        }
                    });
                }
            });
        }
    },
    selectSubmittor: function (username) {
        this.selectedSubmittor = username;
        $('.submit-filter').removeClass('active');
    },
    searchProblem: function () {
        var val = $('.textbox-search-problem').val();
        var self = this;
        if (!val) {
            self.problemSearchResult = [];
            self.selectedProblem = null;
        } else {
            qv.createView('/api/problem/all', { title: val }).fetch(x => {
                self.problemSearchResult = x.data.result.map(y => {
                    return {
                        id: y.id,
                        title: y.title
                    };
                }).slice(0, 5);
            });
        }
    },
    selectProblem: function (id, title) {
        this.selectedProblem = { id: id, title: title };
        $('.problem-filter').removeClass('active');
    },
    selectTimeRange: function () {
        this.selectedTime = {
            begin: $('.time-range-begin').val(),
            end: $('.time-range-end').val()
        };
        $('.time-filter').removeClass('active');
    },
    clearTimeRange: function () {
        this.selectedTime = null;
        $('.time-range-begin').val('')
        $('.time-range-end').val('')
        $('.time-filter').removeClass('active');
    },
    loadStatuses: function () {
        var self = this;
        if (self.view) {
            self.view.unsubscribe();
        }
        self.view = qv.createView('/api/judge/all', {
            problemid: self.selectedProblem ? self.selectedProblem.id : null,
            status: self.selectedStatus,
            userId: self.selectedSubmittor,
            contestId: self.selectedContest.id,
            language: self.selectedLanguage,
            begin: self.selectedTime && self.selectedTime.begin ? new Date(self.selectedTime.begin).toISOString() : null,
            end: self.selectedTime && self.selectedTime.end ? new Date(self.selectedTime.end).toISOString() : null,
            page: self.paging.current
        });
        self.view.fetch(x => {
            if (this.selectedContest.id) {
                app.links = [
                    {
                        text: '比赛列表',
                        to: '/contest'
                    },
                    {
                        text: this.selectedContest.title,
                        to: { name: '/contest/:id', path: '/contest/' + this.selectedContest.id, params: { id: this.selectedContest.id } }
                    }
                ];
            }

            self.paging.count = x.data.count;
            self.paging.current = x.data.current;
            self.result = x.data.result.map(y =>
            {
                var ret = clone(y);
                ret.result = formatJudgeResult(y.result);
                ret.resultClass = ConvertJudgeResultToCss(ret.result);
                ret.iconClass = ConvertJudgeResultToIconCss(ret.result);
                ret.userName = app.lookup.user[y.userId] ? app.lookup.user[y.userId].name : y.userId.substr(0, 8);
                ret.userRole = app.lookup.user[y.userId] ? app.lookup.user[y.userId].role : undefined;
                ret.roleClass = app.lookup.user[y.userId] ? app.lookup.user[y.userId].class : undefined;
                ret.problemTitle = app.lookup.problem[ret.problemId];
                return ret;
            });

            if (self.result.length) {
                var cachedProblems = Object.getOwnPropertyNames(app.lookup.problem);
                var uncachedProblems = x.data.result.map(y => y.problemId).filter(y => !cachedProblems.some(z => z == y));
                if (uncachedProblems.length) {
                    qv.get('/api/problem/title', { problemids: uncachedProblems.toString() })
                        .then(y => {
                            for (var z in y.data) {
                                app.lookup.problem[z] = y.data[z].title;
                                var impactedResults = self.result.filter(a => a.problemId == z);
                                for (var i in impactedResults) {
                                    impactedResults[i].problemTitle = app.lookup.problem[z];
                                }
                            }
                            self.$forceUpdate();
                        });
                }

                var cachedUsers = Object.getOwnPropertyNames(app.lookup.user);
                var uncachedUsers = x.data.result.map(y => y.userId).filter(y => !cachedUsers.some(z => z == y));
                if (uncachedUsers.length) {
                    qv.get('/api/user/role', { userids: uncachedUsers.toString() })
                        .then(y => {
                            for (var z in y.data) {
                                app.lookup.user[z] = {
                                    id: z.id,
                                    avatar: y.data[z].avatarUrl,
                                    name: y.data[z].username,
                                    role: y.data[z].role,
                                    class: ConvertUserRoleToCss(y.data[z].role)
                                };

                                app.lookup[y.data[z].id] = app.lookup.user[z];

                                var impactedResults = self.result.filter(a => a.userId == z);
                                for (var i in impactedResults) {
                                    impactedResults[i].userName = app.lookup.user[z].name;
                                    impactedResults[i].userRole = app.lookup.user[z].role;
                                    impactedResults[i].roleClass = app.lookup.user[z].class;
                                }
                            }
                            self.$forceUpdate();
                        });
                }
            }

            self.view.subscribe('judge');
        });
    }
};<|endoftext|>


<commit_before>var Q = require('q');

var Twit = require('twit');

var models = require('../models');
var utils = require('../helpers/utils');
var config = require('../config');
var match = require('../helpers/match')
var tweetBuilder = require('./tweetBuilder');

var T = new Twit(config.twitter);

function removeHashTag(text) {
  return text.replace(/#\w+/i, '');
}

function removeUser(text) {
  return text.replace(/@\w/i, '')
}

function parseFieldsFromTweet(tweet, fields) {
  var parsed = {};
  var mapFields = {
    id: 'id',
    name: 'user.name',
    screen_name: 'user.screen_name',
    text: 'text',
    hashtags: 'entities.hashtags'
  }

  fields.forEach(function(k) {
    if (k in mapFields) {
      parsed[k] = utils.getField(tweet, mapFields[k], 'none '+k);
    }
  })

  return parsed;
}

function getLocation(id) {
  console.log(getLocation);
  return Q.promise(function (resolve, reject) {
    T.get('statuses/show/:id', {id: id}, function (err, data, response) {
      console.log(err, id);
      console.log(data);
    });
  });
}

function findScheduleAndPost(msg, screen_name) {

  match.parseQueryFromTweet(msg)
    .then(models.schedule.getOne)
    .then(function(data) {
      if(!data.schedule) {
        data.schedule = 'No schedule found';
      };
      var posts = tweetBuilder.createPosts(screen_name, data);
      posts.forEach(function(post) {
        postTweet(post);
      })
    });
}

function handleNewTweet(tweet) {

  console.log('------------------on tweet --------------------------');
  var tweetFields = parseFieldsFromTweet(tweet,
                     ['id', 'name', 'screen_name', 'text', 'hashtags']);

  if (msg.indexOf('boterino123') < 0 && msg.indexOf(config.hashtag) < 0) {
    return;
  }
  var msg = removeHashTag(tweetFields.text);
  msg = removeUser(msg);

  var msgClean = utils.cleanSpaces(msg);
  console.log(tweetFields);
  console.log('msgClean', msgClean);
  if ( msgClean === 'help' || !msgClean.length ) {
    var post = tweetBuilder.createHelpMsg(tweetFields.screen_name);
    postTweet(post);
    return;
  }

  findScheduleAndPost(msg, tweetFields.screen_name);

}

function listenStream(hashtag) {
  T.stream('statuses/filter', { track: hashtag});
  T.stream('user').on('tweet',handleNewTweet);;

}

function postTweet(message) {
  T.post('statuses/update', {status: message},
    function(err, data, response) {
      if (err) return console.log(err);
      console.log('posted', message);
    }
  )
}

// var mongoose = require('mongoose');
// var config = require('../config');

// mongoose.connect(config.mongoConnection);

// findScheduleAndPost('larcomar Terminator ', 'ggwp')

module.exports.listenStream = listenStream;<commit_msg>hashtag and user bug<commit_after>var Q = require('q');

var Twit = require('twit');

var models = require('../models');
var utils = require('../helpers/utils');
var config = require('../config');
var match = require('../helpers/match')
var tweetBuilder = require('./tweetBuilder');

var T = new Twit(config.twitter);

function removeHashTag(text) {
  return text.replace(/#\w+/i, '');
}

function removeUser(text) {
  return text.replace(/@\w/i, '')
}

function parseFieldsFromTweet(tweet, fields) {
  var parsed = {};
  var mapFields = {
    id: 'id',
    name: 'user.name',
    screen_name: 'user.screen_name',
    text: 'text',
    hashtags: 'entities.hashtags'
  }

  fields.forEach(function(k) {
    if (k in mapFields) {
      parsed[k] = utils.getField(tweet, mapFields[k], 'none '+k);
    }
  })

  return parsed;
}

function getLocation(id) {
  console.log(getLocation);
  return Q.promise(function (resolve, reject) {
    T.get('statuses/show/:id', {id: id}, function (err, data, response) {
      console.log(err, id);
      console.log(data);
    });
  });
}

function findScheduleAndPost(msg, screen_name) {

  match.parseQueryFromTweet(msg)
    .then(models.schedule.getOne)
    .then(function(data) {
      if(!data.schedule) {
        data.schedule = 'No schedule found';
      };
      var posts = tweetBuilder.createPosts(screen_name, data);
      posts.forEach(function(post) {
        postTweet(post);
      })
    });
}

function handleNewTweet(tweet) {

  var tweetFields = parseFieldsFromTweet(tweet,
                     ['id', 'name', 'screen_name', 'text', 'hashtags']);
  var msg = tweetFields.msg
  if (msg.indexOf('boterino123') < 0 && msg.indexOf(config.hashtag) < 0) {
    return;
  }
  console.log('------------------on tweet --------------------------');
  var msg = removeHashTag(msg);
  msg = removeUser(msg);

  var msgClean = utils.cleanSpaces(msg);
  console.log(tweetFields);
  console.log('msgClean', msgClean);
  if ( msgClean === 'help' || !msgClean.length ) {
    var post = tweetBuilder.createHelpMsg(tweetFields.screen_name);
    postTweet(post);
    return;
  }

  findScheduleAndPost(msg, tweetFields.screen_name);

}

function listenStream(hashtag) {
  T.stream('statuses/filter', { track: hashtag});
  T.stream('user').on('tweet',handleNewTweet);;

}

function postTweet(message) {
  T.post('statuses/update', {status: message},
    function(err, data, response) {
      if (err) return console.log(err);
      console.log('posted', message);
    }
  )
}

// var mongoose = require('mongoose');
// var config = require('../config');

// mongoose.connect(config.mongoConnection);

// findScheduleAndPost('larcomar Terminator ', 'ggwp')

module.exports.listenStream = listenStream;<|endoftext|>


<commit_before>var kunstmaanbundles = kunstmaanbundles || {};

kunstmaanbundles.nestedForm = (function(window, undefined) {

    var init, setupForm,
        addNewItem, delItem,
        addNewBtn, addDelBtn, showOrHideActions,
        updateSortkeys;

    var newButtonHtml = '<button type="button" class="js-nested-form__add-btn btn btn-primary btn--raise-on-hover nested-form__add-btn">Add</button>';
    var delButtonHtml = '<button type="button" class="js-nested-form__del-btn btn--raise-on-hover nested-form__item__header__actions__action nested-form__item__header__actions__action--del"></button>'

    init = function() {
        $('.js-nested-form').each(function() {
            var $form = $(this),
                initialized = $form.data('initialized');

            if(!initialized) {
                setupForm($form);
                $form.data('initialized', true);
            }

        });
    };

    // Initial Setup
    setupForm = function($form) {
        var sortable = $form.data('sortable'),
            allowNew = $form.data('allow-new'),
            allowDelete = $form.data('allow-delete'),
            minItems = $form.data('min-items'),
            maxItems = $form.data('max-items'),
            $currentItems = $form.find('.js-nested-form__item');

        // Set index
        var totalItems = $currentItems.length;
            $form.data('index', totalItems);

        // Add "New" button
        if(allowNew) {
            addNewBtn($form);
        }

        // Add "Delete" button
        if(allowDelete) {
            $currentItems.each(function() {
                addDelBtn($(this), $form);
            });
        }

        // Make sure we have at least as many items than minimally required
        if (minItems > 0 && minItems > totalItems) {
            var newNeeded = minItems - totalItems;

            for (var i=0; i<newNeeded; i++) {
                addNewItem($form);
            }
        }

        // Check Actions
        showOrHideActions($form);

        // Update Sortkeys
        if(sortable) {
            $form.on('sort', function() {
                updateSortkeys($form);
            });
        }
    };

    // Show/Hide Actions (New and Delete buttons)
    showOrHideActions = function($form) {
        var allowNew = $form.data('allow-new'),
            allowDelete = $form.data('allow-delete'),
            minItems = $form.data('min-items'),
            maxItems = $form.data('max-items'),
            totalItems = $form.find('.js-nested-form__item').length;

        var $newBtn = $form.find('.js-nested-form__add-btn'),
            $delBtn = $form.find('.js-nested-form__del-btn');

        // "New" button
        if(allowNew && (maxItems === false || totalItems < maxItems)) {
            $newBtn.removeClass('hidden');
        } else {
            $delBtn.addClass('hidden');
        }

        // "Delete" button
        if(allowDelete && totalItems > minItems) {
            $delBtn.removeClass('hidden');
        } else {
            $delBtn.addClass('hidden');
        }
    };

    // Add "New" button
    addNewBtn = function($form) {
        var $newBtn = $(newButtonHtml);

        $form.append($newBtn);

        $newBtn.on('click', function() {
            addNewItem($form);
        });
    };

    // Add "Delete" button
    addDelBtn = function($item, $form) {
        var $actionBar = $item.find('.js-nested-form__item__header__actions'),
            $delBtn = $(delButtonHtml);

        $actionBar.append($delBtn);

        $delBtn.on('click', function() {
            delItem($(this), $form, $item)
        });
    };

    // Add new item
    addNewItem = function($form) {
        var prototype = $form.data('prototype'),
            currentIndex = $form.data('index'),
            sortable = $form.data('sortable');

        // Update prototype with new index
        prototype = prototype.replace(/__name__/g, currentIndex);

        // Increase the index with one for the next item
        $form.data('index', currentIndex + 1);

        // Make item template
        if(sortable) {
            var sortKey = $form.data('sortkey').replace(/__name__/g, currentIndex);
            var $newItem = $('

');
        } else {
            var $newItem = $('

');
        }

        $newItem.find('.js-nested-form__item__view').append(prototype);

        // Append before "New" button
        var $newBtn = $form.find('.js-nested-form__add-btn');

        $newBtn.before($newItem);

        // Add "Delete" button
        addDelBtn($newItem, $form);

        // Reinit rich Editors
        kunstmaanbundles.richEditor.destroyRichEditors();
        kunstmaanbundles.richEditor.init();

        // Init Ajax Modals
        kunstmaanbundles.ajaxModal.resetAjaxModals();

        // Update sortkeys
        if(sortable) {
            updateSortkeys($form);
        }
    };

    // Delete item
    delItem = function($btn, $form, $item) {
        var delKey = $item.data('delete-key'),
            sortable = $form.data('sortable');

        // Set delKey
        if(delKey) {
            $form.append('<input type="hidden" name="' + delKey + '" value="1">');
        }

        // Remove item
        $item.remove();

        // Check that we need to show/hide the add/delete buttons
        showOrHideActions($form);

        // Update sortkeys
        if(sortable) {
            updateSortkeys($form);
        }
    };

    // Update Sortkeys
    updateSortkeys = function($form) {
        var key = 0,
            $currentItems = $form.find('.js-nested-form__item');

        $currentItems.each(function() {
            var fieldId = $(this).data('sortkey');

            if (fieldId === undefined) {
                return;
            }

            $('#' + fieldId).val(key++);
        });
    };

    return {
        init: init
    };

}(window));
<commit_msg>fix also for nested forms<commit_after>var kunstmaanbundles = kunstmaanbundles || {};

kunstmaanbundles.nestedForm = (function(window, undefined) {

    var init, setupForm,
        addNewItem, delItem,
        addNewBtn, addDelBtn, showOrHideActions,
        updateSortkeys;

    var newButtonHtml = '<button type="button" class="js-nested-form__add-btn btn btn-primary btn--raise-on-hover nested-form__add-btn">Add</button>';
    var delButtonHtml = '<button type="button" class="js-nested-form__del-btn btn--raise-on-hover nested-form__item__header__actions__action nested-form__item__header__actions__action--del"></button>'

    init = function() {
        $('.js-nested-form').each(function() {
            var $form = $(this),
                initialized = $form.data('initialized');

            if(!initialized) {
                setupForm($form);
                $form.data('initialized', true);
            }

        });
    };

    // Initial Setup
    setupForm = function($form) {
        var sortable = $form.data('sortable'),
            allowNew = $form.data('allow-new'),
            allowDelete = $form.data('allow-delete'),
            minItems = $form.data('min-items'),
            maxItems = $form.data('max-items'),
            $currentItems = $form.find('.js-nested-form__item');

        // Set index
        var totalItems = $currentItems.length;
            $form.data('index', totalItems);

        // Add "New" button
        if(allowNew) {
            addNewBtn($form);
        }

        // Add "Delete" button
        if(allowDelete) {
            $currentItems.each(function() {
                addDelBtn($(this), $form);
            });
        }

        // Make sure we have at least as many items than minimally required
        if (minItems > 0 && minItems > totalItems) {
            var newNeeded = minItems - totalItems;

            for (var i=0; i<newNeeded; i++) {
                addNewItem($form);
            }
        }

        // Check Actions
        showOrHideActions($form);

        // Update Sortkeys
        if(sortable) {
            $form.on('sort', function() {
                updateSortkeys($form);
            });
        }
    };

    // Show/Hide Actions (New and Delete buttons)
    showOrHideActions = function($form) {
        var allowNew = $form.data('allow-new'),
            allowDelete = $form.data('allow-delete'),
            minItems = $form.data('min-items'),
            maxItems = $form.data('max-items'),
            totalItems = $form.find('.js-nested-form__item').length;

        var $newBtn = $form.find('.js-nested-form__add-btn'),
            $delBtn = $form.find('.js-nested-form__del-btn');

        // "New" button
        if(allowNew && (maxItems === false || totalItems < maxItems)) {
            $newBtn.removeClass('hidden');
        } else {
            $delBtn.addClass('hidden');
        }

        // "Delete" button
        if(allowDelete && totalItems > minItems) {
            $delBtn.removeClass('hidden');
        } else {
            $delBtn.addClass('hidden');
        }
    };

    // Add "New" button
    addNewBtn = function($form) {
        var $newBtn = $(newButtonHtml);

        $form.append($newBtn);

        $newBtn.on('click', function() {
            addNewItem($form);
        });
    };

    // Add "Delete" button
    addDelBtn = function($item, $form) {
        var $actionBar = $item.find('.js-nested-form__item__header__actions'),
            $delBtn = $(delButtonHtml);

        $actionBar.append($delBtn);

        $delBtn.on('click', function() {
            delItem($(this), $form, $item)
        });
    };

    // Add new item
    addNewItem = function($form) {
        var prototype = $form.data('prototype'),
            currentIndex = $form.data('index'),
            sortable = $form.data('sortable');

        // Update prototype with new index
        prototype = prototype.replace(/__name__/g, currentIndex);

        // Increase the index with one for the next item
        $form.data('index', currentIndex + 1);

        // Make item template
        if(sortable) {
            var sortKey = $form.data('sortkey').replace(/__name__/g, currentIndex);
            var $newItem = $('

');
        } else {
            var $newItem = $('

');
        }

        $newItem.find('.js-nested-form__item__view').append(prototype);

        // Append before "New" button
        var $newBtn = $form.find('.js-nested-form__add-btn');

        $newBtn.before($newItem);

        // Add "Delete" button
        addDelBtn($newItem, $form);

        // Reinit rich Editors
        kunstmaanbundles.richEditor.destroyRichEditors();
        kunstmaanbundles.richEditor.init();

        // Init new tooltips
        kunstmaanbundles.tooltip.init();

        // Init new colorpickers
        kunstmaanbundles.colorpicker.init();

        // Init Ajax Modals
        kunstmaanbundles.ajaxModal.resetAjaxModals();

        // Update sortkeys
        if(sortable) {
            updateSortkeys($form);
        }
    };

    // Delete item
    delItem = function($btn, $form, $item) {
        var delKey = $item.data('delete-key'),
            sortable = $form.data('sortable');

        // Set delKey
        if(delKey) {
            $form.append('<input type="hidden" name="' + delKey + '" value="1">');
        }

        // Remove item
        $item.remove();

        // Check that we need to show/hide the add/delete buttons
        showOrHideActions($form);

        // Update sortkeys
        if(sortable) {
            updateSortkeys($form);
        }
    };

    // Update Sortkeys
    updateSortkeys = function($form) {
        var key = 0,
            $currentItems = $form.find('.js-nested-form__item');

        $currentItems.each(function() {
            var fieldId = $(this).data('sortkey');

            if (fieldId === undefined) {
                return;
            }

            $('#' + fieldId).val(key++);
        });
    };

    return {
        init: init
    };

}(window));
<|endoftext|>


<commit_before>iD.oneWayTags = {
    'aerialway': {
        'chair_lift': true,
        'mixed_lift': true,
        't-bar': true,
        'j-bar': true,
        'platter': true,
        'rope_tow': true,
        'magic_carpet': true,
        'yes': true
    },
    'highway': {
        'motorway': true,
        'motorway_link': true
    },
    'junction': {
        'roundabout': true
    },
    'man_made': {
        'piste:halfpipe': true,
        'pipeline': true
    },
    'piste:type': {
        'downhill': true,
        'sled': true,
        'yes': true
    },
    'waterway': {
        'river': true,
        'stream': true
    }
};
<commit_msg>man_made=pipeline doesn't imply oneway thread: https://lists.openstreetmap.org/pipermail/tagging/2014-June/017944.html<commit_after>iD.oneWayTags = {
    'aerialway': {
        'chair_lift': true,
        'mixed_lift': true,
        't-bar': true,
        'j-bar': true,
        'platter': true,
        'rope_tow': true,
        'magic_carpet': true,
        'yes': true
    },
    'highway': {
        'motorway': true,
        'motorway_link': true
    },
    'junction': {
        'roundabout': true
    },
    'man_made': {
        'piste:halfpipe': true
    },
    'piste:type': {
        'downhill': true,
        'sled': true,
        'yes': true
    },
    'waterway': {
        'river': true,
        'stream': true
    }
};
<|endoftext|>


<commit_before>$(document).ready(function () {
    // load fixtures
    $(document.body).append('
' +
        '' +
        '' +
        '<input type="text" id="card-player-answer">' +
        '<button id="card-player-show-hint"></button>' +
        '
');

    // define specs
    describe('CardPlayer', function () {
        var player = null;

        describe('when created', function () {
            beforeAll(function () {
                player = createCardPlayer('empty');
            });
            it('has no cards', function () {
                expect(player.cards).toEqual([]);
            });
            it('has no current card loaded', function () {
                expect(player.currentIndex).toEqual(null);
            });
            it('knows where questions are shown', function () {
                expect(player.question).toEqual($('#card-player-question'));
            });
            it('knows where answers are typed in', function () {
                expect(player.answer).toEqual($('#card-player-answer'));
            });
            it('knows where hints are shown', function () {
                expect(player.hint).toEqual($('#card-player-hint'));
            });
            it('knows when hints are shown', function () {
                expect(player.showHint).toEqual($('#card-player-show-hint'));
            });
        });

        describe('can add a card', function () {
            beforeAll(function () {
                player = createCardPlayer('empty');
            });
            it('based on question and answer', function () {
                player.addCard('bat', 'прилеп');
                expect(player.cards[0].question).toEqual('bat');
                expect(player.cards[0].answer).toEqual('прилеп');
            });
        });

        describe('can fetch the correct answer for the current card', function () {
            beforeAll(function () {
                player = createCardPlayer('full');
                player.loadNextCard();
            });
            it('by checking the current card answer', function () {
                expect(player.getCorrectAnswer()).toEqual('котка');
            });
        });

        describe('can load the next card', function () {
            beforeEach(function () {
                player = createCardPlayer('full');
            });
            it('by setting it as current', function () {
                player.loadNextCard();
                expect(player.currentIndex).toEqual(0);
            });
            it('by showing it\'s question', function () {
                player.loadNextCard();
                expect(player.question.html()).toEqual('cat');
            });
            it('by removing the previous answer', function () {
                player.answer.val('come on');
                player.loadNextCard();
                expect(player.answer.val()).toEqual('');
            });
            it('by clearing the hint', function () {
                player.hint.html('some good old hint');
                player.loadNextCard();
                expect(player.hint.html()).toEqual('');
            });
            it('by finishing the player if there are no more left', function () {
                spyOn(player, 'finish');
                for (var i = 0; i <= 3; i++) {
                    player.loadNextCard();
                }
                expect(player.finish).not.toHaveBeenCalled();
                player.loadNextCard();
                expect(player.finish).toHaveBeenCalled();
            });
        });

        describe('can answer the current card', function () {
            beforeEach(function () {
                player = createCardPlayer('full');
                player.loadNextCard();
            });
            it('by loading the next card if correct (even if case does not match)', function () {
                spyOn(player, 'loadNextCard');
                player.answer.val('коТКа');
                player.answerCurrentCard();
                expect(player.loadNextCard).toHaveBeenCalled();
            });
            it('by doing nothing if incorrect', function () {
                spyOn(player, 'loadNextCard');
                player.answer.val('котк');
                player.answerCurrentCard();
                expect(player.loadNextCard).not.toHaveBeenCalled();
            });
        });

        describe('can show a hint for the current card', function () {
            it('by showing the correct answer', function () {
                player = createCardPlayer('full');
                player.loadNextCard();
                player.showCurrentCardHint();
                expect(player.hint.html()).toEqual('котка');
            });
        });

        describe('can be started', function () {
            beforeAll(function () {
                player = createCardPlayer('full');
                spyOn(player, 'loadNextCard');
                spyOn(player, 'answerCurrentCard');
                spyOn(player, 'showCurrentCardHint');
                player.start();
            });
            it('by loading the first card', function () {
                expect(player.loadNextCard).toHaveBeenCalled();
            });
            it('by watching for a correct answer each time the user types in something', function () {
                player.answer.keyup();
                expect(player.answerCurrentCard).toHaveBeenCalled();
            });
            it('by watching for clicks on the show hint button', function () {
                player.showHint.click();
                expect(player.showCurrentCardHint).toHaveBeenCalled();
            });
        });

        describe('can be finished', function () {
            beforeAll(function () {
                player = createCardPlayer('full');
                player.start();
                player.answer.val('great');
                spyOn(player, 'answerCurrentCard');
                spyOn(player, 'showCurrentCardHint');
                player.finish();
            });
            it('by showing the finished message', function () {
                expect(player.question.html()).toEqual('No more cards to learn.');
            });
            it('by removing the last answer', function () {
                expect(player.answer.val()).toEqual('');
            });
            it('by not watching for a correct answer anymore', function () {
                player.answer.keyup();
                expect(player.answerCurrentCard).not.toHaveBeenCalled();
            });
            it('by not watching for clicks on the show hint button anymore', function () {
                player.showHint.click();
                expect(player.showCurrentCardHint).not.toHaveBeenCalled();
            });
        });
    });
});

/**
 * Initialize different versions of a test card player.
 *
 * @param {string} type Defines the type of player to initialize.
 * @returns {CardPlayer}
 */
function createCardPlayer(type) {
    var player = new CardPlayer(jQuery);
    $('#card-player-question').html('');
    $('#card-player-answer').val('');

    // add cards for each available type
    switch (type) {
        case 'full':
            player.addCard('cat', 'котка');
            player.addCard('dog', 'куче');
            player.addCard('rat', 'плъх');
            player.addCard('котка', 'cat');
            break;
    }

    return player;
};
<commit_msg>Fix all JSLint errors in card player tests.<commit_after>/*global $, CardPlayer, createCardPlayer */
/*global describe, it, expect, spyOn */
/*global beforeAll, beforeEach */

(function () {
    "use strict";
    $(document).ready(function () {
        // load fixtures
        $(document.body).append('
' +
            '' +
            '' +
            '<input type="text" id="card-player-answer">' +
            '<button id="card-player-show-hint"></button>' +
            '
');

        // define specs
        describe('CardPlayer', function () {
            var player = null;

            describe('when created', function () {
                beforeAll(function () {
                    player = createCardPlayer('empty');
                });
                it('has no cards', function () {
                    expect(player.cards).toEqual([]);
                });
                it('has no current card loaded', function () {
                    expect(player.currentIndex).toEqual(null);
                });
                it('knows where questions are shown', function () {
                    expect(player.question).toEqual($('#card-player-question'));
                });
                it('knows where answers are typed in', function () {
                    expect(player.answer).toEqual($('#card-player-answer'));
                });
                it('knows where hints are shown', function () {
                    expect(player.hint).toEqual($('#card-player-hint'));
                });
                it('knows when hints are shown', function () {
                    expect(player.showHint).toEqual($('#card-player-show-hint'));
                });
            });

            describe('can add a card', function () {
                beforeAll(function () {
                    player = createCardPlayer('empty');
                });
                it('based on question and answer', function () {
                    player.addCard('bat', 'прилеп');
                    expect(player.cards[0].question).toEqual('bat');
                    expect(player.cards[0].answer).toEqual('прилеп');
                });
            });

            describe('can fetch the correct answer for the current card', function () {
                beforeAll(function () {
                    player = createCardPlayer('full');
                    player.loadNextCard();
                });
                it('by checking the current card answer', function () {
                    expect(player.getCorrectAnswer()).toEqual('котка');
                });
            });

            describe('can load the next card', function () {
                beforeEach(function () {
                    player = createCardPlayer('full');
                });
                it('by setting it as current', function () {
                    player.loadNextCard();
                    expect(player.currentIndex).toEqual(0);
                });
                it('by showing it\'s question', function () {
                    player.loadNextCard();
                    expect(player.question.html()).toEqual('cat');
                });
                it('by removing the previous answer', function () {
                    player.answer.val('come on');
                    player.loadNextCard();
                    expect(player.answer.val()).toEqual('');
                });
                it('by clearing the hint', function () {
                    player.hint.html('some good old hint');
                    player.loadNextCard();
                    expect(player.hint.html()).toEqual('');
                });
                it('by finishing the player if there are no more left', function () {
                    var i = 1;
                    spyOn(player, 'finish');
                    for (i; i <= 4; i += 1) {
                        player.loadNextCard();
                    }
                    expect(player.finish).not.toHaveBeenCalled();
                    player.loadNextCard();
                    expect(player.finish).toHaveBeenCalled();
                });
            });

            describe('can answer the current card', function () {
                beforeEach(function () {
                    player = createCardPlayer('full');
                    player.loadNextCard();
                });
                it('by loading the next card if correct (even if case does not match)', function () {
                    spyOn(player, 'loadNextCard');
                    player.answer.val('коТКа');
                    player.answerCurrentCard();
                    expect(player.loadNextCard).toHaveBeenCalled();
                });
                it('by doing nothing if incorrect', function () {
                    spyOn(player, 'loadNextCard');
                    player.answer.val('котк');
                    player.answerCurrentCard();
                    expect(player.loadNextCard).not.toHaveBeenCalled();
                });
            });

            describe('can show a hint for the current card', function () {
                it('by showing the correct answer', function () {
                    player = createCardPlayer('full');
                    player.loadNextCard();
                    player.showCurrentCardHint();
                    expect(player.hint.html()).toEqual('котка');
                });
            });

            describe('can be started', function () {
                beforeAll(function () {
                    player = createCardPlayer('full');
                    spyOn(player, 'loadNextCard');
                    spyOn(player, 'answerCurrentCard');
                    spyOn(player, 'showCurrentCardHint');
                    player.start();
                });
                it('by loading the first card', function () {
                    expect(player.loadNextCard).toHaveBeenCalled();
                });
                it('by watching for a correct answer each time the user types in something', function () {
                    player.answer.keyup();
                    expect(player.answerCurrentCard).toHaveBeenCalled();
                });
                it('by watching for clicks on the show hint button', function () {
                    player.showHint.click();
                    expect(player.showCurrentCardHint).toHaveBeenCalled();
                });
            });

            describe('can be finished', function () {
                beforeAll(function () {
                    player = createCardPlayer('full');
                    player.start();
                    player.answer.val('great');
                    spyOn(player, 'answerCurrentCard');
                    spyOn(player, 'showCurrentCardHint');
                    player.finish();
                });
                it('by showing the finished message', function () {
                    expect(player.question.html()).toEqual('No more cards to learn.');
                });
                it('by removing the last answer', function () {
                    expect(player.answer.val()).toEqual('');
                });
                it('by not watching for a correct answer anymore', function () {
                    player.answer.keyup();
                    expect(player.answerCurrentCard).not.toHaveBeenCalled();
                });
                it('by not watching for clicks on the show hint button anymore', function () {
                    player.showHint.click();
                    expect(player.showCurrentCardHint).not.toHaveBeenCalled();
                });
            });
        });
    });

    /**
     * Initialize different versions of a test card player.
     *
     * @param {string} type Defines the type of player to initialize.
     * @returns {CardPlayer}
     */
    function createCardPlayer(type) {
        var player = new CardPlayer($);
        $('#card-player-question').html('');
        $('#card-player-answer').val('');

        // add cards for each available type
        switch (type) {
        case 'full':
            player.addCard('cat', 'котка');
            player.addCard('dog', 'куче');
            player.addCard('rat', 'плъх');
            player.addCard('котка', 'cat');
            break;
        }

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


<commit_before>import React, { Component, Fragment } from 'react';
import {
  StyleSheet,
  View,
  TouchableWithoutFeedback,
  Animated,
  ScrollView,
  Text,
  Linking,
} from 'react-native';
import { connect } from 'react-redux';
import moment from 'moment';
import HtmlView from 'react-native-htmlview';
import Icon from 'react-native-vector-icons/FontAwesome';
import IllustComments from '../screens/Shared/IllustComments';
import NovelComments from '../screens/Shared/NovelComments';
import NovelSeries from '../screens/Shared/NovelSeries';
import RelatedIllusts from '../screens/Shared/RelatedIllusts';
import FollowButtonContainer from '../containers/FollowButtonContainer';
import { connectLocalization } from './Localization';
import Tags from './Tags';
import PXTouchable from './PXTouchable';
import PXThumbnail from './PXThumbnail';
import TagBottomSheet from './TagBottomSheet';
import * as searchHistoryActionCreators from '../common/actions/searchHistory';
import { makeGetTagsWithStatus } from '../common/selectors';
import { SEARCH_TYPES, SCREENS } from '../common/constants';
import { globalStyleVariables } from '../styles';

const styles = StyleSheet.create({
  container: {
    backgroundColor: '#fff',
  },
  backdropContainer: {
    position: 'absolute',
    top: 0,
    left: 0,
    right: 0,
    bottom: 0,
    backgroundColor: 'rgba(0, 0, 0, 0.5)',
  },
  infoContainer: {
    margin: 10,
  },
  sectionContainer: {
    marginBottom: 10,
  },
  sectionHeader: {
    margin: 10,
    flexDirection: 'row',
    justifyContent: 'space-between',
  },
  sectionTitle: {
    fontWeight: 'bold',
  },
  sectionSeriesTitle: {
    color: globalStyleVariables.PRIMARY_COLOR,
  },
  thumnailNameContainer: {
    flexDirection: 'row',
    alignItems: 'center',
  },
  profileContainer: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
  },
  nameContainer: {
    flexDirection: 'column',
    marginLeft: 10,
  },
  captionContainer: {
    marginVertical: 10,
  },
  statContainer: {
    flexDirection: 'row',
    alignItems: 'center',
  },
  title: {
    fontSize: 18,
    fontWeight: 'bold',
    marginBottom: 5,
  },
  seriesTitle: {
    color: globalStyleVariables.PRIMARY_COLOR,
    fontWeight: 'bold',
    marginBottom: 5,
  },
});

class DetailInfoModal extends Component {
  static defaultProps = {
    duration: 300,
    height:
      globalStyleVariables.WINDOW_HEIGHT -
      globalStyleVariables.APPBAR_HEIGHT -
      globalStyleVariables.STATUSBAR_HEIGHT -
      200,
  };

  constructor(props) {
    super(props);
    this.state = {
      animatedHeight: new Animated.Value(0),
      modalVisible: false,
      selectedTag: null,
      isOpenTagBottomSheet: false,
    };
  }

  componentWillReceiveProps(nextProps) {
    const { visible } = nextProps;
    const { visible: prevVisible } = this.props;
    if (visible !== null && visible !== prevVisible) {
      this.setModalVisible(visible);
    }
  }

  setModalVisible = visible => {
    const { height, duration } = this.props;
    const { modalVisible, animatedHeight } = this.state;
    if (visible && !modalVisible) {
      this.setState({ modalVisible: visible });
      Animated.timing(animatedHeight, {
        toValue: height,
        duration,
      }).start();
    } else if (!visible && modalVisible) {
      Animated.timing(animatedHeight, {
        toValue: 0,
        duration,
      }).start(() => {
        this.setState({ modalVisible: visible });
      });
    }
  };

  handleOnCloseModal = () => {
    this.setModalVisible(false);
  };

  handleOnPressAvatar = () => {
    const { onPressAvatar, item } = this.props;
    onPressAvatar(item.user.id);
  };

  handleOnPressLink = url => {
    Linking.canOpenURL(url)
      .then(supported => {
        if (!supported) {
          return null;
        }
        return Linking.openURL(url);
      })
      .catch(err => err);
  };

  handleOnPressTag = tag => {
    const { addSearchHistory, navigation: { push } } = this.props;
    addSearchHistory(tag);
    push(SCREENS.SearchResult, {
      word: tag,
      searchType: SEARCH_TYPES.ILLUST,
    });
  };

  handleOnLongPressTag = tag => {
    this.setState({
      isOpenTagBottomSheet: true,
      selectedTag: tag,
    });
  };

  handleOnCancelTagBottomSheet = () => {
    this.setState({
      isOpenTagBottomSheet: false,
    });
  };

  render() {
    const {
      onCancel,
      item,
      authUser,
      tags,
      i18n,
      navigation,
      highlightTags,
      muteTags,
    } = this.props;
    const {
      animatedHeight,
      modalVisible,
      isOpenTagBottomSheet,
      selectedTag,
    } = this.state;
    if (!modalVisible) {
      return null;
    }
    return (
      <Fragment>
        <TouchableWithoutFeedback onPress={onCancel}>
          <View style={styles.backdropContainer} />
        </TouchableWithoutFeedback>
        <View style={styles.container}>
          <Animated.View style={{ maxHeight: animatedHeight }}>
            <ScrollView>
              <View style={styles.infoContainer}>
                <View style={styles.profileContainer}>
                  <PXTouchable
                    style={styles.thumnailNameContainer}
                    onPress={this.handleOnPressAvatar}
                  >
                    <PXThumbnail uri={item.user.profile_image_urls.medium} />
                    <View style={styles.nameContainer}>
                      <Text>
                        {item.user.name}
                      </Text>
                      <Text>
                        {item.user.account}
                      </Text>
                    </View>
                  </PXTouchable>
                  {((authUser && authUser.id !== item.user.id) || !authUser) &&
                    <FollowButtonContainer userId={item.user.id} />}
                </View>
                <View style={styles.captionContainer}>
                  {item.series &&
                    item.series.id &&
                    <Text style={styles.seriesTitle} selectable>
                      {item.series.title}
                    </Text>}
                  <Text style={styles.title} selectable>
                    {item.title}
                  </Text>
                  <HtmlView
                    value={item.caption}
                    onLinkPress={this.handleOnPressLink}
                    textComponentProps={{ selectable: true }}
                  />
                </View>
                <View style={styles.statContainer}>
                  <Text>
                    {moment(item.create_date).format('YYYY-MM-DD')}
                  </Text>
                  <Icon name="eye" style={{ marginLeft: 10 }} />
                  <Text style={{ marginLeft: 5 }}>
                    {item.total_view}
                  </Text>
                  <Icon name="heart" style={{ marginLeft: 10 }} />
                  <Text style={{ marginLeft: 5 }}>
                    {item.total_bookmarks}
                  </Text>
                </View>
                <Tags
                  tags={tags}
                  onPressTag={this.handleOnPressTag}
                  onLongPressTag={this.handleOnLongPressTag}
                />
              </View>
              <View style={styles.sectionContainer}>
                <View style={styles.sectionHeader}>
                  <Text style={styles.sectionTitle}>
                    {i18n.comments}
                  </Text>
                </View>
                {item.text_length
                  ? <NovelComments
                      novelId={item.id}
                      authorId={item.user.id}
                      isFeatureInDetailPage
                      maxItems={6}
                      navigation={navigation}
                    />
                  : <IllustComments
                      illustId={item.id}
                      authorId={item.user.id}
                      isFeatureInDetailPage
                      maxItems={6}
                      navigation={navigation}
                    />}
              </View>
              {!item.text_length &&
                <View style={styles.sectionContainer}>
                  <View style={styles.sectionHeader}>
                    <Text style={styles.sectionTitle}>
                      {i18n.relatedWorks}
                    </Text>
                  </View>
                  <RelatedIllusts
                    illustId={item.id}
                    listKey={`relatedIllusts-${navigation.state
                      .key}-${item.id}`}
                    isFeatureInDetailPage
                    maxItems={6}
                    navigation={navigation}
                  />
                </View>}
              {item.series &&
                item.series.id &&
                item.text_length > 0 &&
                <View style={styles.sectionContainer}>
                  <View style={styles.sectionHeader}>
                    <Text
                      style={[styles.sectionTitle, styles.sectionSeriesTitle]}
                      selectable
                    >
                      {item.series.title}
                    </Text>
                  </View>
                  <NovelSeries
                    seriesId={item.series.id}
                    seriesTitle={item.series.title}
                    isFeatureInDetailPage
                    maxItems={6}
                    navigation={navigation}
                  />
                </View>}
            </ScrollView>
          </Animated.View>
        </View>
        <TagBottomSheet
          visible={isOpenTagBottomSheet}
          selectedTag={selectedTag}
          isHighlight={highlightTags.includes(selectedTag)}
          isMute={muteTags.includes(selectedTag)}
          navigation={navigation}
          onCancel={this.handleOnCancelTagBottomSheet}
        />
      </Fragment>
    );
  }
}

export default connectLocalization(
  connect(() => {
    const getTagsWithStatus = makeGetTagsWithStatus();
    return (state, props) => ({
      highlightTags: state.highlightTags.items,
      muteTags: state.muteTags.items,
      tags: getTagsWithStatus(state, props),
    });
  }, searchHistoryActionCreators)(DetailInfoModal),
);
<commit_msg>change height for detail info modal<commit_after>import React, { Component, Fragment } from 'react';
import {
  StyleSheet,
  View,
  TouchableWithoutFeedback,
  Animated,
  ScrollView,
  Text,
  Linking,
} from 'react-native';
import { connect } from 'react-redux';
import moment from 'moment';
import HtmlView from 'react-native-htmlview';
import Icon from 'react-native-vector-icons/FontAwesome';
import IllustComments from '../screens/Shared/IllustComments';
import NovelComments from '../screens/Shared/NovelComments';
import NovelSeries from '../screens/Shared/NovelSeries';
import RelatedIllusts from '../screens/Shared/RelatedIllusts';
import FollowButtonContainer from '../containers/FollowButtonContainer';
import { connectLocalization } from './Localization';
import Tags from './Tags';
import PXTouchable from './PXTouchable';
import PXThumbnail from './PXThumbnail';
import TagBottomSheet from './TagBottomSheet';
import * as searchHistoryActionCreators from '../common/actions/searchHistory';
import { makeGetTagsWithStatus } from '../common/selectors';
import { SEARCH_TYPES, SCREENS } from '../common/constants';
import { globalStyleVariables } from '../styles';

const styles = StyleSheet.create({
  container: {
    backgroundColor: '#fff',
  },
  backdropContainer: {
    position: 'absolute',
    top: 0,
    left: 0,
    right: 0,
    bottom: 0,
    backgroundColor: 'rgba(0, 0, 0, 0.5)',
  },
  infoContainer: {
    margin: 10,
  },
  sectionContainer: {
    marginBottom: 10,
  },
  sectionHeader: {
    margin: 10,
    flexDirection: 'row',
    justifyContent: 'space-between',
  },
  sectionTitle: {
    fontWeight: 'bold',
  },
  sectionSeriesTitle: {
    color: globalStyleVariables.PRIMARY_COLOR,
  },
  thumnailNameContainer: {
    flexDirection: 'row',
    alignItems: 'center',
  },
  profileContainer: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
  },
  nameContainer: {
    flexDirection: 'column',
    marginLeft: 10,
  },
  captionContainer: {
    marginVertical: 10,
  },
  statContainer: {
    flexDirection: 'row',
    alignItems: 'center',
  },
  title: {
    fontSize: 18,
    fontWeight: 'bold',
    marginBottom: 5,
  },
  seriesTitle: {
    color: globalStyleVariables.PRIMARY_COLOR,
    fontWeight: 'bold',
    marginBottom: 5,
  },
});

class DetailInfoModal extends Component {
  static defaultProps = {
    duration: 300,
    height: Math.floor(
      (globalStyleVariables.WINDOW_HEIGHT -
        globalStyleVariables.APPBAR_HEIGHT -
        globalStyleVariables.STATUSBAR_HEIGHT) *
        0.6,
    ),
  };

  constructor(props) {
    super(props);
    this.state = {
      animatedHeight: new Animated.Value(0),
      modalVisible: false,
      selectedTag: null,
      isOpenTagBottomSheet: false,
    };
  }

  componentWillReceiveProps(nextProps) {
    const { visible } = nextProps;
    const { visible: prevVisible } = this.props;
    if (visible !== null && visible !== prevVisible) {
      this.setModalVisible(visible);
    }
  }

  setModalVisible = visible => {
    const { height, duration } = this.props;
    const { modalVisible, animatedHeight } = this.state;
    if (visible && !modalVisible) {
      this.setState({ modalVisible: visible });
      Animated.timing(animatedHeight, {
        toValue: height,
        duration,
      }).start();
    } else if (!visible && modalVisible) {
      Animated.timing(animatedHeight, {
        toValue: 0,
        duration,
      }).start(() => {
        this.setState({ modalVisible: visible });
      });
    }
  };

  handleOnCloseModal = () => {
    this.setModalVisible(false);
  };

  handleOnPressAvatar = () => {
    const { onPressAvatar, item } = this.props;
    onPressAvatar(item.user.id);
  };

  handleOnPressLink = url => {
    Linking.canOpenURL(url)
      .then(supported => {
        if (!supported) {
          return null;
        }
        return Linking.openURL(url);
      })
      .catch(err => err);
  };

  handleOnPressTag = tag => {
    const { addSearchHistory, navigation: { push } } = this.props;
    addSearchHistory(tag);
    push(SCREENS.SearchResult, {
      word: tag,
      searchType: SEARCH_TYPES.ILLUST,
    });
  };

  handleOnLongPressTag = tag => {
    this.setState({
      isOpenTagBottomSheet: true,
      selectedTag: tag,
    });
  };

  handleOnCancelTagBottomSheet = () => {
    this.setState({
      isOpenTagBottomSheet: false,
    });
  };

  render() {
    const {
      onCancel,
      item,
      authUser,
      tags,
      i18n,
      navigation,
      highlightTags,
      muteTags,
    } = this.props;
    const {
      animatedHeight,
      modalVisible,
      isOpenTagBottomSheet,
      selectedTag,
    } = this.state;
    if (!modalVisible) {
      return null;
    }
    return (
      <Fragment>
        <TouchableWithoutFeedback onPress={onCancel}>
          <View style={styles.backdropContainer} />
        </TouchableWithoutFeedback>
        <View style={styles.container}>
          <Animated.View style={{ maxHeight: animatedHeight }}>
            <ScrollView>
              <View style={styles.infoContainer}>
                <View style={styles.profileContainer}>
                  <PXTouchable
                    style={styles.thumnailNameContainer}
                    onPress={this.handleOnPressAvatar}
                  >
                    <PXThumbnail uri={item.user.profile_image_urls.medium} />
                    <View style={styles.nameContainer}>
                      <Text>
                        {item.user.name}
                      </Text>
                      <Text>
                        {item.user.account}
                      </Text>
                    </View>
                  </PXTouchable>
                  {((authUser && authUser.id !== item.user.id) || !authUser) &&
                    <FollowButtonContainer userId={item.user.id} />}
                </View>
                <View style={styles.captionContainer}>
                  {item.series &&
                    item.series.id &&
                    <Text style={styles.seriesTitle} selectable>
                      {item.series.title}
                    </Text>}
                  <Text style={styles.title} selectable>
                    {item.title}
                  </Text>
                  <HtmlView
                    value={item.caption}
                    onLinkPress={this.handleOnPressLink}
                    textComponentProps={{ selectable: true }}
                  />
                </View>
                <View style={styles.statContainer}>
                  <Text>
                    {moment(item.create_date).format('YYYY-MM-DD')}
                  </Text>
                  <Icon name="eye" style={{ marginLeft: 10 }} />
                  <Text style={{ marginLeft: 5 }}>
                    {item.total_view}
                  </Text>
                  <Icon name="heart" style={{ marginLeft: 10 }} />
                  <Text style={{ marginLeft: 5 }}>
                    {item.total_bookmarks}
                  </Text>
                </View>
                <Tags
                  tags={tags}
                  onPressTag={this.handleOnPressTag}
                  onLongPressTag={this.handleOnLongPressTag}
                />
              </View>
              <View style={styles.sectionContainer}>
                <View style={styles.sectionHeader}>
                  <Text style={styles.sectionTitle}>
                    {i18n.comments}
                  </Text>
                </View>
                {item.text_length
                  ? <NovelComments
                      novelId={item.id}
                      authorId={item.user.id}
                      isFeatureInDetailPage
                      maxItems={6}
                      navigation={navigation}
                    />
                  : <IllustComments
                      illustId={item.id}
                      authorId={item.user.id}
                      isFeatureInDetailPage
                      maxItems={6}
                      navigation={navigation}
                    />}
              </View>
              {!item.text_length &&
                <View style={styles.sectionContainer}>
                  <View style={styles.sectionHeader}>
                    <Text style={styles.sectionTitle}>
                      {i18n.relatedWorks}
                    </Text>
                  </View>
                  <RelatedIllusts
                    illustId={item.id}
                    listKey={`relatedIllusts-${navigation.state
                      .key}-${item.id}`}
                    isFeatureInDetailPage
                    maxItems={6}
                    navigation={navigation}
                  />
                </View>}
              {item.series &&
                item.series.id &&
                item.text_length > 0 &&
                <View style={styles.sectionContainer}>
                  <View style={styles.sectionHeader}>
                    <Text
                      style={[styles.sectionTitle, styles.sectionSeriesTitle]}
                      selectable
                    >
                      {item.series.title}
                    </Text>
                  </View>
                  <NovelSeries
                    seriesId={item.series.id}
                    seriesTitle={item.series.title}
                    isFeatureInDetailPage
                    maxItems={6}
                    navigation={navigation}
                  />
                </View>}
            </ScrollView>
          </Animated.View>
        </View>
        <TagBottomSheet
          visible={isOpenTagBottomSheet}
          selectedTag={selectedTag}
          isHighlight={highlightTags.includes(selectedTag)}
          isMute={muteTags.includes(selectedTag)}
          navigation={navigation}
          onCancel={this.handleOnCancelTagBottomSheet}
        />
      </Fragment>
    );
  }
}

export default connectLocalization(
  connect(() => {
    const getTagsWithStatus = makeGetTagsWithStatus();
    return (state, props) => ({
      highlightTags: state.highlightTags.items,
      muteTags: state.muteTags.items,
      tags: getTagsWithStatus(state, props),
    });
  }, searchHistoryActionCreators)(DetailInfoModal),
);
<|endoftext|>


<commit_before>import { storiesOf } from '@kadira/storybook'
import Heading from './Heading'
import ThemeProvider from './ThemeProvider'
import VerticalRhythm from './VerticalRhythm'
import {
  color,
  number,
  select,
  text,
  withKnobs
} from '@kadira/storybook-addon-knobs'

storiesOf('Heading', module)
  .addDecorator(withKnobs)
  .addDecorator((story, context) => (
    <ThemeProvider>
      <VerticalRhythm baseline>
        {story()}
      </VerticalRhythm>
    </ThemeProvider>
    ))
  .add('Typographic Hierarchy', () => (

      <Heading level={1}>Canon</Heading>
      <Heading level={2}>Trafalgar</Heading>
      <Heading level={3}>Double Pica</Heading>
      <Heading level={4}>Great Primer</Heading>
      <Heading level={5}>Pica</Heading>
      <Heading level={6}>Long Primer</Heading>

  ))
  .add('Numerical Levels', () => (
    <Heading level={number('Level', 1)}>{text('Text', 'Text Here')}</Heading>
  ))
  .add('Named Levels', () => (
    <Heading level={select('Level', Heading.levels, 'canon')}>
      {text('Text', 'Text Here')}
    </Heading>
  ))
  .add('Borders', () => (
    <Heading
      borderColor={color('Border Color', 'green')}
      borderWidth={number('Border Width', 10)}
      level={text('Level', 'canon')}
      padding={number('Padding', 1)}
    >
      {text('Text', 'Text Here')}
    </Heading>
  ))
<commit_msg>Whitespace clean-up<commit_after>import { storiesOf } from '@kadira/storybook'
import Heading from './Heading'
import ThemeProvider from './ThemeProvider'
import VerticalRhythm from './VerticalRhythm'
import {
  color,
  number,
  select,
  text,
  withKnobs
} from '@kadira/storybook-addon-knobs'

storiesOf('Heading', module)
  .addDecorator(withKnobs)
  .addDecorator((story, context) => (
    <ThemeProvider>
      <VerticalRhythm baseline>
        {story()}
      </VerticalRhythm>
    </ThemeProvider>
  ))
  .add('Typographic Hierarchy', () => (

      <Heading level={1}>Canon</Heading>
      <Heading level={2}>Trafalgar</Heading>
      <Heading level={3}>Double Pica</Heading>
      <Heading level={4}>Great Primer</Heading>
      <Heading level={5}>Pica</Heading>
      <Heading level={6}>Long Primer</Heading>

  ))
  .add('Numerical Levels', () => (
    <Heading level={number('Level', 1)}>{text('Text', 'Text Here')}</Heading>
  ))
  .add('Named Levels', () => (
    <Heading level={select('Level', Heading.levels, 'canon')}>
      {text('Text', 'Text Here')}
    </Heading>
  ))
  .add('Borders', () => (
    <Heading
      borderColor={color('Border Color', 'green')}
      borderWidth={number('Border Width', 10)}
      level={text('Level', 'canon')}
      padding={number('Padding', 1)}
    >
      {text('Text', 'Text Here')}
    </Heading>
  ))
<|endoftext|>


<commit_before>'use strict';

/**
 * Module dependencies.
 */
var mongoose = require('mongoose'),
  Schema = mongoose.Schema;

/**
 * Improvement Schema
 */
var ImprovementSchema = new Schema({
  body: {
    type: String,
    default: '',
    required: 'Please fill Improvement body',
    trim: true
  },
  submission: {
    type: Schema.ObjectId,
    ref: 'Submission'
  },
  created: {
    type: Date,
    default: Date.now
  },
  user: {
    type: Schema.ObjectId,
    ref: 'User'
  },
  likes: Number
});

mongoose.model('Improvement', ImprovementSchema);
<commit_msg>Updated Improvement model - List of users and the value of their vote<commit_after>'use strict';

/**
 * Module dependencies.
 */
var mongoose = require('mongoose'),
  Schema = mongoose.Schema;

/**
 * Improvement Schema
 */
var ImprovementSchema = new Schema({
  body: {
    type: String,
    default: '',
    required: 'Please fill Improvement body',
    trim: true
  },
  submission: {
    type: Schema.ObjectId,
    ref: 'Submission'
  },
  created: {
    type: Date,
    default: Date.now
  },
  user: {
    type: Schema.ObjectId,
    ref: 'User'
  },
  userWhoVoted: [{
    theUser: Schema.ObjectId,
    voteValue: Number
  }],
  likes: Number
});

mongoose.model('Improvement', ImprovementSchema);
<|endoftext|>


<commit_before>/**
 * jQuery UI PickList Widget
 *
 * Copyright (c) 2012 Awnry Software
 * Distributed under the terms of the MIT License.
 *
 * http://www.awnry.com/
 */
(function($)
{
	$.widget("awnry.pickList",
	{
		options:
		{
			// Container classes
			mainClass:                  "pickList",
			listContainerClass:         "pickList_listContainer",
			sourceListContainerClass:   "pickList_sourceListContainer",
			controlsContainerClass:     "pickList_controlsContainer",
			targetListContainerClass:   "pickList_targetListContainer",
			listClass:                  "pickList_list",
			sourceListClass:            "pickList_sourceList",
			targetListClass:            "pickList_targetList",
			clearClass:                 "pickList_clear",

			// List item classes
			listItemClass:              "pickList_listItem",
			selectedListItemClass:      "pickList_selectedListItem",

			// Control classes
			addAllClass:                "pickList_addAll",
			addClass:                   "pickList_add",
			removeAllClass:             "pickList_removeAll",
			removeClass:                "pickList_remove",

			// Control labels
			addAllLabel:                ">>",
			addLabel:                   ">",
			removeAllLabel:             "<<",
			removeLabel:                "<",

			// List labels
			listLabelClass:             "pickList_listLabel",
			sourceListLabel:            "Available",
			sourceListLabelClass:       "pickList_sourceListLabel",
			targetListLabel:            "Selected",
			targetListLabelClass:       "pickList_targetListLabel",

			// Behavior
			sortItems:                  true,
			sourceRichItems:            new Array(),
			targetRichItems:            new Array()
		},

		_create: function()
		{
			var self = this;

			self._buildPickList();
			self._refresh();
		},

		_buildPickList: function()
		{
			var self = this;

			self.pickList = $("<div/>")
					.hide()
					.addClass(self.options.mainClass)
					.insertAfter(self.element)
					.append(self._buildSourceList())
					.append(self._buildControls())
					.append(self._buildTargetList())
					.append( $("<div/>").addClass(self.options.clearClass) );

			self._populateLists();

			self.element.hide();
			self.pickList.show();
		},

		_buildSourceList: function()
		{
			var self = this;

			var container = $("<div/>")
					.addClass(self.options.listContainerClass)
					.addClass(self.options.sourceListContainerClass)
					.disableSelection();

			var label = $("<div/>")
					.text(self.options.sourceListLabel)
					.addClass(self.options.listLabelClass)
					.addClass(self.options.sourceListLabelClass);

			self.sourceList = $("<ul/>")
					.addClass(self.options.listClass)
					.addClass(self.options.sourceListClass)
					.delegate("li", "click", {pickList: self}, self._changeHandler);

			container
					.append(label)
					.append(self.sourceList);

			return container;
		},

		_buildTargetList: function()
		{
			var self = this;

			var container = $("<div/>")
					.addClass(self.options.listContainerClass)
					.addClass(self.options.targetListContainerClass)
					.disableSelection();

			var label = $("<div/>")
					.text(self.options.targetListLabel)
					.addClass(self.options.listLabelClass)
					.addClass(self.options.targetListLabelClass);

			self.targetList = $("<ul/>")
					.addClass(self.options.listClass)
					.addClass(self.options.targetListClass)
					.delegate("li", "click", {pickList: self}, self._changeHandler);

			container
					.append(label)
					.append(self.targetList);

			return container;
		},

		_buildControls: function()
		{
			var self = this;

			self.controls = $("<div/>").addClass(self.options.controlsContainerClass);

			self.addAllButton = $("<button/>").button().click({pickList: self}, self._addAllHandler).html(self.options.addAllLabel).addClass(self.options.addAllClass);
			self.addButton = $("<button/>").button().click({pickList: self}, self._addHandler).html(self.options.addLabel).addClass(self.options.addClass);
			self.removeButton = $("<button/>").button().click({pickList: self}, self._removeHandler).html(self.options.removeLabel).addClass(self.options.removeClass);
			self.removeAllButton = $("<button/>").button().click({pickList: self}, self._removeAllHandler).html(self.options.removeAllLabel).addClass(self.options.removeAllClass);

			self.controls
					.append(self.addAllButton)
					.append(self.addButton)
					.append(self.removeButton)
					.append(self.removeAllButton);

			return self.controls;
		},

		_populateLists: function()
		{
			var self = this;

			self.element.children().each(function()
			{
				var text = $(this).text();
				var copy = $("<li/>")
						.text(text)
						.val($(this).val())
						.attr("label", text)
						.addClass(self.options.listItemClass);

				if($(this).attr("selected") == "selected")
				{
					self.targetList.append( copy );
				}
				else
				{
					self.sourceList.append( copy );
				}
			});

			$(self.options.sourceRichItems).each(function()
			{
				self.sourceList.append( self._createRichItem(this) );
			});

			$(self.options.targetRichItems).each(function()
			{
				self.sourceList.append( self._createRichItem(this) );
			});
		},

		_addItem: function(value)
		{
			var self = this;

			self.sourceList.children("[value='" + value + "']").each(function()
			{
				self.targetList.append( self._removeSelection($(this)) );
			});

			self.element.children("[value='" + value + "']").each(function()
			{
				$(this).attr("selected", "selected");
			});
		},

		_removeItem: function(value)
		{
			var self = this;

			self.targetList.children("[value='" + value + "']").each(function()
			{
				self.sourceList.append( self._removeSelection($(this)) );
			});

			self.element.children("[value='" + value + "']").each(function()
			{
				$(this).removeAttr("selected");
			});
		},

		_addAllHandler: function(e)
		{
			var self = e.data.pickList;

			self.sourceList.children().each(function()
			{
				self._addItem( $(this).val() );
			});

			self._refresh();
		},

		_addHandler: function(e)
		{
			var self = e.data.pickList;

			self.sourceList.children(".ui-selected").each(function()
			{
				self._addItem( $(this).val() );
			});

			self._refresh();
		},

		_removeHandler: function(e)
		{
			var self = e.data.pickList;

			self.targetList.children(".ui-selected").each(function()
			{
				self._removeItem( $(this).val() );
			});

			self._refresh();
		},

		_removeAllHandler: function(e)
		{
			var self = e.data.pickList;

			self.targetList.children().each(function()
			{
				self._removeItem( $(this).val() );
			});

			self._refresh();
		},

		_refresh: function()
		{
			var self = this;

			// Enable/disable the Add All and Remove All buttons.
			self.addAllButton.button( (self.sourceList.children().length > 0) ? "enable" : "disable" );
			self.removeAllButton.button( (self.targetList.children().length > 0) ? "enable" : "disable" );

			// Enable/disable the Add button state.
			if(self.sourceList.children(".ui-selected").length)
			{
				self.addButton.button("enable");
			}
			else
			{
				self.addButton.button("disable");
			}

			// Enable/disable the Remove button state.
			if(self.targetList.children(".ui-selected").length)
			{
				self.removeButton.button("enable");
			}
			else
			{
				self.removeButton.button("disable");
			}

			// Refresh the buttons.
			self.controls.children().each(function()
			{
				$(this).button("refresh");
			});

			// Sort the selection lists.
			if(self.options.sortItems)
			{
				self._sortItems(self.sourceList);
				self._sortItems(self.targetList);
			}
		},

		_sortItems: function(list)
		{
			var items = new Array();

			list.children().each(function()
			{
				items.push( $(this) );
			});

			items.sort(function(a, b)
			{
				if(a.attr("label") > b.attr("label"))
				{
					return 1;
				}
				else if(a.attr("label") == b.attr("label"))
				{
					return 0;
				}
				else
				{
					return -1;
				}
			});

			list.empty();

			for(var i = 0; i < items.length; i++)
			{
				list.append(items[i]);
			}
		},

		_changeHandler: function(e)
		{
			var self = e.data.pickList;

			if(e.ctrlKey)
			{
				if(self._isSelected( $(this) ))
				{
					self._removeSelection( $(this) );
				}
				else
				{
					self.lastSelectedItem = $(this);
					self._addSelection( $(this) );
				}
			}
			else if(e.shiftKey)
			{
				var current = $(this).val();
				var last = self.lastSelectedItem.val();

				if($(this).index() < $(self.lastSelectedItem).index())
				{
					var temp = current;
					current = last;
					last = temp;
				}

				var pastStart = false;
				var beforeEnd = true;

				self._clearSelections( $(this).parent() );

				$(this).parent().children().each(function()
				{
					if($(this).val() == last)
					{
						pastStart = true;
					}

					if(pastStart && beforeEnd)
					{
						self._addSelection( $(this) );
					}

					if($(this).val() == current)
					{
						beforeEnd = false;
					}

				});
			}
			else
			{
				self.lastSelectedItem = $(this);
				self._clearSelections( $(this).parent() );
				self._addSelection( $(this) );
			}

			self._refresh();
		},

		_isSelected: function(listItem)
		{
			return listItem.hasClass("ui-selected");
		},

		_addSelection: function(listItem)
		{
			var self = this;

			return listItem
					.addClass("ui-selected")
					.addClass("ui-state-highlight")
					.addClass(self.options.selectedListItemClass);
		},

		_removeSelection: function(listItem)
		{
			var self = this;

			return listItem
					.removeClass("ui-selected")
					.removeClass("ui-state-highlight")
					.removeClass(self.options.selectedListItemClass);
		},

		_clearSelections: function(list)
		{
			var self = this;

			list.children().each(function()
			{
				self._removeSelection( $(this) );
			});
		},

		_setOption: function(key, value)
		{
			switch(key)
			{
				case "clear":
				{
					break;
				}
			}

			$.Widget.prototype._setOption.apply(this, arguments);
		},

		destroy: function()
		{
			$.Widget.prototype.destroy.call(this);
		},

		insert: function(item)
		{
			var self = this;

			self.sourceList.append( self._createRichItem(item) );
			self._refresh();
		},

		_createRichItem: function(item)
		{
			var self = this;
			console.log("Item value = " + item.value);
			console.log("Item label = " + item.label);
			console.log("Item element = " + item.element);

			self.element.append( $("<option/>").val(item.value).text(item.label) );

			return $("<li/>")
					.val(item.value)
					.attr("label", item.label)
					.addClass(self.options.listItemClass)
					.append(item.element);
		}
	});
}(jQuery));<commit_msg>Minor cleanup.<commit_after>/**
 * jQuery UI PickList Widget
 *
 * Copyright (c) 2012 Awnry Software
 * Distributed under the terms of the MIT License.
 *
 * http://www.awnry.com/
 */
(function($)
{
	$.widget("awnry.pickList",
	{
		options:
		{
			// Container classes
			mainClass:                  "pickList",
			listContainerClass:         "pickList_listContainer",
			sourceListContainerClass:   "pickList_sourceListContainer",
			controlsContainerClass:     "pickList_controlsContainer",
			targetListContainerClass:   "pickList_targetListContainer",
			listClass:                  "pickList_list",
			sourceListClass:            "pickList_sourceList",
			targetListClass:            "pickList_targetList",
			clearClass:                 "pickList_clear",

			// List item classes
			listItemClass:              "pickList_listItem",
			selectedListItemClass:      "pickList_selectedListItem",

			// Control classes
			addAllClass:                "pickList_addAll",
			addClass:                   "pickList_add",
			removeAllClass:             "pickList_removeAll",
			removeClass:                "pickList_remove",

			// Control labels
			addAllLabel:                ">>",
			addLabel:                   ">",
			removeAllLabel:             "<<",
			removeLabel:                "<",

			// List labels
			listLabelClass:             "pickList_listLabel",
			sourceListLabel:            "Available",
			sourceListLabelClass:       "pickList_sourceListLabel",
			targetListLabel:            "Selected",
			targetListLabelClass:       "pickList_targetListLabel",

			// Behavior
			sortItems:                  true,
			sourceRichItems:            new Array(),
			targetRichItems:            new Array()
		},

		_create: function()
		{
			var self = this;

			self._buildPickList();
			self._refresh();
		},

		_buildPickList: function()
		{
			var self = this;

			self.pickList = $("<div/>")
					.hide()
					.addClass(self.options.mainClass)
					.insertAfter(self.element)
					.append(self._buildSourceList())
					.append(self._buildControls())
					.append(self._buildTargetList())
					.append( $("<div/>").addClass(self.options.clearClass) );

			self._populateLists();

			self.element.hide();
			self.pickList.show();
		},

		_buildSourceList: function()
		{
			var self = this;

			var container = $("<div/>")
					.addClass(self.options.listContainerClass)
					.addClass(self.options.sourceListContainerClass)
					.disableSelection();

			var label = $("<div/>")
					.text(self.options.sourceListLabel)
					.addClass(self.options.listLabelClass)
					.addClass(self.options.sourceListLabelClass);

			self.sourceList = $("<ul/>")
					.addClass(self.options.listClass)
					.addClass(self.options.sourceListClass)
					.delegate("li", "click", {pickList: self}, self._changeHandler);

			container
					.append(label)
					.append(self.sourceList);

			return container;
		},

		_buildTargetList: function()
		{
			var self = this;

			var container = $("<div/>")
					.addClass(self.options.listContainerClass)
					.addClass(self.options.targetListContainerClass)
					.disableSelection();

			var label = $("<div/>")
					.text(self.options.targetListLabel)
					.addClass(self.options.listLabelClass)
					.addClass(self.options.targetListLabelClass);

			self.targetList = $("<ul/>")
					.addClass(self.options.listClass)
					.addClass(self.options.targetListClass)
					.delegate("li", "click", {pickList: self}, self._changeHandler);

			container
					.append(label)
					.append(self.targetList);

			return container;
		},

		_buildControls: function()
		{
			var self = this;

			self.controls = $("<div/>").addClass(self.options.controlsContainerClass);

			self.addAllButton = $("<button/>").button().click({pickList: self}, self._addAllHandler).html(self.options.addAllLabel).addClass(self.options.addAllClass);
			self.addButton = $("<button/>").button().click({pickList: self}, self._addHandler).html(self.options.addLabel).addClass(self.options.addClass);
			self.removeButton = $("<button/>").button().click({pickList: self}, self._removeHandler).html(self.options.removeLabel).addClass(self.options.removeClass);
			self.removeAllButton = $("<button/>").button().click({pickList: self}, self._removeAllHandler).html(self.options.removeAllLabel).addClass(self.options.removeAllClass);

			self.controls
					.append(self.addAllButton)
					.append(self.addButton)
					.append(self.removeButton)
					.append(self.removeAllButton);

			return self.controls;
		},

		_populateLists: function()
		{
			var self = this;

			self.element.children().each(function()
			{
				var text = $(this).text();
				var copy = $("<li/>")
						.text(text)
						.val($(this).val())
						.attr("label", text)
						.addClass(self.options.listItemClass);

				if($(this).attr("selected") == "selected")
				{
					self.targetList.append( copy );
				}
				else
				{
					self.sourceList.append( copy );
				}
			});

			$(self.options.sourceRichItems).each(function()
			{
				self.sourceList.append( self._createRichItem(this) );
			});

			$(self.options.targetRichItems).each(function()
			{
				self.sourceList.append( self._createRichItem(this) );
			});
		},

		_addItem: function(value)
		{
			var self = this;

			self.sourceList.children("[value='" + value + "']").each(function()
			{
				self.targetList.append( self._removeSelection($(this)) );
			});

			self.element.children("[value='" + value + "']").each(function()
			{
				$(this).attr("selected", "selected");
			});
		},

		_removeItem: function(value)
		{
			var self = this;

			self.targetList.children("[value='" + value + "']").each(function()
			{
				self.sourceList.append( self._removeSelection($(this)) );
			});

			self.element.children("[value='" + value + "']").each(function()
			{
				$(this).removeAttr("selected");
			});
		},

		_addAllHandler: function(e)
		{
			var self = e.data.pickList;

			self.sourceList.children().each(function()
			{
				self._addItem( $(this).val() );
			});

			self._refresh();
		},

		_addHandler: function(e)
		{
			var self = e.data.pickList;

			self.sourceList.children(".ui-selected").each(function()
			{
				self._addItem( $(this).val() );
			});

			self._refresh();
		},

		_removeHandler: function(e)
		{
			var self = e.data.pickList;

			self.targetList.children(".ui-selected").each(function()
			{
				self._removeItem( $(this).val() );
			});

			self._refresh();
		},

		_removeAllHandler: function(e)
		{
			var self = e.data.pickList;

			self.targetList.children().each(function()
			{
				self._removeItem( $(this).val() );
			});

			self._refresh();
		},

		_refresh: function()
		{
			var self = this;

			// Enable/disable the Add All and Remove All buttons.
			self.addAllButton.button( (self.sourceList.children().length > 0) ? "enable" : "disable" );
			self.removeAllButton.button( (self.targetList.children().length > 0) ? "enable" : "disable" );

			// Enable/disable the Add button state.
			if(self.sourceList.children(".ui-selected").length)
			{
				self.addButton.button("enable");
			}
			else
			{
				self.addButton.button("disable");
			}

			// Enable/disable the Remove button state.
			if(self.targetList.children(".ui-selected").length)
			{
				self.removeButton.button("enable");
			}
			else
			{
				self.removeButton.button("disable");
			}

			// Refresh the buttons.
			self.controls.children().each(function()
			{
				$(this).button("refresh");
			});

			// Sort the selection lists.
			if(self.options.sortItems)
			{
				self._sortItems(self.sourceList);
				self._sortItems(self.targetList);
			}
		},

		_sortItems: function(list)
		{
			var items = new Array();

			list.children().each(function()
			{
				items.push( $(this) );
			});

			items.sort(function(a, b)
			{
				if(a.attr("label") > b.attr("label"))
				{
					return 1;
				}
				else if(a.attr("label") == b.attr("label"))
				{
					return 0;
				}
				else
				{
					return -1;
				}
			});

			list.empty();

			for(var i = 0; i < items.length; i++)
			{
				list.append(items[i]);
			}
		},

		_changeHandler: function(e)
		{
			var self = e.data.pickList;

			if(e.ctrlKey)
			{
				if(self._isSelected( $(this) ))
				{
					self._removeSelection( $(this) );
				}
				else
				{
					self.lastSelectedItem = $(this);
					self._addSelection( $(this) );
				}
			}
			else if(e.shiftKey)
			{
				var current = $(this).val();
				var last = self.lastSelectedItem.val();

				if($(this).index() < $(self.lastSelectedItem).index())
				{
					var temp = current;
					current = last;
					last = temp;
				}

				var pastStart = false;
				var beforeEnd = true;

				self._clearSelections( $(this).parent() );

				$(this).parent().children().each(function()
				{
					if($(this).val() == last)
					{
						pastStart = true;
					}

					if(pastStart && beforeEnd)
					{
						self._addSelection( $(this) );
					}

					if($(this).val() == current)
					{
						beforeEnd = false;
					}

				});
			}
			else
			{
				self.lastSelectedItem = $(this);
				self._clearSelections( $(this).parent() );
				self._addSelection( $(this) );
			}

			self._refresh();
		},

		_isSelected: function(listItem)
		{
			return listItem.hasClass("ui-selected");
		},

		_addSelection: function(listItem)
		{
			var self = this;

			return listItem
					.addClass("ui-selected")
					.addClass("ui-state-highlight")
					.addClass(self.options.selectedListItemClass);
		},

		_removeSelection: function(listItem)
		{
			var self = this;

			return listItem
					.removeClass("ui-selected")
					.removeClass("ui-state-highlight")
					.removeClass(self.options.selectedListItemClass);
		},

		_clearSelections: function(list)
		{
			var self = this;

			list.children().each(function()
			{
				self._removeSelection( $(this) );
			});
		},

		_setOption: function(key, value)
		{
			switch(key)
			{
				case "clear":
				{
					break;
				}
			}

			$.Widget.prototype._setOption.apply(this, arguments);
		},

		destroy: function()
		{
			$.Widget.prototype.destroy.call(this);
		},

		insert: function(item)
		{
			var self = this;

			self.sourceList.append( self._createRichItem(item) );
			self._refresh();
		},

		_createRichItem: function(item)
		{
			var self = this;

			self.element.append( $("<option/>").val(item.value).text(item.label) );

			return $("<li/>")
					.val(item.value)
					.attr("label", item.label)
					.addClass(self.options.listItemClass)
					.append(item.element);
		}
	});
}(jQuery));<|endoftext|>