<commit_before>/**
 * SURFconext EngineBlock
 *
 * LICENSE
 *
 * Copyright 2011 SURFnet bv, The Netherlands
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and limitations under the License.
 *
 * @category  SURFconext EngineBlock
 * @package
 * @copyright Copyright © 2010-2011 SURFnet SURFnet bv, The Netherlands (http://www.surfnet.nl)
 * @license   http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
 */

var Discover = function() {

    var module = {

        enableScrolling: function() {
            library.handleScrollBars();

            var throttleTimeout;
            $(window).bind(
                'resize',
                function()
                {
                    if ($.browser.msie) {
                        // IE fires multiple resize events while you are dragging the browser window which
                        // causes it to crash if you try to update the scrollpane on every one. So we need
                        // to throttle it to fire a maximum of once every 50 milliseconds...
                        if (!throttleTimeout) {
                            throttleTimeout = setTimeout(
                                function()
                                {
                                    library.handleScrollBars();
                                    throttleTimeout = null;
                                },
                                50
                            );
                        }
                    } else {
                        library.handleScrollBars();
                    }
                }
            );
        },

        setLanguage : function(lang) {
            library.lang = lang;
        },

        setSearchText : function(text) {
            library.searchText = text;
        },

        setIdpList : function(idpList) {
            library.idpList = idpList;
        },

        setUri : function(uri) {
            library.uri = uri;
        },

        setSelectedEntityId : function(selectedEntityId) {
            library.selectedEntityId = selectedEntityId;
        },

        show : function() {
            this.enableScrolling();

            // Restrict the form from submitting unless a valid idp has been chosen
            $('#IdpListForm').submit(function() {
                var selectedIdp = $('#Idp').attr('value');
                if (!selectedIdp) {
                    return false;
                }
                for (var idp in library.idpList) {
                    if (encodeURIComponent(library.idpList[idp].EntityId) === selectedIdp) {
                        return true;
                    }
                }
                return false;
            });

            //Initialize keyboard navigator
            keyboardNavigator.init();

            //Get start organisations
            library.sortIdps();
            library.loadIdps($('#searchBox').val());

            //Hook up searchbox event
            $('#searchBox').keyup(function (e) {
                switch (e.which) {
                    case 40: // ignore the arrow keys
                    case 38:
                    case 37:
                    case 39:
                        break;
                    default:
                        library.loadIdps($('#searchBox').val());
                }
            });

            //Disable or enable keyboardNavigator if search field gets or looses focus
            $('#searchBox').focus(function() {
                keyboardNavigator.enabled = false;
                // clear searchbox text on focus
                if ($('#searchBox').val() == library.searchText) {
                    $('#searchBox').val('');
                }
            });

            $('#searchBox').blur(function() {
                keyboardNavigator.enabled = true;
            });

            $('#tabThumbs').click(library.showThumbs);
            $('#tabList').click(library.showList);

            library.initLinks();

            // set thums/list view based on cookie
            if ($.cookie("tabs") == 'thumbs') {
                library.showThumbs();
            }
            if ($.cookie("tabs") == 'list') {
                library.showList();
            }

            // In case of a preselected IdP fill the suggestion
            if (library.selectedEntityId !== '') {
                library.fillSuggestion();
            }

            if (library.selectedId != '') {
                library.selectSuggestion();
            }
        },

        linkHelp: function() {
            library.initLinks();
        }
    };

    var library = {
        lang : '',
        searchText : '',
        idpList : '',
        selectedId : '',
        selectedEntityId : '',
        uri : '',

        selectIdpJSON : function() {
            for (var idp in this.idpList) {
                if (this.idpList[idp].hasOwnProperty('EntityId') && this.idpList[idp]['EntityId'] == this.selectedEntityId) {
                    return this.idpList[idp];
                }
            }
            return null;
        },

        initLinks : function() {
            $("#help_nav a").live("click", function(e) {
                e.preventDefault();
                if ($('#help:visible').length > 0 && $.trim($('#help:visible').html()) !== "") {
                    return;
                }
                $.get('/authentication/idp/help?lang='+library.lang, function(data) {
                    $("#content").hide('slow');

                    var help = $("#help");
                    help.html(data);
                    help.show('slow', function() { library.handleScrollBars(); });

                    library.prepareFaq();
                });
            });
        },

        prepareFaq : function() {
            //Attach click handler to open and close help items
            $("#faq li").click(function(e) {
                $(this).toggleClass("open");

                //Close all faq items except the clicked one
                $('#faq li').not(this).removeClass('open');
            });

            $("#back_link").live("click", function(e) {
                e.preventDefault();
                $("#content").show('slow');
                $("#help").hide('slow');
            });
        },

        fillSuggestion : function() {
            var idp = this.selectIdpJSON();
            if (idp) {
                this.selectedId = idp['ID'];

                idp['Name'] = idp['Name_nl'];
                if ((this.lang == 'en') & (idp['Name_en'] != undefined)) {
                    idp['Name'] = idp['Name_en'];
                }
                idp['Alt'] = encodeURIComponent(idp['EntityId']);

                idp['Suggestion'] = 'Onze Suggestie:';
                if ((this.lang == 'en')) {
                    idp['Suggestion'] = 'Our Suggestion:';
                }

                if (idp['Access'] == 0) {
                    idp['noAccess'] = 'Geen toegang. »';
                    if (this.lang == 'en') {
                        idp['noAccess'] = 'No access. »';
                    }
                    idp['NoAccessClass'] = 'noAccess';
                    idp['Name'] = this.clipString(idp['Name'], 45); //Clip string to prevent overlap with 'No access' label
                }
                var html = $('#idpListSuggestionTemplate').tmpl(idp);
                $('#IdpSuggestion').append(html).click(function() {
                    //action no access or access
                    if (idp['Access'] == 0) {
                        //TODO implemented action on no access
                    } else {
                        $('#Idp').attr('value', idp['Alt']);
                        $('#IdpListForm').submit();
                    }
                });

            } else {
                //apparantly there is a cookie for a selected IDP, but it's not allowed for this SP
                $('#IdpSuggestion').remove();
            }
        },

        /**
         * Clips a string and appends an ellipsis so that the resulting length equals the given max length
         *
         * @param string        input string
         * @param maxLength        desired string length
         * @return string        clipped string with ellipsis appended
         */
        clipString : function (string, maxLength) {
            var appendString = '...';

            if (string.length <= maxLength) {
                return string;
            } else {
                var clippedString = string.substring(0, maxLength - appendString.length);

                //If last character is a space, we remove that as well to avoid gaps between the string and the ellipsis
                if (clippedString.substring(clippedString.length - 1) == ' ') {
                    clippedString = clippedString.substring(0, clippedString.length - 1);
                }

                return clippedString + appendString;
            }
        },

        sortIdps : function() {
            this.idpList.sort(function(o1, o2){
                var prop = 'Name_'+library.lang;
                var v1 = o1.hasOwnProperty(prop) ? o1[prop] : o1['Name_nl'];
                var v2 = o2.hasOwnProperty(prop) ? o2[prop] : o2['Name_nl'];
                return v1.localeCompare(v2);
            });
        },

        /**
         * Loads idps, optionally filtered
         *
         * @param filter    string used to filter idps
         */
        loadIdps : function(filter, isSearch) {
            if (filter == this.searchText) {
                filter = '';
            }
            library.displayIdps(library.filterIdps(filter));

            // Return focus on searchbox if it is a search
            if (filter !== '') {
                $('#searchBox').focus();
                $('#searchBox').putCursorAtEnd();
            }
        },

        filterIdps : function(filter) {
            var filteredResults = [];

            // empty filter
            if (filter === '') {
                return this.idpList;
            }

            filter = filter.toLowerCase();

            // filter idps based on keywords
            for (var idp in this.idpList) {
                var inKeywords = false;
                // Filter first on keywords
                if (this.idpList[idp].hasOwnProperty('Keywords')) {
                    for (var keyword in this.idpList[idp]['Keywords']) {
                        if (this.idpList[idp]['Keywords'][keyword].toLowerCase().indexOf(filter) >= 0) {
                            inKeywords = true;
                        }
                    }
                    // Filter based on IdP Name
                }
                var nameProp = 'Name_' + this.lang;
                if (this.idpList[idp].hasOwnProperty(nameProp) && this.idpList[idp][nameProp].toLowerCase().indexOf(filter) >= 0) {
                    inKeywords = true;
                }

                if (inKeywords) {
                    filteredResults.push(this.idpList[idp]);
                }
            }
            return filteredResults;
        },

        /**
         * Takes a multidimensional array of idps and displays them in the results box
         *
         * @param results    array of idps
         */
        displayIdps : function(results) {

            //Display no results message if needed
            if (results.length == 0) {
                $('#noResultsMessage').show();
                $('#scrollViewport').hide();
            } else {
                if (window.innerWidth>=768) {
                    $('#noResultsMessage').hide();
                    $('#scrollViewport').show();
                }

                //Clear results box
                $('#organisationsContainer').html('');

                //Loop through every idp, create a html snippet for it, and append it to the container
                for (var i = 0; i < results.length; i++) {
                    var result = results[i];

                    // create a new object for the idp
                    var idp = {};

                    idp['ID'] = result['ID'];
                    idp['Logo'] = result['Logo'];

                    idp['Name'] = result['Name_nl'];
                    if ((this.lang == 'en') & (result['Name_en'] != undefined)) {
                        idp['Name'] = result['Name_en'];
                    }

                    idp['Alt'] = encodeURIComponent(result['EntityId']);
                    idp['NoAccess'] = '';
                    idp['NoAccessClass'] = '';

                    if (result['Access'] == 0) {
                        idp['NoAccess'] = 'Geen toegang. »';
                        if (this.lang == 'en') {
                            idp['NoAccess'] = 'No access. »';
                        }
                        idp['NoAccessClass'] = 'noAccess';
                        idp['Name'] = clipString(idp['Name'], 45); //Clip string to prevent overlap with 'No access' label
                    }

                    // Use jquery template to create html
                    var html = $('#idpListTemplate').tmpl(idp);
                    $('#organisationsContainer').append(html);
                }

                // Check whether there is a search and a selection has to be made
                if (($('#searchBox').val() == "") || ($('#searchBox').val() == this.searchText)) {
                    // no search no selection
                    // keyboardNavigator.setSelectedIndex(-1);
                    $('#organisationsContainer li').removeClass('selected');
                } else {
                    // search, select first in list
                    // keyboardNavigator.setSelectedIndex(0);
                    $('#organisationsContainer li:first').addClass('selected', '');
                }

                //Hook up onclick handler for keynavigator
                $('#organisationsContainer li').click(function() {

                    //check if there is a selected item
                    var org = $('ul#organisationsContainer li.selected a').attr('alt');
                    //if no select suggestion
                    if (org == undefined) {
                        library.selectSuggestion();
                    }

                    //action no access or access
                    if ($(this).hasClass('noAccess')) {
                        //TODO implemented action on no access
                    } else {
                        $('#Idp').attr('value', org);
                        $('#IdpListForm').submit();
                    }

                    return false;
                });
            }
        },

        // set selection of suggestion in list
        selectSuggestion : function() {
            id = $('#organisationsContainer li#c' + this.selectedId).index();
            keyboardNavigator.setSelectedIndex(id);
            $('#organisationsContainer li#c' + this.selectedId).addClass('selected', '');
        },

        showThumbs : function() {
            // set cookie for tabs thums view
            $.cookie("tabs", "thumbs", { expires: 7 });

            //Toggle tab active class
            $('#tabThumbs').addClass('active');
            $('#tabList').removeClass('active');

            $('#organisationsContainer').addClass('thumbs');
            $('#organisationsContainer').removeClass('list');

            keyboardNavigator.setMode(keyboardNavigator.MODE_3COLUMN_GRID);
        },

        showList : function() {
            // set cookie for tabs list view
            $.cookie("tabs", "list", { expires: 7 });

            //Toggle tab active class
            $('#tabList').addClass('active');
            $('#tabThumbs').removeClass('active');

            $('#organisationsContainer').removeClass('thumbs');
            $('#organisationsContainer').addClass('list');

            keyboardNavigator.setMode(keyboardNavigator.MODE_LIST);
        },

        handleScrollBars: function() {
            $('#scrollViewport').each(function() {
                if (window.innerWidth >= 768) {
                    $(this).jScrollPane(
                        {
                            showArrows: $(this).is('.arrow')
                        }
                    ).data('jsp').reinitialise();
                }
                else {
                    $(this).jScrollPane().data('jsp').destroy();
                }
            });

            $('#scrollViewportHelp').each(function() {
                $(this).jScrollPane(
                    {
                        showArrows: $(this).is('.arrow')
                    }
                ).data('jsp').reinitialise();
            });
        }
    };

    return module;
};<commit_msg>BACKLOG-454: Enable scrolling AFTER loading the IDPs<commit_after>/**
 * SURFconext EngineBlock
 *
 * LICENSE
 *
 * Copyright 2011 SURFnet bv, The Netherlands
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and limitations under the License.
 *
 * @category  SURFconext EngineBlock
 * @package
 * @copyright Copyright © 2010-2011 SURFnet SURFnet bv, The Netherlands (http://www.surfnet.nl)
 * @license   http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
 */

var Discover = function() {

    var module = {

        enableScrolling: function() {
            library.handleScrollBars();

            var throttleTimeout;
            $(window).bind(
                'resize',
                function()
                {
                    if ($.browser.msie) {
                        // IE fires multiple resize events while you are dragging the browser window which
                        // causes it to crash if you try to update the scrollpane on every one. So we need
                        // to throttle it to fire a maximum of once every 50 milliseconds...
                        if (!throttleTimeout) {
                            throttleTimeout = setTimeout(
                                function()
                                {
                                    library.handleScrollBars();
                                    throttleTimeout = null;
                                },
                                50
                            );
                        }
                    } else {
                        library.handleScrollBars();
                    }
                }
            );
        },

        setLanguage : function(lang) {
            library.lang = lang;
        },

        setSearchText : function(text) {
            library.searchText = text;
        },

        setIdpList : function(idpList) {
            library.idpList = idpList;
        },

        setUri : function(uri) {
            library.uri = uri;
        },

        setSelectedEntityId : function(selectedEntityId) {
            library.selectedEntityId = selectedEntityId;
        },

        show : function() {
            // Restrict the form from submitting unless a valid idp has been chosen
            $('#IdpListForm').submit(function() {
                var selectedIdp = $('#Idp').attr('value');
                if (!selectedIdp) {
                    return false;
                }
                for (var idp in library.idpList) {
                    if (encodeURIComponent(library.idpList[idp].EntityId) === selectedIdp) {
                        return true;
                    }
                }
                return false;
            });

            //Initialize keyboard navigator
            keyboardNavigator.init();

            //Get start organisations
            library.sortIdps();
            library.loadIdps($('#searchBox').val());

            this.enableScrolling();

            //Hook up searchbox event
            $('#searchBox').keyup(function (e) {
                switch (e.which) {
                    case 40: // ignore the arrow keys
                    case 38:
                    case 37:
                    case 39:
                        break;
                    default:
                        library.loadIdps($('#searchBox').val());
                }
            });

            //Disable or enable keyboardNavigator if search field gets or looses focus
            $('#searchBox').focus(function() {
                keyboardNavigator.enabled = false;
                // clear searchbox text on focus
                if ($('#searchBox').val() == library.searchText) {
                    $('#searchBox').val('');
                }
            });

            $('#searchBox').blur(function() {
                keyboardNavigator.enabled = true;
            });

            $('#tabThumbs').click(library.showThumbs);
            $('#tabList').click(library.showList);

            library.initLinks();

            // set thums/list view based on cookie
            if ($.cookie("tabs") == 'thumbs') {
                library.showThumbs();
            }
            if ($.cookie("tabs") == 'list') {
                library.showList();
            }

            // In case of a preselected IdP fill the suggestion
            if (library.selectedEntityId !== '') {
                library.fillSuggestion();
            }

            if (library.selectedId != '') {
                library.selectSuggestion();
            }
        },

        linkHelp: function() {
            library.initLinks();
        }
    };

    var library = {
        lang : '',
        searchText : '',
        idpList : '',
        selectedId : '',
        selectedEntityId : '',
        uri : '',

        selectIdpJSON : function() {
            for (var idp in this.idpList) {
                if (this.idpList[idp].hasOwnProperty('EntityId') && this.idpList[idp]['EntityId'] == this.selectedEntityId) {
                    return this.idpList[idp];
                }
            }
            return null;
        },

        initLinks : function() {
            $("#help_nav a").live("click", function(e) {
                e.preventDefault();
                if ($('#help:visible').length > 0 && $.trim($('#help:visible').html()) !== "") {
                    return;
                }
                $.get('/authentication/idp/help?lang='+library.lang, function(data) {
                    $("#content").hide('slow');

                    var help = $("#help");
                    help.html(data);
                    help.show('slow', function() { library.handleScrollBars(); });

                    library.prepareFaq();
                });
            });
        },

        prepareFaq : function() {
            //Attach click handler to open and close help items
            $("#faq li").click(function(e) {
                $(this).toggleClass("open");

                //Close all faq items except the clicked one
                $('#faq li').not(this).removeClass('open');
            });

            $("#back_link").live("click", function(e) {
                e.preventDefault();
                $("#content").show('slow');
                $("#help").hide('slow');
            });
        },

        fillSuggestion : function() {
            var idp = this.selectIdpJSON();
            if (idp) {
                this.selectedId = idp['ID'];

                idp['Name'] = idp['Name_nl'];
                if ((this.lang == 'en') & (idp['Name_en'] != undefined)) {
                    idp['Name'] = idp['Name_en'];
                }
                idp['Alt'] = encodeURIComponent(idp['EntityId']);

                idp['Suggestion'] = 'Onze Suggestie:';
                if ((this.lang == 'en')) {
                    idp['Suggestion'] = 'Our Suggestion:';
                }

                if (idp['Access'] == 0) {
                    idp['noAccess'] = 'Geen toegang. »';
                    if (this.lang == 'en') {
                        idp['noAccess'] = 'No access. »';
                    }
                    idp['NoAccessClass'] = 'noAccess';
                    idp['Name'] = this.clipString(idp['Name'], 45); //Clip string to prevent overlap with 'No access' label
                }
                var html = $('#idpListSuggestionTemplate').tmpl(idp);
                $('#IdpSuggestion').append(html).click(function() {
                    //action no access or access
                    if (idp['Access'] == 0) {
                        //TODO implemented action on no access
                    } else {
                        $('#Idp').attr('value', idp['Alt']);
                        $('#IdpListForm').submit();
                    }
                });

            } else {
                //apparantly there is a cookie for a selected IDP, but it's not allowed for this SP
                $('#IdpSuggestion').remove();
            }
        },

        /**
         * Clips a string and appends an ellipsis so that the resulting length equals the given max length
         *
         * @param string        input string
         * @param maxLength        desired string length
         * @return string        clipped string with ellipsis appended
         */
        clipString : function (string, maxLength) {
            var appendString = '...';

            if (string.length <= maxLength) {
                return string;
            } else {
                var clippedString = string.substring(0, maxLength - appendString.length);

                //If last character is a space, we remove that as well to avoid gaps between the string and the ellipsis
                if (clippedString.substring(clippedString.length - 1) == ' ') {
                    clippedString = clippedString.substring(0, clippedString.length - 1);
                }

                return clippedString + appendString;
            }
        },

        sortIdps : function() {
            this.idpList.sort(function(o1, o2){
                var prop = 'Name_'+library.lang;
                var v1 = o1.hasOwnProperty(prop) ? o1[prop] : o1['Name_nl'];
                var v2 = o2.hasOwnProperty(prop) ? o2[prop] : o2['Name_nl'];
                return v1.localeCompare(v2);
            });
        },

        /**
         * Loads idps, optionally filtered
         *
         * @param filter    string used to filter idps
         */
        loadIdps : function(filter, isSearch) {
            if (filter == this.searchText) {
                filter = '';
            }
            library.displayIdps(library.filterIdps(filter));

            // Return focus on searchbox if it is a search
            if (filter !== '') {
                $('#searchBox').focus();
                $('#searchBox').putCursorAtEnd();
            }
        },

        filterIdps : function(filter) {
            var filteredResults = [];

            // empty filter
            if (filter === '') {
                return this.idpList;
            }

            filter = filter.toLowerCase();

            // filter idps based on keywords
            for (var idp in this.idpList) {
                var inKeywords = false;
                // Filter first on keywords
                if (this.idpList[idp].hasOwnProperty('Keywords')) {
                    for (var keyword in this.idpList[idp]['Keywords']) {
                        if (this.idpList[idp]['Keywords'][keyword].toLowerCase().indexOf(filter) >= 0) {
                            inKeywords = true;
                        }
                    }
                    // Filter based on IdP Name
                }
                var nameProp = 'Name_' + this.lang;
                if (this.idpList[idp].hasOwnProperty(nameProp) && this.idpList[idp][nameProp].toLowerCase().indexOf(filter) >= 0) {
                    inKeywords = true;
                }

                if (inKeywords) {
                    filteredResults.push(this.idpList[idp]);
                }
            }
            return filteredResults;
        },

        /**
         * Takes a multidimensional array of idps and displays them in the results box
         *
         * @param results    array of idps
         */
        displayIdps : function(results) {

            //Display no results message if needed
            if (results.length == 0) {
                $('#noResultsMessage').show();
                $('#scrollViewport').hide();
            } else {
                if (window.innerWidth>=768) {
                    $('#noResultsMessage').hide();
                    $('#scrollViewport').show();
                }

                //Clear results box
                $('#organisationsContainer').html('');

                //Loop through every idp, create a html snippet for it, and append it to the container
                for (var i = 0; i < results.length; i++) {
                    var result = results[i];

                    // create a new object for the idp
                    var idp = {};

                    idp['ID'] = result['ID'];
                    idp['Logo'] = result['Logo'];

                    idp['Name'] = result['Name_nl'];
                    if ((this.lang == 'en') & (result['Name_en'] != undefined)) {
                        idp['Name'] = result['Name_en'];
                    }

                    idp['Alt'] = encodeURIComponent(result['EntityId']);
                    idp['NoAccess'] = '';
                    idp['NoAccessClass'] = '';

                    if (result['Access'] == 0) {
                        idp['NoAccess'] = 'Geen toegang. »';
                        if (this.lang == 'en') {
                            idp['NoAccess'] = 'No access. »';
                        }
                        idp['NoAccessClass'] = 'noAccess';
                        idp['Name'] = clipString(idp['Name'], 45); //Clip string to prevent overlap with 'No access' label
                    }

                    // Use jquery template to create html
                    var html = $('#idpListTemplate').tmpl(idp);
                    $('#organisationsContainer').append(html);
                }

                // Check whether there is a search and a selection has to be made
                if (($('#searchBox').val() == "") || ($('#searchBox').val() == this.searchText)) {
                    // no search no selection
                    // keyboardNavigator.setSelectedIndex(-1);
                    $('#organisationsContainer li').removeClass('selected');
                } else {
                    // search, select first in list
                    // keyboardNavigator.setSelectedIndex(0);
                    $('#organisationsContainer li:first').addClass('selected', '');
                }

                //Hook up onclick handler for keynavigator
                $('#organisationsContainer li').click(function() {

                    //check if there is a selected item
                    var org = $('ul#organisationsContainer li.selected a').attr('alt');
                    //if no select suggestion
                    if (org == undefined) {
                        library.selectSuggestion();
                    }

                    //action no access or access
                    if ($(this).hasClass('noAccess')) {
                        //TODO implemented action on no access
                    } else {
                        $('#Idp').attr('value', org);
                        $('#IdpListForm').submit();
                    }

                    return false;
                });
            }
        },

        // set selection of suggestion in list
        selectSuggestion : function() {
            id = $('#organisationsContainer li#c' + this.selectedId).index();
            keyboardNavigator.setSelectedIndex(id);
            $('#organisationsContainer li#c' + this.selectedId).addClass('selected', '');
        },

        showThumbs : function() {
            // set cookie for tabs thums view
            $.cookie("tabs", "thumbs", { expires: 7 });

            //Toggle tab active class
            $('#tabThumbs').addClass('active');
            $('#tabList').removeClass('active');

            $('#organisationsContainer').addClass('thumbs');
            $('#organisationsContainer').removeClass('list');

            keyboardNavigator.setMode(keyboardNavigator.MODE_3COLUMN_GRID);
        },

        showList : function() {
            // set cookie for tabs list view
            $.cookie("tabs", "list", { expires: 7 });

            //Toggle tab active class
            $('#tabList').addClass('active');
            $('#tabThumbs').removeClass('active');

            $('#organisationsContainer').removeClass('thumbs');
            $('#organisationsContainer').addClass('list');

            keyboardNavigator.setMode(keyboardNavigator.MODE_LIST);
        },

        handleScrollBars: function() {
            $('#scrollViewport').each(function() {
                if (window.innerWidth >= 768) {
                    $(this).jScrollPane(
                        {
                            showArrows: $(this).is('.arrow')
                        }
                    ).data('jsp').reinitialise();
                }
                else {
                    $(this).jScrollPane().data('jsp').destroy();
                }
            });

            $('#scrollViewportHelp').each(function() {
                $(this).jScrollPane(
                    {
                        showArrows: $(this).is('.arrow')
                    }
                ).data('jsp').reinitialise();
            });
        }
    };

    return module;
};
<|endoftext|>


<commit_before>function(doc) {
  var type = doc["details"]["type"];
  // Only output production documents
  //if(type != "Production") { exit; }

  // Get sequencing platform and application for stratification
  var sequencing_platform = doc["details"]["sequencing_platform"];
  var application = doc["application"];

  // Calculate lane load per sample
  var proj_lanes = doc["details"]["sequence_units_ordered_(lanes)"];
  var num_samples = doc.no_of_samples;
  var lanes_per_sample = proj_lanes/num_samples;

  // Find arrival date (if present)
  var open_date = "0000-00-00";
  if (doc["open_date"] > open_date) {
    open_date = doc["open_date"];
    //if(open_date < "2013-07-01") { exit; } // this filter should not be used
  }
  // Find all samples sequenced (if present)
  var ass = doc["details"]["all_samples_sequenced"];

  // Find all raw data delivered (if present)
  var all_raw_data_delivered = "0000-00-00";
  if (doc.details["all_raw_data_delivered"] > all_raw_data_delivered) {
    all_raw_data_delivered = doc.details["all_raw_data_delivered"];
  }

  // close date
  var close_date = "0000-00-00";
  if (doc["close_date"] > close_date) {
    close_date = doc["close_date"];
  }

  // Find aborted date (if present)
  var aborted_date = "0000-00-00";
  if (doc.details["aborted"] > aborted_date) {
    aborted_date = doc.details["aborted"];
  }

  // go through each sample
  for (sample in doc["samples"]){

    // Find Rec ctrl start
    var initial_qc_start = "0000-00-00";
    if(doc["samples"][sample]["first_initial_qc_start_date"] > initial_qc_start) {
      initial_qc_start = doc["samples"][sample]["first_initial_qc_start_date"];
    }

    // library prep start date
    // NEW temp way to get lib prep start
    // This bit of code to be transferred to production server
    var lib_prep_start = "0000-00-00";
    if(doc["samples"][sample]["first_prep_start_date"]) {
      lib_prep_start = doc["samples"][sample]["first_prep_start_date"];
    }

    // final validation date for Library QC
    var final_validation = "0000-00-00";
    // sequence start date
    var sequence_start_date = "9999-99-99";
    // final sequence date
    var final_sequence_date = "0000-00-00";

    // Find queue date (if present)
    var queued = "0000-00-00";
    if (doc["details"]["queued"] > queued) {
      queued = doc["details"]["queued"];
    }

    // go through each lib prep for sample
    for (library_prep in doc["samples"][sample]["library_prep"]) {
      var LP = doc["samples"][sample]["library_prep"][library_prep]

      // This is the lib prep finish date before QC starts. Should not be used as final_validation
      //if(LP.prep_finished_date) {
      //  final_validation = LP.prep_finished_date
      //}

      // capture earliest lib prep start if not set at sample/first_prep_start_date
      // done above at sample level.
      //
      if(LP["prep_start_date"]) {
        if (lib_prep_start == "0000-00-00") {
          lib_prep_start = LP["prep_start_date"];
        } else if (LP["prep_start_date"]<lib_prep_start) {
          lib_prep_start = LP["prep_start_date"];
        }
      }

      var passed_prep = (LP["prep_status"] == "PASSED");

      // Find QC library finish date by looking at the final library validation.
      // final_validation initialized at sample level
      for (lv in LP["library_validation"]) {
        var lib_val_fin = LP["library_validation"][lv]["finish_date"];
        if (passed_prep && lib_val_fin > final_validation) {
          final_validation = lib_val_fin;
        }
      }

      // Find sequence start date & final sequence date by looking at the first sequence start date & the last sequencing_finish_date
      // sequence_start_date initialized at sample level
      // final_sequence_date initialized at sample level
      for (sample_run_metrics in LP["sample_run_metrics"]) {
        // sequence start date
        if(sequence_start_date > LP["sample_run_metrics"][sample_run_metrics]["sequencing_start_date"]) {
          sequence_start_date = LP["sample_run_metrics"][sample_run_metrics]["sequencing_start_date"];
        }

        // sequence end date
        if (final_sequence_date < LP["sample_run_metrics"][sample_run_metrics]["sequencing_finish_date"]) {
          final_sequence_date = LP["sample_run_metrics"][sample_run_metrics]["sequencing_finish_date"];
        } else if (final_sequence_date < LP["sample_run_metrics"][sample_run_metrics]["sequencing_run_QC_finished"]) { // some older(?) projects only have info on seq_run_QC_finished
          final_sequence_date = LP["sample_run_metrics"][sample_run_metrics]["sequencing_run_QC_finished"];
        }
      } // sequence

    } // library prep

    // sample status
    var status = doc["samples"][sample]["details"]["status_(manual)"];
    if(!status) { status = null; }

    // in the case final_sequence_date has not been set, and all samples sequenced date is available
    if(final_sequence_date == "0000-00-00" && ass != null) {
      final_sequence_date = ass;
    }

    if (sequence_start_date == "9999-99-99") { sequence_start_date = "0000-00-00"; }
    //NEW! Emit what we have all variables should be set before so will be ok at emit
    //if (!("library_prep" in doc["samples"][sample])) {
    var KPI = Object();
    KPI["Arrival date"] = open_date;
    KPI["Rec ctrl start"] = initial_qc_start;
    KPI["Queue date"] = queued;
    KPI["Lib prep start"] = lib_prep_start;
    KPI["QC library finished"] = final_validation;
    KPI["Sequencing start"] = sequence_start_date;
    KPI["All samples sequenced"] = final_sequence_date;
    KPI["All raw data delivered"] = all_raw_data_delivered;
    KPI["Close date"] = close_date;
    KPI["Aborted date"]  = aborted_date;
    KPI["Samples"] = 1;
    KPI["Lanes"] = lanes_per_sample;
    KPI["Status"] = status;

    emit([doc["project_id"], type, application, sequencing_platform, sample], KPI);

  } // sample

}<commit_msg>Testing to skip using sequencing_run_QC_finished as an alternative for the sequencing finish date<commit_after>function(doc) {
  var type = doc["details"]["type"];
  // Only output production documents
  //if(type != "Production") { exit; }

  // Get sequencing platform and application for stratification
  var sequencing_platform = doc["details"]["sequencing_platform"];
  var application = doc["application"];

  // Calculate lane load per sample
  var proj_lanes = doc["details"]["sequence_units_ordered_(lanes)"];
  var num_samples = doc.no_of_samples;
  var lanes_per_sample = proj_lanes/num_samples;

  // Find arrival date (if present)
  var open_date = "0000-00-00";
  if (doc["open_date"] > open_date) {
    open_date = doc["open_date"];
    //if(open_date < "2013-07-01") { exit; } // this filter should not be used
  }
  // Find all samples sequenced (if present)
  var ass = doc["details"]["all_samples_sequenced"];

  // Find all raw data delivered (if present)
  var all_raw_data_delivered = "0000-00-00";
  if (doc.details["all_raw_data_delivered"] > all_raw_data_delivered) {
    all_raw_data_delivered = doc.details["all_raw_data_delivered"];
  }

  // close date
  var close_date = "0000-00-00";
  if (doc["close_date"] > close_date) {
    close_date = doc["close_date"];
  }

  // Find aborted date (if present)
  var aborted_date = "0000-00-00";
  if (doc.details["aborted"] > aborted_date) {
    aborted_date = doc.details["aborted"];
  }

  // go through each sample
  for (sample in doc["samples"]){

    // Find Rec ctrl start
    var initial_qc_start = "0000-00-00";
    if(doc["samples"][sample]["first_initial_qc_start_date"] > initial_qc_start) {
      initial_qc_start = doc["samples"][sample]["first_initial_qc_start_date"];
    }

    // library prep start date
    // NEW temp way to get lib prep start
    // This bit of code to be transferred to production server
    var lib_prep_start = "0000-00-00";
    if(doc["samples"][sample]["first_prep_start_date"]) {
      lib_prep_start = doc["samples"][sample]["first_prep_start_date"];
    }

    // final validation date for Library QC
    var final_validation = "0000-00-00";
    // sequence start date
    var sequence_start_date = "9999-99-99";
    // final sequence date
    var final_sequence_date = "0000-00-00";

    // Find queue date (if present)
    var queued = "0000-00-00";
    if (doc["details"]["queued"] > queued) {
      queued = doc["details"]["queued"];
    }

    // go through each lib prep for sample
    for (library_prep in doc["samples"][sample]["library_prep"]) {
      var LP = doc["samples"][sample]["library_prep"][library_prep]

      // This is the lib prep finish date before QC starts. Should not be used as final_validation
      //if(LP.prep_finished_date) {
      //  final_validation = LP.prep_finished_date
      //}

      // capture earliest lib prep start if not set at sample/first_prep_start_date
      // done above at sample level.
      //
      if(LP["prep_start_date"]) {
        if (lib_prep_start == "0000-00-00") {
          lib_prep_start = LP["prep_start_date"];
        } else if (LP["prep_start_date"]<lib_prep_start) {
          lib_prep_start = LP["prep_start_date"];
        }
      }

      var passed_prep = (LP["prep_status"] == "PASSED");

      // Find QC library finish date by looking at the final library validation.
      // final_validation initialized at sample level
      for (lv in LP["library_validation"]) {
        var lib_val_fin = LP["library_validation"][lv]["finish_date"];
        if (passed_prep && lib_val_fin > final_validation) {
          final_validation = lib_val_fin;
        }
      }

      // Find sequence start date & final sequence date by looking at the first sequence start date & the last sequencing_finish_date
      // sequence_start_date initialized at sample level
      // final_sequence_date initialized at sample level
      for (sample_run_metrics in LP["sample_run_metrics"]) {
        // sequence start date
        if(sequence_start_date > LP["sample_run_metrics"][sample_run_metrics]["sequencing_start_date"]) {
          sequence_start_date = LP["sample_run_metrics"][sample_run_metrics]["sequencing_start_date"];
        }

        // sequence end date
        if (final_sequence_date < LP["sample_run_metrics"][sample_run_metrics]["sequencing_finish_date"]) {
          final_sequence_date = LP["sample_run_metrics"][sample_run_metrics]["sequencing_finish_date"];
        //} else if (final_sequence_date < LP["sample_run_metrics"][sample_run_metrics]["sequencing_run_QC_finished"]) { // some older(?) projects only have info on seq_run_QC_finished
        //  final_sequence_date = LP["sample_run_metrics"][sample_run_metrics]["sequencing_run_QC_finished"];
        }
      } // sequence

    } // library prep

    // sample status
    var status = doc["samples"][sample]["details"]["status_(manual)"];
    if(!status) { status = null; }

    // in the case final_sequence_date has not been set, and all samples sequenced date is available
    if(final_sequence_date == "0000-00-00" && ass != null) {
      final_sequence_date = ass;
    }

    if (sequence_start_date == "9999-99-99") { sequence_start_date = "0000-00-00"; }
    //NEW! Emit what we have all variables should be set before so will be ok at emit
    //if (!("library_prep" in doc["samples"][sample])) {
    var KPI = Object();
    KPI["Arrival date"] = open_date;
    KPI["Rec ctrl start"] = initial_qc_start;
    KPI["Queue date"] = queued;
    KPI["Lib prep start"] = lib_prep_start;
    KPI["QC library finished"] = final_validation;
    KPI["Sequencing start"] = sequence_start_date;
    KPI["All samples sequenced"] = final_sequence_date;
    KPI["All raw data delivered"] = all_raw_data_delivered;
    KPI["Close date"] = close_date;
    KPI["Aborted date"]  = aborted_date;
    KPI["Samples"] = 1;
    KPI["Lanes"] = lanes_per_sample;
    KPI["Status"] = status;

    emit([doc["project_id"], type, application, sequencing_platform, sample], KPI);

  } // sample

}<|endoftext|>


<commit_before>'use strict';

/* global vl:true, vlSchema:true */

describe('Directive: functionSelect', function() {

  // load the directive's module
  beforeEach(module('vlui', function($provide) {
    $provide.constant('vl', vl);
    $provide.constant('vlSchema', vlSchema);
  }));

  var element, scope, $compile;

  beforeEach(inject(function($rootScope, _$compile_) {
    scope = $rootScope.$new();
    scope.schema = {
      properties: {
        aggregate: {
          supportedEnums: {
            quantitative: ['a', 'b'],
            undefined: []
          }
        },
        timeUnit: {
          supportedEnums: {
            temporal: ['f1','f2']
          }
        },
        bin: {
          supportedTypes: {
            quantitative: true
          }
        }
      }
    };
    scope.pills = {
      x: { type: 'quantitative', field: 'x'},
      y: { aggregate: 'count', field:'*'},
      color: { type: 'temporal', field: 'c'},
      update: function() {}
    };
    scope.encoding = {
      x: { type: 'quantitative', field: 'x'},
      y: { aggregate: 'count', field:'*'},
      color: { type: 'temporal', field: 'c'},
    };
    scope.channel = 'x';
    scope.channel2 = 'y';
    scope.channel3 = 'color';

    $compile = _$compile_;
  }));

  it('should have correct number of radio', function() {
    element = angular.element('<function-select field-def="encoding[channel]" channel="channel" pills="pills"></function-select>');
    element = $compile(element)(scope);
    scope.$digest();
    expect(element.find('input').length).to.eql(21);
  });

  it('should have correct number of radio', function() {
    element = angular.element('<function-select  field-def="encoding[channel3]" channel="channel3" pills="pills"></function-select>');
    element = $compile(element)(scope);
    scope.$digest();
    expect(element.find('input').length).to.eql(25);
  });

  it('should not show other options for count field', function() {
    element = angular.element('<function-select  field-def="encoding[channel2]" channel="channel2" pills="pills"></function-select>');
    element = $compile(element)(scope);
    scope.$digest();
    scope.pills.y = { aggregate:'count', field: '*'};
    scope.$digest();
    expect(element.find('input').length).to.eql(1);
  });

});
<commit_msg>Fix test case as the number of timeUnits in function-select has changed (#222)<commit_after>'use strict';

/* global vl:true, vlSchema:true */

describe('Directive: functionSelect', function() {

  // load the directive's module
  beforeEach(module('vlui', function($provide) {
    $provide.constant('vl', vl);
    $provide.constant('vlSchema', vlSchema);
  }));

  var element, scope, $compile;

  beforeEach(inject(function($rootScope, _$compile_) {
    scope = $rootScope.$new();
    scope.schema = {
      properties: {
        aggregate: {
          supportedEnums: {
            quantitative: ['a', 'b'],
            undefined: []
          }
        },
        timeUnit: {
          supportedEnums: {
            temporal: ['f1','f2']
          }
        },
        bin: {
          supportedTypes: {
            quantitative: true
          }
        }
      }
    };
    scope.pills = {
      x: { type: 'quantitative', field: 'x'},
      y: { aggregate: 'count', field:'*'},
      color: { type: 'temporal', field: 'c'},
      update: function() {}
    };
    scope.encoding = {
      x: { type: 'quantitative', field: 'x'},
      y: { aggregate: 'count', field:'*'},
      color: { type: 'temporal', field: 'c'},
    };
    scope.channel = 'x';
    scope.channel2 = 'y';
    scope.channel3 = 'color';

    $compile = _$compile_;
  }));

  it('should have correct number of radio', function() {
    element = angular.element('<function-select field-def="encoding[channel]" channel="channel" pills="pills"></function-select>');
    element = $compile(element)(scope);
    scope.$digest();
    expect(element.find('input').length).to.eql(21);
  });

  it('should have correct number of radio', function() {
    element = angular.element('<function-select  field-def="encoding[channel3]" channel="channel3" pills="pills"></function-select>');
    element = $compile(element)(scope);
    scope.$digest();
    expect(element.find('input').length).to.eql(22);
  });

  it('should not show other options for count field', function() {
    element = angular.element('<function-select  field-def="encoding[channel2]" channel="channel2" pills="pills"></function-select>');
    element = $compile(element)(scope);
    scope.$digest();
    scope.pills.y = { aggregate:'count', field: '*'};
    scope.$digest();
    expect(element.find('input').length).to.eql(1);
  });

});
<|endoftext|>


<commit_before>const argv = require('yargs').argv
const webpack = require('webpack')
const cssnano = require('cssnano')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const project = require('./project.config')
const debug = require('debug')('app:config:webpack')

const __DEV__ = project.globals.__DEV__
const __PROD__ = project.globals.__PROD__
const __TEST__ = project.globals.__TEST__

debug('Creating configuration.')
const webpackConfig = {
  name    : 'client',
  target  : 'web',
  devtool : project.compiler_devtool,
  resolve : {
    modules: [
      project.paths.client(),
      'node_modules',
    ],
    extensions : ['.js', '.jsx', '.json'],
    alias      : {
      'constants': project.paths.server('./constants'),
    }
  },
  module : {}
}
// ------------------------------------
// Entry Points
// ------------------------------------
const APP_ENTRY = project.paths.client('main.js')

webpackConfig.entry = {
  app : __DEV__
    ? [APP_ENTRY].concat(`webpack-hot-middleware/client?path=${project.compiler_public_path}__webpack_hmr`)
    : [APP_ENTRY],
  vendor : project.compiler_vendors
}

// ------------------------------------
// Bundle Output
// ------------------------------------
webpackConfig.output = {
  filename   : `[name].[${project.compiler_hash_type}].js`,
  path       : project.paths.dist(),
  publicPath : project.compiler_public_path
}

// ------------------------------------
// Externals
// ------------------------------------
webpackConfig.externals = {}
webpackConfig.externals['react/lib/ExecutionEnvironment'] = true
webpackConfig.externals['react/lib/ReactContext'] = true
webpackConfig.externals['react/addons'] = true

// ------------------------------------
// Plugins
// ------------------------------------
webpackConfig.plugins = [
  new webpack.DefinePlugin(project.globals),
  new HtmlWebpackPlugin({
    template : project.paths.client('index.html'),
    hash     : false,
    favicon  : project.paths.public('favicon.ico'),
    filename : 'index.html',
    inject   : 'body',
    minify   : {
      collapseWhitespace : true
    }
  })
]

// Ensure that the compiler exits on errors during testing so that
// they do not get skipped and misreported.
if (__TEST__ && !argv.watch) {
  webpackConfig.plugins.push(function () {
    this.plugin('done', function (stats) {
      if (stats.compilation.errors.length) {
        // Pretend no assets were generated. This prevents the tests
        // from running making it clear that there were warnings.
        throw new Error(
          stats.compilation.errors.map(err => err.message || err)
        )
      }
    })
  })
}

if (__DEV__) {
  debug('Enabling plugins for live development (HMR, NoEmitOnErrors)')
  webpackConfig.plugins.push(
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoEmitOnErrorsPlugin()
  )
} else if (__PROD__) {
  debug('Enabling plugins for production (UglifyJS)')
  webpackConfig.plugins.push(
    new webpack.optimize.UglifyJsPlugin({
      sourceMap: true,
      compress : {
        unused    : true,
        dead_code : true,
        // warnings  : false
      }
    }),
    new webpack.optimize.AggressiveMergingPlugin()
  )
}

// Don't split bundles during testing, since we only want import one bundle
if (!__TEST__) {
  webpackConfig.plugins.push(
    new webpack.optimize.CommonsChunkPlugin({
      names : ['vendor']
    })
  )
}

// ------------------------------------
// Loaders
// ------------------------------------
// JavaScript
webpackConfig.module.rules = [{
  test    : /\.(js|jsx)$/,
  exclude : /node_modules/,
  loader  : 'babel-loader',
  query   : project.compiler_babel,
}]

// ------------------------------------
// Style Loaders
// ------------------------------------
// We use cssnano with the postcss loader, so we tell
// css-loader not to duplicate minimization.
webpackConfig.module.rules.push({
  test : /\.scss$/,
  use  : [
    {
      loader: 'style-loader'
    },
    {
      loader      : 'css-loader',
      options     : {
        sourceMap : true,
        minimize  : true,
      }
    },
    {
      loader : 'postcss-loader'
    },
    {
      loader  : 'sass-loader',
      options : {
        sourceMap : true,
        includePaths: [...project.paths.client('styles'), './node_modules'],
      }
    }
  ]
})
webpackConfig.module.rules.push({
  test : /\.css$/,
  use  : [
    {
      loader : 'style-loader'
    },
    {
      loader  : 'css-loader',
      options : {
        modules   : true,
        sourceMap : true,
        minimize  : true
      }
    },
    {
      loader : 'postcss-loader'
    }
  ]
})

webpackConfig.plugins.push(
  new webpack.LoaderOptionsPlugin({
    options : {
      postcss : [
        cssnano({
          autoprefixer : {
            add      : true,
            remove   : true,
            browsers : ['last 2 versions']
          },
          discardComments: {
            removeAll : true
          },
          discardUnused : false,
          mergeIdents   : false,
          reduceIdents  : false,
          safe          : true,
          sourcemap     : true
        })
      ],
      sassLoader : {
        includePaths : project.paths.client('styles')
      }
    }
  })
)

// File loaders
/* eslint-disable */
webpackConfig.module.rules.push(
  {
    test    : /\.woff(\?.*)?$/,
    loader  : 'url-loader',
    options : {
      prefix : 'fonts/',
      name     : 'fonts/[name].[ext]',
      limit    : '10000',
      mimetype : 'application/font-woff'
    }
  },
  {
    test    : /\.woff2(\?.*)?$/,
    loader  : 'url-loader',
    options : {
      prefix   : 'fonts/',
      name     : 'fonts/[name].[ext]',
      limit    : '10000',
      mimetype : 'application/font-woff2'
    }
  },
  {
    test    : /\.otf(\?.*)?$/,
    loader  : 'file-loader',
    options : {
      prefix   : 'fonts/',
      name     : 'fonts/[name].[ext]',
      limit    : '10000',
      mimetype : 'font/opentype'
    }
  },
  {
    test    : /\.ttf(\?.*)?$/,
    loader  : 'url-loader',
    options : {
      prefix   : 'fonts/',
      name     : 'fonts/[name].[ext]',
      limit    : '10000',
      mimetype : 'application/octet-stream'
    }
  },
  {
    test    : /\.eot(\?.*)?$/,
    loader  : 'file-loader',
    options : {
      prefix : 'fonts/',
      name   : 'fonts/[name].[ext]'
    }
  },
  {
    test    : /\.svg(\?.*)?$/,
    loader  : 'url-loader',
    options : {
      prefix   : 'fonts/',
      name     : 'fonts/[name].[ext]',
      limit    : '10000',
      mimetype : 'image/svg+xml'
    }
  },
  {
    test    : /\.(png|jpg)$/,
    loader  : 'url-loader',
    options : {
      limit : '8192'
    }
  }
)
/* eslint-enable */

// ------------------------------------
// Finalize Configuration
// ------------------------------------
// when we don't know the public path (we know it only when HMR is enabled [in development]) we
// need to use the extractTextPlugin to fix this issue:
// http://stackoverflow.com/questions/34133808/webpack-ots-parsing-error-loading-fonts/34133809#34133809
if (!__DEV__) {
  debug('Applying ExtractTextPlugin to CSS loaders.')
  webpackConfig.module.rules.filter(rule =>
    rule.loader && /css/.test(rule.loader)
  ).forEach(loader => {
    const first = rule.loader
    const rest = rule.loader.slice(1)

    rule.loader = ExtractTextPlugin.extract({
      fallback: first,
      use: rest.join('!')
    })
    delete rule.loader
  })

  webpackConfig.plugins.push(
    new ExtractTextPlugin({
      filename  : '[name].[contenthash].css',
      allChunks : true
    })
  )
}
module.exports = webpackConfig
<commit_msg>Update ExtractTextPlugin fix<commit_after>const argv = require('yargs').argv
const webpack = require('webpack')
const cssnano = require('cssnano')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const project = require('./project.config')
const debug = require('debug')('app:config:webpack')

const __DEV__ = project.globals.__DEV__
const __PROD__ = project.globals.__PROD__
const __TEST__ = project.globals.__TEST__

debug('Creating configuration.')
const webpackConfig = {
  name    : 'client',
  target  : 'web',
  devtool : project.compiler_devtool,
  resolve : {
    modules: [
      project.paths.client(),
      'node_modules',
    ],
    extensions : ['.js', '.jsx', '.json'],
    alias      : {
      'constants': project.paths.server('./constants'),
    }
  },
  module : {}
}
// ------------------------------------
// Entry Points
// ------------------------------------
const APP_ENTRY = project.paths.client('main.js')

webpackConfig.entry = {
  app : __DEV__
    ? [APP_ENTRY].concat(`webpack-hot-middleware/client?path=${project.compiler_public_path}__webpack_hmr`)
    : [APP_ENTRY],
  vendor : project.compiler_vendors
}

// ------------------------------------
// Bundle Output
// ------------------------------------
webpackConfig.output = {
  filename   : `[name].[${project.compiler_hash_type}].js`,
  path       : project.paths.dist(),
  publicPath : project.compiler_public_path
}

// ------------------------------------
// Externals
// ------------------------------------
webpackConfig.externals = {}
webpackConfig.externals['react/lib/ExecutionEnvironment'] = true
webpackConfig.externals['react/lib/ReactContext'] = true
webpackConfig.externals['react/addons'] = true

// ------------------------------------
// Plugins
// ------------------------------------
webpackConfig.plugins = [
  new webpack.DefinePlugin(project.globals),
  new HtmlWebpackPlugin({
    template : project.paths.client('index.html'),
    hash     : false,
    favicon  : project.paths.public('favicon.ico'),
    filename : 'index.html',
    inject   : 'body',
    minify   : {
      collapseWhitespace : true
    }
  })
]

// Ensure that the compiler exits on errors during testing so that
// they do not get skipped and misreported.
if (__TEST__ && !argv.watch) {
  webpackConfig.plugins.push(function () {
    this.plugin('done', function (stats) {
      if (stats.compilation.errors.length) {
        // Pretend no assets were generated. This prevents the tests
        // from running making it clear that there were warnings.
        throw new Error(
          stats.compilation.errors.map(err => err.message || err)
        )
      }
    })
  })
}

if (__DEV__) {
  debug('Enabling plugins for live development (HMR, NoEmitOnErrors)')
  webpackConfig.plugins.push(
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoEmitOnErrorsPlugin()
  )
} else if (__PROD__) {
  debug('Enabling plugins for production (UglifyJS)')
  webpackConfig.plugins.push(
    new webpack.optimize.UglifyJsPlugin({
      sourceMap: true,
      compress : {
        unused    : true,
        dead_code : true,
        // warnings  : false
      }
    }),
    new webpack.optimize.AggressiveMergingPlugin()
  )
}

// Don't split bundles during testing, since we only want import one bundle
if (!__TEST__) {
  webpackConfig.plugins.push(
    new webpack.optimize.CommonsChunkPlugin({
      names : ['vendor']
    })
  )
}

// ------------------------------------
// Loaders
// ------------------------------------
// JavaScript
webpackConfig.module.rules = [{
  test    : /\.(js|jsx)$/,
  exclude : /node_modules/,
  loader  : 'babel-loader',
  query   : project.compiler_babel,
}]

// ------------------------------------
// Style Loaders
// ------------------------------------
// We use cssnano with the postcss loader, so we tell
// css-loader not to duplicate minimization.
webpackConfig.module.rules.push({
  test : /\.scss$/,
  use  : [
    {
      loader: 'style-loader'
    },
    {
      loader      : 'css-loader',
      options     : {
        sourceMap : true,
        minimize  : true,
      }
    },
    {
      loader : 'postcss-loader'
    },
    {
      loader  : 'sass-loader',
      options : {
        sourceMap : true,
        includePaths: [...project.paths.client('styles'), './node_modules'],
      }
    }
  ]
})
webpackConfig.module.rules.push({
  test : /\.css$/,
  use  : [
    {
      loader : 'style-loader'
    },
    {
      loader  : 'css-loader',
      options : {
        modules   : true,
        sourceMap : true,
        minimize  : true
      }
    },
    {
      loader : 'postcss-loader'
    }
  ]
})

webpackConfig.plugins.push(
  new webpack.LoaderOptionsPlugin({
    options : {
      postcss : [
        cssnano({
          autoprefixer : {
            add      : true,
            remove   : true,
            browsers : ['last 2 versions']
          },
          discardComments: {
            removeAll : true
          },
          discardUnused : false,
          mergeIdents   : false,
          reduceIdents  : false,
          safe          : true,
          sourcemap     : true
        })
      ],
      sassLoader : {
        includePaths : project.paths.client('styles')
      }
    }
  })
)

// File loaders
/* eslint-disable */
webpackConfig.module.rules.push(
  {
    test    : /\.woff(\?.*)?$/,
    loader  : 'url-loader',
    options : {
      prefix : 'fonts/',
      name     : 'fonts/[name].[ext]',
      limit    : '10000',
      mimetype : 'application/font-woff'
    }
  },
  {
    test    : /\.woff2(\?.*)?$/,
    loader  : 'url-loader',
    options : {
      prefix   : 'fonts/',
      name     : 'fonts/[name].[ext]',
      limit    : '10000',
      mimetype : 'application/font-woff2'
    }
  },
  {
    test    : /\.otf(\?.*)?$/,
    loader  : 'file-loader',
    options : {
      prefix   : 'fonts/',
      name     : 'fonts/[name].[ext]',
      limit    : '10000',
      mimetype : 'font/opentype'
    }
  },
  {
    test    : /\.ttf(\?.*)?$/,
    loader  : 'url-loader',
    options : {
      prefix   : 'fonts/',
      name     : 'fonts/[name].[ext]',
      limit    : '10000',
      mimetype : 'application/octet-stream'
    }
  },
  {
    test    : /\.eot(\?.*)?$/,
    loader  : 'file-loader',
    options : {
      prefix : 'fonts/',
      name   : 'fonts/[name].[ext]'
    }
  },
  {
    test    : /\.svg(\?.*)?$/,
    loader  : 'url-loader',
    options : {
      prefix   : 'fonts/',
      name     : 'fonts/[name].[ext]',
      limit    : '10000',
      mimetype : 'image/svg+xml'
    }
  },
  {
    test    : /\.(png|jpg)$/,
    loader  : 'url-loader',
    options : {
      limit : '8192'
    }
  }
)
/* eslint-enable */

// ------------------------------------
// Finalize Configuration
// ------------------------------------
// when we don't know the public path (we know it only when HMR is enabled [in development]) we
// need to use the extractTextPlugin to fix this issue:
// http://stackoverflow.com/questions/34133808/webpack-ots-parsing-error-loading-fonts/34133809#34133809
if (!__DEV__) {
  debug('Apply ExtractTextPlugin to CSS loaders.')

  webpackConfig.module.rules.filter(rule =>
    rule.use && rule.use.some(loader => /css/.test(loader.loader))
  ).forEach(rule => {
    const [first, ...rest] = rule.use

    rule.use = ExtractTextPlugin.extract({
      fallback: first,
      use: rest.join('!')
    })
  })

  webpackConfig.plugins.push(
    new ExtractTextPlugin({
      filename  : '[name].[contenthash].css',
      allChunks : true
    })
  )
}
module.exports = webpackConfig
<|endoftext|>


<commit_before>var path = require('path');
var fs = require('fs-extra');
var pug = require('pug');

var buildUtils = require('../examples/build-utils');

// generate the tutorials
fs.ensureDirSync('website/source/tutorials');
var tutorials = buildUtils.getList('tutorials', 'tutorial', path.resolve('website', 'source'));

tutorials.map(function (json) {
  var pugTemplate = fs.readFileSync(path.relative('.', path.resolve(json.dir, 'index.pug')), 'utf8');
  pugTemplate = pugTemplate.replace('extends ../common/index.pug', 'extends ../common/index-website.pug');

  var fn = pug.compile(pugTemplate, {
    pretty: false,
    filename: path.relative('.', path.resolve(json.dir, 'index.pug'))
  });
  var html = fn(json);
  html = `---
layout: tutorial
title: ${json.title}
about: ${json.about.text}
tutorialCss: ${JSON.stringify(json.tutorialCss)}
tutorialJs: ${JSON.stringify(json.tutorialJs)}
---
` + html;
  fs.writeFileSync(path.resolve(json.output, 'index.html'), html);
});

// copy common files
fs.copySync('tutorials/common', 'website/source/tutorials/common');

buildUtils.writeYamlList(path.resolve('website', 'source', '_data'), 'tutorials.yml', tutorials);
<commit_msg>Fix the website tutorial build to escape <=.<commit_after>var path = require('path');
var fs = require('fs-extra');
var pug = require('pug');

var buildUtils = require('../examples/build-utils');

// generate the tutorials
fs.ensureDirSync('website/source/tutorials');
var tutorials = buildUtils.getList('tutorials', 'tutorial', path.resolve('website', 'source'));

tutorials.map(function (json) {
  var pugTemplate = fs.readFileSync(path.relative('.', path.resolve(json.dir, 'index.pug')), 'utf8');
  pugTemplate = pugTemplate.replace('extends ../common/index.pug', 'extends ../common/index-website.pug');

  var fn = pug.compile(pugTemplate, {
    pretty: false,
    filename: path.relative('.', path.resolve(json.dir, 'index.pug'))
  });
  var html = fn(json);
  html = html.replace(/<=/g, '<=').replace(/>=/g, '>=');
  html = `---
layout: tutorial
title: ${json.title}
about: ${json.about.text}
tutorialCss: ${JSON.stringify(json.tutorialCss)}
tutorialJs: ${JSON.stringify(json.tutorialJs)}
---
` + html;
  fs.writeFileSync(path.resolve(json.output, 'index.html'), html);
});

// copy common files
fs.copySync('tutorials/common', 'website/source/tutorials/common');

buildUtils.writeYamlList(path.resolve('website', 'source', '_data'), 'tutorials.yml', tutorials);
<|endoftext|>


<commit_before><commit_msg>Applied a workaround until https://github.com/phetsims/sun/issues/173 can be addressed<commit_after><|endoftext|>


<commit_before>// - get available locales on init stage
// - setup locale from cookies if exists
// - guess locale from browser (headers) if no cookies
// - use default locale in other cases
//
'use strict';

const _ = require('lodash');

module.exports = function (N) {
  // Enabled locales map of `normalized -> original` pairs.
  //
  //   { 'ru-ru': 'ru-RU', 'en': 'en-US' }
  //
  var enabledLocalesMap = {};

  // RegExp used to extract language quality
  //
  var QUALITY_RE = /^q=([0-9.]+)$/;

  // Parses Accept-Language header string into array of locale names sorted by
  // quality and with appended zone-less fallback for each language.
  //
  //   'en-US;q=0.8,en-GB,ru-RU' -> [ 'en-gb', 'en-us', 'en', 'ru-ru', 'ru' ]
  //
  // NOTE: We limit amount of variant to maximum 10 elements.
  //
  function getAcceptedLanguages(string) {
    var tmp = String(string)
            // remove any whitespace that might appear according to RFC:
            // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4
            .replace(/\s+/g, '')
            .split(',')
            // Limit list to 10 for safety
            .slice(0, 10);

    return _(tmp)
              // parse partials
              // [ 'en-US;q=0.8', 'en-GB', 'ru-RU' ]
              .map(function (str) {
                var q = 1,
                    parts = str.split(';', 2);

                if (QUALITY_RE.test(parts[1])) {
                  var qval = parseFloat(parts[1].match(QUALITY_RE)[1]);
                  if (!isNaN(qval)) { q = qval; }
                }

                return {
                  locale: parts[0].toLowerCase(),
                  quality: q
                };
              })
              .sortBy(tmp, 'quality')
              .map('locale')
              // cleanup garbage
              .compact()
              .uniq()
              .value();
  }

  // find first matching locale from the list of accepted languages
  //
  function findAcceptedLanguage(req) {
    var locales, i, l;

    if (req && req.headers && req.headers['accept-language']) {
      locales = getAcceptedLanguages(req.headers['accept-language']);

      for (i = 0; i < locales.length; i++) {
        l = locales[i];
        if (enabledLocalesMap[l]) return l;
      }

      // if not found - try second pass, with stripped language zones
      for (i = 0; i < locales.length; i++) {
        l = locales[i].split('-', 2)[0];
        if (enabledLocalesMap[l]) return l;
      }
    }
  }

  ////////////////////////////////////////////////////////////////////////////////
  // Fill enabled locales map on INIT stage. (all i18n is done in bundler)
  //
  N.wire.after('init:bundle', function locale_set_prepare(N) {

    // Add full locale names to the map.
    N.config.locales.forEach(function (locale) {
      enabledLocalesMap[locale.toLowerCase()] = locale;
    });

    // Add zone-less locale aliases like 'en' for 'en-US'.
    N.config.locales.forEach(function (locale) {
      var languageId = locale.toLowerCase().split('-')[0];

      if (!enabledLocalesMap[languageId]) {
        enabledLocalesMap[languageId] = locale;
      }
    });
  });

  ////////////////////////////////////////////////////////////////////////////////
  // Add helper to env
  //
  require('nodeca.core/lib/system/env').initHandlers.push(env => {
    env.helpers.getLocale  = function () {
      let locale;

      // Use locale from cookies if presented and valid
      //
      if (env.extras.getCookie) {
        locale = env.extras.getCookie('locale');

        if (N.config.locales.indexOf(locale) !== -1) return locale;
      }

      // Try autodetect by browser headers
      //
      locale = enabledLocalesMap[findAcceptedLanguage(env.origin.req)];

      if (locale) return locale;

      // Use default in other cases
      //
      return N.config.locales[0];
    };
  });

  ////////////////////////////////////////////////////////////////////////////////
  // Fill locale to runtime for use in the browser
  //
  N.wire.after('server_chain:http:*', function fill_runtime_locale(env) {
    env.runtime.locale = env.helpers.getLocale();
  });
};
<commit_msg>Fix sort order in locales detector<commit_after>// - get available locales on init stage
// - setup locale from cookies if exists
// - guess locale from browser (headers) if no cookies
// - use default locale in other cases
//
'use strict';

const _ = require('lodash');

module.exports = function (N) {
  // Enabled locales map of `normalized -> original` pairs.
  //
  //   { 'ru-ru': 'ru-RU', 'en': 'en-US' }
  //
  var enabledLocalesMap = {};

  // RegExp used to extract language quality
  //
  var QUALITY_RE = /^q=([0-9.]+)$/;

  // Parses Accept-Language header string into array of locale names sorted by
  // quality and with appended zone-less fallback for each language.
  //
  //   'en-US;q=0.8,en-GB,ru-RU' -> [ 'en-gb', 'en-us', 'en', 'ru-ru', 'ru' ]
  //
  // NOTE: We limit amount of variant to maximum 10 elements.
  //
  function getAcceptedLanguages(string) {
    var tmp = String(string)
            // remove any whitespace that might appear according to RFC:
            // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4
            .replace(/\s+/g, '')
            .split(',')
            // Limit list to 10 for safety
            .slice(0, 10);

    return _(tmp)
              // parse partials
              // [ 'en-US;q=0.8', 'en-GB', 'ru-RU' ]
              .map(function (str) {
                var q = 1,
                    parts = str.split(';', 2);

                if (QUALITY_RE.test(parts[1])) {
                  var qval = parseFloat(parts[1].match(QUALITY_RE)[1]);
                  if (!isNaN(qval)) { q = qval; }
                }

                return {
                  locale: parts[0].toLowerCase(),
                  quality: q
                };
              })
              .sortBy(l => -l.quality)
              .map('locale')
              // cleanup garbage
              .compact()
              .uniq()
              .value();
  }

  // find first matching locale from the list of accepted languages
  //
  function findAcceptedLanguage(req) {
    var locales, i, l;

    if (req && req.headers && req.headers['accept-language']) {
      locales = getAcceptedLanguages(req.headers['accept-language']);

      for (i = 0; i < locales.length; i++) {
        l = locales[i];
        if (enabledLocalesMap[l]) return l;
      }

      // if not found - try second pass, with stripped language zones
      for (i = 0; i < locales.length; i++) {
        l = locales[i].split('-', 2)[0];
        if (enabledLocalesMap[l]) return l;
      }
    }
  }

  ////////////////////////////////////////////////////////////////////////////////
  // Fill enabled locales map on INIT stage. (all i18n is done in bundler)
  //
  N.wire.after('init:bundle', function locale_set_prepare(N) {

    // Add full locale names to the map.
    N.config.locales.forEach(function (locale) {
      enabledLocalesMap[locale.toLowerCase()] = locale;
    });

    // Add zone-less locale aliases like 'en' for 'en-US'.
    N.config.locales.forEach(function (locale) {
      var languageId = locale.toLowerCase().split('-')[0];

      if (!enabledLocalesMap[languageId]) {
        enabledLocalesMap[languageId] = locale;
      }
    });
  });

  ////////////////////////////////////////////////////////////////////////////////
  // Add helper to env
  //
  require('nodeca.core/lib/system/env').initHandlers.push(env => {
    env.helpers.getLocale  = function () {
      let locale;

      // Use locale from cookies if presented and valid
      //
      if (env.extras.getCookie) {
        locale = env.extras.getCookie('locale');

        if (N.config.locales.indexOf(locale) !== -1) return locale;
      }

      // Try autodetect by browser headers
      //
      locale = enabledLocalesMap[findAcceptedLanguage(env.origin.req)];

      if (locale) return locale;

      // Use default in other cases
      //
      return N.config.locales[0];
    };
  });

  ////////////////////////////////////////////////////////////////////////////////
  // Fill locale to runtime for use in the browser
  //
  N.wire.after('server_chain:http:*', function fill_runtime_locale(env) {
    env.runtime.locale = env.helpers.getLocale();
  });
};
<|endoftext|>


<commit_before>'use strict';

const format = require('date-fns/format');
const parseType = require('../parse-type');

describe('parseType', () => {
  describe('boolean', () => {
    it('Handles string booleans', () => {
      expect(parseType({ type: 'boolean', value: 'true' })).toBe(true);
      expect(parseType({ type: 'boolean', value: 't' })).toBe(true);
      expect(parseType({ type: 'boolean', value: '1' })).toBe(true);

      expect(parseType({ type: 'boolean', value: 'false' })).toBe(false);
      expect(parseType({ type: 'boolean', value: 'f' })).toBe(false);
      expect(parseType({ type: 'boolean', value: '0' })).toBe(false);

      expect(() => parseType({ type: 'boolean', value: 'test' })).toThrow();
    });

    it('Handles numerical booleans', () => {
      expect(parseType({ type: 'boolean', value: 1 })).toBe(true);

      expect(parseType({ type: 'boolean', value: 0 })).toBe(false);

      expect(() => parseType({ type: 'boolean', value: 12 })).toThrow();
    });
  });

  describe('Time', () => {
    it('Always returns the same time format', () => {
      expect(parseType({ type: 'time', value: '12:31:11' })).toBe('12:31:11.000');
      expect(parseType({ type: 'time', value: '12:31:11.2' })).toBe('12:31:11.200');
      expect(parseType({ type: 'time', value: '12:31:11.31' })).toBe('12:31:11.310');
      expect(parseType({ type: 'time', value: '12:31:11.319' })).toBe('12:31:11.319');
    });

    it('Throws on  invalid time format', () => {
      expect(() => parseType({ type: 'time', value: '25:12:09' })).toThrow();
      expect(() => parseType({ type: 'time', value: '23:78:09' })).toThrow();
      expect(() => parseType({ type: 'time', value: '23:11:99' })).toThrow();

      expect(() => parseType({ type: 'time', value: '12:12' })).toThrow();
      expect(() => parseType({ type: 'time', value: 'test' })).toThrow();
      expect(() => parseType({ type: 'time', value: 122 })).toThrow();
      expect(() => parseType({ type: 'time', value: {} })).toThrow();
      expect(() => parseType({ type: 'time', value: [] })).toThrow();
    });
  });

  describe('Date', () => {
    it('Supports ISO formats and always returns the right format', () => {
      expect(parseType({ type: 'date', value: '2019-01-01 12:01:11' })).toBe('2019-01-01');

      expect(parseType({ type: 'date', value: '2018-11-02' })).toBe('2018-11-02');

      const isoDateFormat = new Date().toISOString();
      const expectedDateFormat = format(new Date(isoDateFormat), 'yyyy-MM-dd');

      expect(parseType({ type: 'date', value: isoDateFormat })).toBe(expectedDateFormat);
    });

    it('Throws on invalid formator dates', () => {
      expect(() => parseType({ type: 'date', value: '-1029-11-02' })).toThrow();
      expect(() => parseType({ type: 'date', value: '2019-13-02' })).toThrow();
      expect(() => parseType({ type: 'date', value: '2019-12-32' })).toThrow();
      expect(() => parseType({ type: 'date', value: '2019-02-31' })).toThrow();
    });

    it('Throws on incorrect dates and checks the error message', () => {
      expect(() => parseType({ type: 'date', value: '2019-213-23' })).toThrow(
        'Invalid format, expected an ISO compatible date'
      );
      expect(() => parseType({ type: 'date', value: '-212' })).toThrow(
        'Invalid format, expected an ISO compatible date'
      );
      expect(() => parseType({ type: 'date', value: '2020-02-31' })).toThrow(
        'Invalid format, expected an ISO compatible date'
      );
    });
  });

  describe('Datetime', () => {
    it.each(['2019-01-01', '2019-01-01 10:11:12', '1234567890111', '2019-01-01T10:11:12.123Z'])(
      'Supports ISO formats and always returns a date %s',
      value => {
        const r = parseType({ type: 'datetime', value });
        expect(r instanceof Date).toBe(true);
      }
    );
  });
});
<commit_msg>Addressed PR comments to check throw messages<commit_after>'use strict';

const format = require('date-fns/format');
const parseType = require('../parse-type');

describe('parseType', () => {
  describe('boolean', () => {
    it('Handles string booleans', () => {
      expect(parseType({ type: 'boolean', value: 'true' })).toBe(true);
      expect(parseType({ type: 'boolean', value: 't' })).toBe(true);
      expect(parseType({ type: 'boolean', value: '1' })).toBe(true);

      expect(parseType({ type: 'boolean', value: 'false' })).toBe(false);
      expect(parseType({ type: 'boolean', value: 'f' })).toBe(false);
      expect(parseType({ type: 'boolean', value: '0' })).toBe(false);

      expect(() => parseType({ type: 'boolean', value: 'test' })).toThrow();
    });

    it('Handles numerical booleans', () => {
      expect(parseType({ type: 'boolean', value: 1 })).toBe(true);

      expect(parseType({ type: 'boolean', value: 0 })).toBe(false);

      expect(() => parseType({ type: 'boolean', value: 12 })).toThrow();
    });
  });

  describe('Time', () => {
    it('Always returns the same time format', () => {
      expect(parseType({ type: 'time', value: '12:31:11' })).toBe('12:31:11.000');
      expect(parseType({ type: 'time', value: '12:31:11.2' })).toBe('12:31:11.200');
      expect(parseType({ type: 'time', value: '12:31:11.31' })).toBe('12:31:11.310');
      expect(parseType({ type: 'time', value: '12:31:11.319' })).toBe('12:31:11.319');
    });

    it('Throws on  invalid time format', () => {
      expect(() => parseType({ type: 'time', value: '25:12:09' })).toThrow();
      expect(() => parseType({ type: 'time', value: '23:78:09' })).toThrow();
      expect(() => parseType({ type: 'time', value: '23:11:99' })).toThrow();

      expect(() => parseType({ type: 'time', value: '12:12' })).toThrow();
      expect(() => parseType({ type: 'time', value: 'test' })).toThrow();
      expect(() => parseType({ type: 'time', value: 122 })).toThrow();
      expect(() => parseType({ type: 'time', value: {} })).toThrow();
      expect(() => parseType({ type: 'time', value: [] })).toThrow();
    });
  });

  describe('Date', () => {
    it('Supports ISO formats and always returns the right format', () => {
      expect(parseType({ type: 'date', value: '2019-01-01 12:01:11' })).toBe('2019-01-01');

      expect(parseType({ type: 'date', value: '2018-11-02' })).toBe('2018-11-02');

      const isoDateFormat = new Date().toISOString();
      const expectedDateFormat = format(new Date(isoDateFormat), 'yyyy-MM-dd');

      expect(parseType({ type: 'date', value: isoDateFormat })).toBe(expectedDateFormat);
    });

    it('Throws on invalid formator dates', () => {
      expect(() => parseType({ type: 'date', value: '-1029-11-02' })).toThrow(
        'Invalid format, expected an ISO compatible date'
      );
      expect(() => parseType({ type: 'date', value: '2019-13-02' })).toThrow(
        'Invalid format, expected an ISO compatible date'
      );
      expect(() => parseType({ type: 'date', value: '2019-12-32' })).toThrow(
        'Invalid format, expected an ISO compatible date'
      );
      expect(() => parseType({ type: 'date', value: '2019-02-31' })).toThrow(
        'Invalid format, expected an ISO compatible date'
      );
    });

    it('Throws on incorrect dates and checks the error message', () => {
      expect(() => parseType({ type: 'date', value: '2019-213-23' })).toThrow(
        'Invalid format, expected an ISO compatible date'
      );
      expect(() => parseType({ type: 'date', value: '-212' })).toThrow(
        'Invalid format, expected an ISO compatible date'
      );
      expect(() => parseType({ type: 'date', value: '2020-02-31' })).toThrow(
        'Invalid format, expected an ISO compatible date'
      );
    });
  });

  describe('Datetime', () => {
    it.each(['2019-01-01', '2019-01-01 10:11:12', '1234567890111', '2019-01-01T10:11:12.123Z'])(
      'Supports ISO formats and always returns a date %s',
      value => {
        const r = parseType({ type: 'datetime', value });
        expect(r instanceof Date).toBe(true);
      }
    );
  });
});
<|endoftext|>


<commit_before>/* eslint-disable*/
import React from 'react'
import logoDTA from './dta_logo.svg'
import logoNISA from './NISA_logo.svg'

const AUFooter = () => (

              About us

              Contact us

              Terms of Use

              Privacy

              Security

              Disclaimer

              Copyright

                An initiative of the Digital Transformation Agency. This program
                forms part of the National Innovation and Science{' '}
                Agenda. With the exception of the Commonwealth Coat
                of Arms and where otherwise noted, this work is licensed under the{' '}

                  MIT license

)

export default AUFooter
<commit_msg>[Footer] Update NISA link (#707)<commit_after>/* eslint-disable*/
import React from 'react'
import logoDTA from './dta_logo.svg'
import logoNISA from './NISA_logo.svg'

const AUFooter = () => (

              About us

              Contact us

              Terms of Use

              Privacy

              Security

              Disclaimer

              Copyright

                An initiative of the Digital Transformation Agency. This program
                forms part of the National Innovation and Science{' '}

                  Agenda
                . With the exception of the Commonwealth Coat of Arms and where otherwise noted, this work is
                licensed under the{' '}

                  MIT license

)

export default AUFooter
<|endoftext|>


<commit_before>;(function($){

})(jQuery);
<commit_msg>Update search.js<commit_after>;(function($){

})(window.jQuery);
<|endoftext|>


<commit_before>"use strict"

// CONFIG

// Mapbox
function getMapboxAccessToken() {
    return "pk.eyJ1IjoibmljaG85MCIsImEiOiJjaWdrdmswOTQwMDd0dmlrdHFibzQzNjU1In0.s96Fw4mPajLSSu6Azfzgfw";
};

// API
function getURL() {
    return "http://localhost:8080/api";
}
<commit_msg>Changed Mapbox-Access-Token<commit_after>"use strict"

// CONFIG

// Mapbox
function getMapboxAccessToken() {
    return "pk.eyJ1IjoibmljaG85MCIsImEiOiJjaWp3enA1NmMwMDFzdmNtMGczdGI4YTdxIn0.WKPEegyEq-K_65K-OJ0mgg";
};

// API
function getURL() {
    return "http://localhost:8080/api";
}
<|endoftext|>


<commit_before>/* Project specific Javascript goes here. */
$(document).ready(function() {
    console.log("ready!");
    $("#upload_image_form").on('submit', function(e) {
        e.preventDefault();
        console.log("Submitted!");
        data = new FormData(e.target);
        $.ajax({
            url: e.target.action,
            type: 'POST',
            data: data,
            cache: false,
            dataType: 'json',
            processData: false,
            contentType: false,
            success: function(data) {
                console.log("Success");
                console.log(arguments);
                if (data['location']) {
                    $('#error').hide();
                    $('#id_text_ifr').contents().find('body').append(
                            '');
                } else {
                    var $err = $('#error');
                    $err.text(data['error'].file[0]);
                    $err.show();
                    console.log(data['error']);
                }
                // make file uploading possible again
                e.target.reset();
            },
            error: function() {
                console.log("Error");
                console.log(arguments);
            }
        });
    });
});
<commit_msg>Made images scale properly<commit_after>/* Project specific Javascript goes here. */
$(document).ready(function() {
    console.log("ready!");
    $("#upload_image_form").on('submit', function(e) {
        e.preventDefault();
        console.log("Submitted!");
        data = new FormData(e.target);
        $.ajax({
            url: e.target.action,
            type: 'POST',
            data: data,
            cache: false,
            dataType: 'json',
            processData: false,
            contentType: false,
            success: function(data) {
                console.log("Success");
                console.log(arguments);
                if (data['location']) {
                    $('#error').hide();
                    $('#id_text_ifr').contents().find('body').append(
                            '');
                } else {
                    var $err = $('#error');
                    $err.text(data['error'].file[0]);
                    $err.show();
                    console.log(data['error']);
                }
                // make file uploading possible again
                e.target.reset();
            },
            error: function() {
                console.log("Error");
                console.log(arguments);
            }
        });
    });
});
<|endoftext|>


<commit_before>// JS for Palettable Chrome Extension - by Jason Gresalfi - released under MIT License - 2017

"use strict";

//Workaround for restriction on accessing external styles by using Window.getComputedStyle method
function getColor(e) {
    var color = window.getComputedStyle(e, null)
        .getPropertyValue('background-color');
    return color;
}

//This filters out default background colors of elements - browser sets default to rgba black with full transparency
function filterBlack(e) {
    if (e !== 'rgba(0, 0, 0, 0)' && 'rgb(0, 0, 0)') {
        return e;
    }
}

//After pageColors() sorts the color list - killDupes() removes any duplicate background colors when multiple elements are assigned the same color
function killDupes(arr) {
    var finalArr = [];
    for (var i = 0; i < arr.length; i++) {
        if (arr[i] !== (arr[i + 1])) {
            finalArr.push(arr[i]);
        }
    }
    return finalArr;
}

function colorBlob(c) {
    var blob = new Blob(c, { "type": "text" });
    return blob;
}

function colorExport(blob) {
    var reader = new FileReader();
    reader.onload = function(e) {
        return e.target.result;
    };
    reader.readAsText(blob);
}

function blobToFile(blob, fileName) {
    blob.lastModifiedDate = new Date();
    blob.name = fileName;
    return blob;
}

//Grabs all elements from a page (a little sledgehammery) - Web API's CSSStyleSheet.cssRules interface restricted by CORS
function pageColors() {
    var pageEls = Array.from(document.querySelectorAll('*'));
    var colorArr = pageEls.map(getColor)
        .filter(filterBlack)
        .sort();
    return killDupes(colorArr);
};

function formatColors(colors) {
  var arr = colors.map(function(e) {
    return "{ color: " + e + " }" + "\n";
  });
  return arr;
}

function grabFile(file) {
    download(file, "color-palette.css", "text/plain");
}

//Listener set for the message coming from popup.js - function arg 'sender' is ID of extension generated when packaged
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
    if (request.message === "get_colors") {
        var colors = pageColors();
        sendResponse({
            "message": "got_the_colors",
            colors: colors
        });
    } else if (request.message === "download-palette") {
        var colors = pageColors();
        var formattedColors = formatColors(colors);
        var blob = colorBlob(formattedColors);
        var file = blobToFile(blob, "color-palette.css");
        grabFile(file);
        sendResponse({
            "message": "file-downloaded"
        });
    }
});
<commit_msg>More extensive comments in content.js...extensively<commit_after>// JS for Palettable Chrome Extension - by Jason Gresalfi - released under MIT License - 2017

"use strict";

//Workaround for restriction on accessing external styles by using Window.getComputedStyle method - Web API's CSSStyleSheet.cssRules interface restricted by CORS
function getColor(e) {
    var color = window.getComputedStyle(e, null)
        .getPropertyValue('background-color');
    return color;
}

//This filters out default background colors of elements - browser sets default to rgba black with full transparency
function filterBlack(e) {
    if (e !== 'rgba(0, 0, 0, 0)' && 'rgb(0, 0, 0)') {
        return e;
    }
}

//After pageColors() sorts the color list - killDupes() removes any duplicate background colors when multiple elements are assigned the same color
function killDupes(arr) {
    var finalArr = [];
    for (var i = 0; i < arr.length; i++) {
        if (arr[i] !== (arr[i + 1])) {
            finalArr.push(arr[i]);
        }
    }
    return finalArr;
}

//Create a blob from the array of colors - you can access the list of blobs via chrome://blob-internals
function colorBlob(c) {
    var blob = new Blob(c, { "type": "text" });
    return blob;
}

//This takes the blob data and adds timestamp and file name properties essentially turning it into a "file"
function blobToFile(blob, fileName) {
    blob.lastModifiedDate = new Date();
    blob.name = fileName;
    return blob;
}

//Grabs all elements from a page (a little sledgehammery)
function pageColors() {
    var pageEls = Array.from(document.querySelectorAll('*'));
    var colorArr = pageEls.map(getColor)
        .filter(filterBlack)
        .sort();
    return killDupes(colorArr);
};

//Takes each color value and makes it into a nice CSS-like list
function formatColors(colors) {
  var arr = colors.map(function(e) {
    return "{ color: " + e + " }" + "\n";
  });
  return arr;
}

function grabFile(file) {
    download(file, "color-palette.css", "text/plain");
}

//Listener set for the message coming from popup.js - function arg 'sender' is ID of extension generated when packaged
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
    if (request.message === "get_colors") {
        var colors = pageColors();
        sendResponse({
            "message": "got_the_colors", //Arbitrary JSON can be returned - here a message is sent with color values
            colors: colors
        });
    } else if (request.message === "download-palette") {
        var colors = pageColors();
        var formattedColors = formatColors(colors); //Formats color values to make more readable
        var blob = colorBlob(formattedColors); //Stores formatted color list in a blob
        var file = blobToFile(blob, "color-palette.css"); //Adds file properties to blob data
        grabFile(file); //Use download.js libraries to save blob file to location
        sendResponse({
            "message": "file-downloaded"
        });
    }
});
<|endoftext|>


<commit_before>const getUserPolyfills = (polyfills) => {
	return polyfills.reduce((userPolyfills, polyfill) => {
		if (polyfill.isNeeded) {
			const bundle = typeof polyfill.bundle === 'function' ? polyfill.bundle() : polyfill.bundle;
			if (typeof bundle !== 'undefined') {
				userPolyfills.push(bundle);
			}
		}
		return userPolyfills;
	}, []);
};

const getPolyfillsURL = (polyfillBundles, { url }) => {
	return `${url}/polyfills.js?with=${polyfillBundles.join(',')}`;
};

const getScriptLoader = () => {
	const loadAsyncScript = (url) => {
		const tag = document.createElement('script');
		tag.src = url;
		tag.async = false;
		document.head.appendChild(tag);
	};

	const pendingScripts = [];
	const scriptStateChange = () => {
		while (pendingScripts[0] && pendingScripts[0].readyState === 'loaded') {
			const scriptToExecute = pendingScripts.shift();
			scriptToExecute.onreadystatechange = null;
			document.head.appendChild(scriptToExecute);
		}
	};
	const loadReadyStateScript = (url) => {
		const tag = document.createElement('script');
		pendingScripts.push(tag);
		tag.onreadystatechange = scriptStateChange;
		tag.src = url;
	};

	if ('async' in document.createElement('script')) {
		return {
			load: loadAsyncScript
		};
	} else {
		return {
			load: loadReadyStateScript
		};
	}
};

export default ({ polyfills, url }) => {
	const scriptLoader = getScriptLoader();
	const userPolyfills = getUserPolyfills(polyfills);
	if (userPolyfills.length > 0) {
		console.log('fetching polyfills : ', userPolyfills.join(', ')); //eslint-disable-line
		const polyfillURL = getPolyfillsURL(userPolyfills, { url });
		scriptLoader.load(polyfillURL);
	} else {
		console.log('you dont need no polyfill'); //eslint-disable-line
	}
	window.polyfilledScripts.forEach(scriptURL => {
		scriptLoader.load(scriptURL);
	});
};
<commit_msg>Fix old IE bug<commit_after>const getUserPolyfills = (polyfills) => {
	return polyfills.reduce((userPolyfills, polyfill) => {
		if (polyfill.isNeeded) {
			const bundle = typeof polyfill.bundle === 'function' ? polyfill.bundle() : polyfill.bundle;
			if (typeof bundle !== 'undefined') {
				userPolyfills.push(bundle);
			}
		}
		return userPolyfills;
	}, []);
};

const getPolyfillsURL = (polyfillBundles, { url }) => {
	return `${url}/polyfills.js?with=${polyfillBundles.join(',')}`;
};

const getScriptLoader = () => {
	const scriptTag = document.scripts[0];

	const loadAsyncScript = (url) => {
		const tag = document.createElement('script');
		tag.src = url;
		tag.async = false;
		document.head.appendChild(tag);
	};

	const pendingScripts = [];
	const scriptStateChange = () => {
		while (pendingScripts[0] && pendingScripts[0].readyState === 'loaded') {
			const scriptToExecute = pendingScripts.shift();
			scriptToExecute.onreadystatechange = null;
			scriptTag.parentNode.insertBefore(scriptToExecute, scriptTag);
		}
	};
	const loadReadyStateScript = (url) => {
		const tag = document.createElement('script');
		pendingScripts.push(tag);
		tag.onreadystatechange = scriptStateChange;
		tag.src = url;
	};

	if ('async' in scriptTag) {
		return {
			load: loadAsyncScript
		};
	} else {
		return {
			load: loadReadyStateScript
		};
	}
};

export default ({ polyfills, url }) => {
	const scriptLoader = getScriptLoader();
	const userPolyfills = getUserPolyfills(polyfills);
	if (userPolyfills.length > 0) {
		console.log('fetching polyfills : ', userPolyfills.join(', ')); //eslint-disable-line
		const polyfillURL = getPolyfillsURL(userPolyfills, { url });
		scriptLoader.load(polyfillURL);
	} else {
		console.log('you dont need no polyfill'); //eslint-disable-line
	}
	window.polyfilledScripts.forEach(scriptURL => {
		scriptLoader.load(scriptURL);
	});
};
<|endoftext|>