<commit_before>/*
 * Copyright 2005 Sakai Foundation Licensed under the
 * Educational Community 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.osedu.org/licenses/ECL-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.
 */

// Eval Template Modify JS for onload functions
// @author lovemore.nalube@uct.ac.za

var evalTemplateLoaderEvents = (function($) {
    var _initDom = function(){
        startSort();
        $(document).trigger('activateControls.templateItems');
        buildSortableIds();
    },

    _modify_block = function(){
                var siteId = $('#site-id').text();
        $.facebox.setHeader(evalTemplateUtils.pages.modify_block_page);

		var baseId = ""; // "blockPage::";

		$('#saveBlockAction').click(function() {
			var childIdList = [],
                reuseBlockText = $('.blockText input[type=radio][checked][value!=new1]').length > 0;
			$('#blockForm input[name*=hidden-item-id]').each(function(){
				childIdList.push($(this).val());
			});
			$("#ordered-child-ids").val(childIdList.toString());
            if (reuseBlockText){
			    evalTemplateData.postFCKform('#blockForm', false, 'modify_block', $('#saveBlockAction'));
                return false;
            }else{
                evalTemplateData.postFCKform('#blockForm', 'item-text::input', 'modify_block', $('#saveBlockAction'));
                return false;
            }
		});

		function disableOrderButtons() {
			$it(baseId + "revertOrderButton").disabled = true;
			$it(baseId + "saveReorderButton").disabled = true;
		}

        //var sortableIds;
        function buildSortableIds() {
            var sortableIds = [];
            var domList = $("div.itemList > div").get();
			for (var i = 0; i < domList.length; i++) {
				sortableIds.push(domList[i].id);
			}
		}

		var reorderButtonsExist = false;
		var saveReorderButton = $it(baseId + "saveReorderButton");

		if (saveReorderButton !== null) {
			reorderButtonsExist = true;
			saveReorderButton.onclick = function() {
				disableOrderButtons();
				buildSortableIds();
				$(saveReorderButton.form).ajaxSubmit();
				return false;
			};
		}

		function setIndex(itemId, newindex) {
			$it(itemId + "item-num").innerHTML = (parseInt(newindex, 10) + 1);
		}

		// put original order into the revertOrder trigger
		var revertOrderButton = $it(baseId + "revertOrderButton");
		if (revertOrderButton !== null) {
			revertOrderButton.onclick = function() {
				disableOrderButtons();
				for(var i = sortableIds.length - 1; i > 0; --i) {
					var thisitem = $it(sortableIds[i]);
					var previtem = $it(sortableIds[i - 1]);
					previtem.parentNode.removeChild(previtem);
					thisitem.parentNode.insertBefore(previtem, thisitem);
					setIndex(thisitem.id, i);
				}
				setIndex(sortableIds[0], 0);
			};
		}
    },

    bindDeleteIcons = function(row){
        var scope = (typeof row === 'undefined') ? document : row.get();
        $(scope).find('a[rel=remove]').itemRemove({
            ref:    'eval-templateitem',
            id:     'evalTemplateUtils.getTemplateItemId($(this))',
            text:   '$(this).parents("div.itemLine2").find("h4.itemText:visible").text()'
        });
        $(scope).find('a[rel=childRemove]').itemRemove({
                    ref:    'eval-templateitem',
                    id:        '$(this).parents("div.itemRowBlock").find("input[name=hidden-item-id]").val()',
                    itemType: 'blockChild',
                    text:   '$(this).parents("div.itemRowBlock").find("span.text").text()'
                });
        $(scope).find('a[rel=childUngroup]').itemRemove({
                    ref:    'eval-templateitem/unblock',
                    id:    '$(this).parents("div.itemRowBlock").find("input[name=hidden-item-id]").val()',
                    itemType: 'blockChild',
                    text:   '$(this).parents("div.itemRowBlock").find("span.text:visible").text()'
                });
        $(scope).find('a[rel=unblock]').itemRemove({
            ref:    'eval-templateitem',
            id:        'evalTemplateUtils.getTemplateItemId($(this))',
            itemType: 'block',
            text:   '$(this).parents("div.itemLine2").find("h4.itemText:visible").text()'
        });
    },

    unBindDeleteIcons = function(){
        $('a[rel=remove]').unbind("click");
        $('a[rel=childRemove]').unbind("click");
        $('a[rel=childUngroup]').unbind("click");
        $('a[rel=unblock]').unbind("click");
    },

    bindRowEditPreviewIcons = function(changedRow){
        if ( typeof changedRow === "undefined" || changedRow === null){
            $('a[rel=facebox]').facebox();
            $('a[rel=faceboxGrid]').faceboxGrid();
        }else{
            changedRow.find('a[rel=facebox]').facebox();
            changedRow.find('a[rel=faceboxGrid]').faceboxGrid();
        }
    },

    unBindRowEditPreviewIcons = function(changedRow){
        if ( typeof changedRow === "undefined" || changedRow === null){
            $('a[rel=facebox]').unbind("facebox");
            $('a[rel=faceboxGrid]').unbind("faceboxGrid");
        }else{
            changedRow.find('a[rel=facebox]').unbind("facebox");
            changedRow.find('a[rel=faceboxGrid]').unbind("faceboxGrid");
        }
    },
        /**
         * this will bind these controls in the main item of a group: hide/show item && more/less item
          */
    bindGroupParentTextControls = function(row){
        var scope = (typeof row === 'undefined') ? document : row.get();
        $(scope).find('.blockExpandText').toggle(
            function() {
                if ($(this).parents('.itemRow').find('.itemLine3').is(':hidden')) {
                    $(this).click();
                    return false;
                }
                var text = evalTemplateUtils.messageLocator('modifytemplate.group.show');
                $(this).parents('.itemRow').find('.itemLine3').slideToggle();
                $(this).text(text);
                // save closed state
                evalTemplateUtils.closedGroup.add( $(this).parents(".itemRow").attr('name') );
                return false;
            },
            function() {
                var text = evalTemplateUtils.messageLocator('modifytemplate.group.hide');
                $(this).parents('.itemRow').find('.itemLine3').slideToggle();
                $(this).text(text);
                // remove closed state
                evalTemplateUtils.closedGroup.remove( $(this).parents(".itemRow").attr('name') );
                return false;
            });
        $(scope).find('.more').bind('click', function() {
            if ($(this).parents('.itemLine2').find('.itemText').eq(1).find('.blockExpandText').length === 0) {
                $(this).parents('.itemLine2').find('.itemText').eq(1).find('.blockExpandText').remove();
                $(this).parent().find('.blockExpandText').clone(true).insertAfter($(this).parents('.itemLine2').find('.itemText').eq(1).find('.less'));
            }
            $(this).parent().toggle();
            $(this).parents('.itemLine2').find('.itemText').eq(1).toggle();
            evalTemplateUtils.frameGrow(0);
            return false;
        });
        $(scope).find('.less').bind('click', function() {
            $(this).parent().toggle();
            $(this).parents('.itemLine2').find('.itemText').eq(0).toggle();
            return false;
        });
    };

    return {
        onDOMReady: _initDom,
        //modify_item.html view
        modify_item: function() {
            var siteId = $('#site-id').text();
            $.facebox.setHeader(evalTemplateUtils.pages.modify_item_page);
            if ($('.act .submit').attr('name').search(/templateBBean.saveTemplateItemToGroupAction/) !== -1) {
                //proper submit  skip validation - it is not important
            } else if ($('.act .submit').attr('name').search(/templateBBean.saveItemAction/) === -1) {
                $('.act .submit').bind('click', function() {
                    evalTemplateData.postFCKform('#item-form', 'item-text::input', 'modify_item', $(this));
                    return false;
                });
            }
        },
        //modify_block.html view
        modify_block: function(){
            _modify_block();
        },
        //modify_template.html view
        modify_template: function(){
            var title = "",
                description = "",
                 o = {
                    beforeSubmit: function() {
                        title = $('#basic-form input[name=title]').val();
                        description = $('#basic-form textarea[name=description]').val();
                        if (!title) {
                            alert( evalTemplateUtils.messageLocator("general.blank.required.field.user.message",
                                    evalTemplateUtils.messageLocator('modifytemplatetitledesc.title.header').toLowerCase())); //TODO: Make unobtrusive
                            return false;
                        }
                        $("#facebox .content").html('<img src="/library/image/sakai/spinner.gif"/>');
                    },
                    success: function() {
                        $('h3.viewNav > span#title').text(title);
                        $('span[id=description-switch::description]').text(description);
                        $(document).trigger('close.facebox');
                    }
                };
                $.facebox.setHeader(evalTemplateUtils.pages.modify_template_page);
                evalTemplateUtils.frameGrow(0);
                $('#basic-form').ajaxForm(o);
                $('input.cancelButtonLightbox').bind("click", function() {
                    $(document).trigger('close.facebox');
                });
        },
        //choose expert items view
        choose_expert_category: function(){
            $.facebox.setHeader(evalTemplateUtils.pages.choose_expert_page);
            $('a[rel*=facebox]').facebox();
        },
        //modify expert item view
        modify_expert_item: function(){
            $.facebox.setHeader(evalTemplateUtils.pages.modify_expert_item_page);
            $('a[rel*=facebox]').facebox();
        },
        //preview expert item view
        preview_expert_item: function(){
            $.facebox.setHeader(evalTemplateUtils.pages.preview_expert_item_page);
            $('a[rel*=facebox]').facebox();
        },
        //remove_expert_item view
        remove_expert_item: function(){
            $.facebox.setHeader(evalTemplateUtils.pages.remove_expert_item_page);
            $('a[rel*=facebox]').facebox();
        },
        preview_item: function(){
            evalsys.instrumentItems("#item_container");
            $.facebox.setHeader(evalTemplateUtils.pages.preview_item_page);
        },
        bindDeleteIcons : bindDeleteIcons,
        unBindDeleteIcons : unBindDeleteIcons,
        bindRowEditPreviewIcons : bindRowEditPreviewIcons,
        unBindRowEditPreviewIcons : unBindRowEditPreviewIcons,
        bindGroupParentTextControls : bindGroupParentTextControls,
        //functions for manipulating the blocks eg: clicking on 'create block items'
        block : {
            countCheckBox : function(){
                    //1)if total cout of checked checkbox > 2, enable "Create Block" button
                    //2) disable all boxes which are not using the same scale as the first one that is checked
                    //3)if no check box is checked, all the check box should be enabled
                    var checkBoxes_ALL = $("label.itemCheckbox input[type=checkbox]"),
                        checkBoxes_CHECKED = $("label.itemCheckbox input[type=checkbox]:checked"),
                        checkBoxes_ALL_array = checkBoxes_ALL.get(),
                        checkBoxes_CHECKED_array = checkBoxes_CHECKED.get(),
                        submitButton = document.getElementById("createBlockBtn"),
                        submitButtonBlock = document.getElementById("blockInputs");

                    var count_CheckBoxes_CHECKED = checkBoxes_CHECKED.length; //enforce at least 2 check box are checked

                    $(".itemLine2").removeAttr('style');
                    if (count_CheckBoxes_CHECKED > 0){
                        for (var a=0; a< checkBoxes_CHECKED_array.length;a++) {
                            var target = $(checkBoxes_CHECKED_array[a]),
                                targetId = target.attr('id');
                                target.parents(".itemLine2:eq(0)").attr('style', 'background-color:#FFFFCC;');
                            var scaleId = targetId.substring(targetId.indexOf('-')+1, targetId.lastIndexOf('-'));
                            //disable other check box which has different scale id
                             for(var b=0;b<checkBoxes_ALL_array.length;b++){
                                 var other = $(checkBoxes_ALL_array[b]),
                                    otherId = other.attr('id');
                                 if(other !== target){
                                    var otherScaleId = otherId.substring(otherId.indexOf('-')+1, otherId.lastIndexOf('-'));
                                    if(otherScaleId !== scaleId){
                                        other.attr("disabled", true);
                                        other.parents("label").addClass("notselectable");
                                    } else {
                                        other.attr("disabled", false);
                                        other.parents("label").addClass("selectable");
                                    }
                                 }
                             }
                        }
                    }

                    //alert("scaleId= "+scaleId);
                    if(count_CheckBoxes_CHECKED === 0){ //no check box is checked, enable all the checkboxes
                        checkBoxes_ALL.attr("disabled", false);
                        checkBoxes_ALL.parents("label").removeClass("selectable");
                        checkBoxes_ALL.parents("label").removeClass("notselectable");
                        submitButton.disabled = true;
                        submitButtonBlock.className="itemOperations";
                    }else if(count_CheckBoxes_CHECKED < 2){
                        //alert("select less than 2 items,disable submit button");
                        submitButton.disabled = true;
                        submitButtonBlock.className="itemOperations";
                    }else{
                        //alert("select 2 or more items,enable submit button");
                        submitButton.disabled = false;
                        submitButtonBlock.className="itemOperationsEnabled";
                    }
            },
            extractSelectedItems : function(e){
                var submitButton = this,
                    checkBoxes_CHECKED = $("label.itemCheckbox input[type=checkbox]:checked"),
                    checkBoxes_CHECKED_array = checkBoxes_CHECKED.get(),
                    destinationForm = submitButton.form;

                if (checkBoxes_CHECKED.length > 0 && destinationForm) {
                    var idList = [];
                    // look for checkboxes which have IDs of the form "block-12-11" and keep track of the ones that are checked.
                    for (var a in checkBoxes_CHECKED_array) {
                        var target = $(checkBoxes_CHECKED_array[a]),
                            targetId = target.attr('id'),
                            scaleId = targetId.substr(targetId.lastIndexOf('-')+1);
                            idList.push(scaleId);
                    }

                    destinationForm.templateItemIds.value=idList.toString();

                    if (checkBoxes_CHECKED.length < 2) {
                        alert(evalTemplateUtils.messageLocator('modifytemplate.group.warn.minimum'));
                         return false;
                    } else {
                        $(submitButton).parent().ajaxSubmit({
                            success: function(msg){
                                //Unbind current reveal event
                                $(document).unbind('reveal.facebox');
                                //Bind new reveal event
                                $(document).bind('reveal.facebox', function() {
                                    evalTemplateLoaderEvents.modify_block();
                                    $('#saveBlockAction')
                                            .unbind("click")
                                            .bind("click", function(){
                                                    var childIdList = [],
                                                    reuseBlockText = $('.blockText input[type=radio][checked][value!=new1]').length > 0;
                                                    $('#blockForm input[name*=hidden-item-id]').each(function(){
                                                        childIdList.push($(this).val());
                                                    });
                                                    $("#ordered-child-ids").val(childIdList.toString());
                                                    return true;
                                                });

                                });
                                $.facebox.setHeader(evalTemplateUtils.pages.modify_block_page);
                                evalTemplateUtils.frameScrollHeight = e.pageY;
                                evalTemplateUtils.frameGrow(0);
                                $.facebox(msg);
                            }
                        });
                        return false;
                    }
                }
                return false;
            }
        }
    };
})($);
<commit_msg>EVALSYS-1425 - Error grouping items in new template<commit_after>/*
 * Copyright 2005 Sakai Foundation Licensed under the
 * Educational Community 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.osedu.org/licenses/ECL-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.
 */

// Eval Template Modify JS for onload functions
// @author lovemore.nalube@uct.ac.za

var evalTemplateLoaderEvents = (function($) {
    var _initDom = function(){
        startSort();
        $(document).trigger('activateControls.templateItems');
        buildSortableIds();
    },

    _modify_block = function(){
                var siteId = $('#site-id').text();
        $.facebox.setHeader(evalTemplateUtils.pages.modify_block_page);

		var baseId = ""; // "blockPage::";

		$('#saveBlockAction').click(function() {
			var childIdList = [],
                reuseBlockText = $('.blockText input[type=radio][checked][value!=new1]').length > 0;
			$('#blockForm input[name*=hidden-item-id]').each(function(){
				childIdList.push($(this).val());
			});
			$("#ordered-child-ids").val(childIdList.toString());
            if (reuseBlockText){
			    evalTemplateData.postFCKform('#blockForm', false, 'modify_block', $('#saveBlockAction'));
                return false;
            }else{
                evalTemplateData.postFCKform('#blockForm', 'item-text::input', 'modify_block', $('#saveBlockAction'));
                return false;
            }
		});

		function disableOrderButtons() {
			$it(baseId + "revertOrderButton").disabled = true;
			$it(baseId + "saveReorderButton").disabled = true;
		}

        //var sortableIds;
        function buildSortableIds() {
            var sortableIds = [];
            var domList = $("div.itemList > div").get();
			for (var i = 0; i < domList.length; i++) {
				sortableIds.push(domList[i].id);
			}
		}

		var reorderButtonsExist = false;
		var saveReorderButton = $it(baseId + "saveReorderButton");

		if (saveReorderButton !== null) {
			reorderButtonsExist = true;
			saveReorderButton.onclick = function() {
				disableOrderButtons();
				buildSortableIds();
				$(saveReorderButton.form).ajaxSubmit();
				return false;
			};
		}

		function setIndex(itemId, newindex) {
			$it(itemId + "item-num").innerHTML = (parseInt(newindex, 10) + 1);
		}

		// put original order into the revertOrder trigger
		var revertOrderButton = $it(baseId + "revertOrderButton");
		if (revertOrderButton !== null) {
			revertOrderButton.onclick = function() {
				disableOrderButtons();
				for(var i = sortableIds.length - 1; i > 0; --i) {
					var thisitem = $it(sortableIds[i]);
					var previtem = $it(sortableIds[i - 1]);
					previtem.parentNode.removeChild(previtem);
					thisitem.parentNode.insertBefore(previtem, thisitem);
					setIndex(thisitem.id, i);
				}
				setIndex(sortableIds[0], 0);
			};
		}
    },

    bindDeleteIcons = function(row){
        var scope = (typeof row === 'undefined') ? document : row.get();
        $(scope).find('a[rel=remove]').itemRemove({
            ref:    'eval-templateitem',
            id:     'evalTemplateUtils.getTemplateItemId($(this))',
            text:   '$(this).parents("div.itemLine2").find("h4.itemText:visible").text()'
        });
        $(scope).find('a[rel=childRemove]').itemRemove({
                    ref:    'eval-templateitem',
                    id:        '$(this).parents("div.itemRowBlock").find("input[name=hidden-item-id]").val()',
                    itemType: 'blockChild',
                    text:   '$(this).parents("div.itemRowBlock").find("span.text").text()'
                });
        $(scope).find('a[rel=childUngroup]').itemRemove({
                    ref:    'eval-templateitem/unblock',
                    id:    '$(this).parents("div.itemRowBlock").find("input[name=hidden-item-id]").val()',
                    itemType: 'blockChild',
                    text:   '$(this).parents("div.itemRowBlock").find("span.text:visible").text()'
                });
        $(scope).find('a[rel=unblock]').itemRemove({
            ref:    'eval-templateitem',
            id:        'evalTemplateUtils.getTemplateItemId($(this))',
            itemType: 'block',
            text:   '$(this).parents("div.itemLine2").find("h4.itemText:visible").text()'
        });
    },

    unBindDeleteIcons = function(){
        $('a[rel=remove]').unbind("click");
        $('a[rel=childRemove]').unbind("click");
        $('a[rel=childUngroup]').unbind("click");
        $('a[rel=unblock]').unbind("click");
    },

    bindRowEditPreviewIcons = function(changedRow){
        if ( typeof changedRow === "undefined" || changedRow === null){
            $('a[rel=facebox]').facebox();
            $('a[rel=faceboxGrid]').faceboxGrid();
        }else{
            changedRow.find('a[rel=facebox]').facebox();
            changedRow.find('a[rel=faceboxGrid]').faceboxGrid();
        }
    },

    unBindRowEditPreviewIcons = function(changedRow){
        if ( typeof changedRow === "undefined" || changedRow === null){
            $('a[rel=facebox]').unbind("facebox");
            $('a[rel=faceboxGrid]').unbind("faceboxGrid");
        }else{
            changedRow.find('a[rel=facebox]').unbind("facebox");
            changedRow.find('a[rel=faceboxGrid]').unbind("faceboxGrid");
        }
    },
        /**
         * this will bind these controls in the main item of a group: hide/show item && more/less item
          */
    bindGroupParentTextControls = function(row){
        var scope = (typeof row === 'undefined') ? document : row.get();
        $(scope).find('.blockExpandText').toggle(
            function() {
                if ($(this).parents('.itemRow').find('.itemLine3').is(':hidden')) {
                    $(this).click();
                    return false;
                }
                var text = evalTemplateUtils.messageLocator('modifytemplate.group.show');
                $(this).parents('.itemRow').find('.itemLine3').slideToggle();
                $(this).text(text);
                // save closed state
                evalTemplateUtils.closedGroup.add( $(this).parents(".itemRow").attr('name') );
                return false;
            },
            function() {
                var text = evalTemplateUtils.messageLocator('modifytemplate.group.hide');
                $(this).parents('.itemRow').find('.itemLine3').slideToggle();
                $(this).text(text);
                // remove closed state
                evalTemplateUtils.closedGroup.remove( $(this).parents(".itemRow").attr('name') );
                return false;
            });
        $(scope).find('.more').bind('click', function() {
            if ($(this).parents('.itemLine2').find('.itemText').eq(1).find('.blockExpandText').length === 0) {
                $(this).parents('.itemLine2').find('.itemText').eq(1).find('.blockExpandText').remove();
                $(this).parent().find('.blockExpandText').clone(true).insertAfter($(this).parents('.itemLine2').find('.itemText').eq(1).find('.less'));
            }
            $(this).parent().toggle();
            $(this).parents('.itemLine2').find('.itemText').eq(1).toggle();
            evalTemplateUtils.frameGrow(0);
            return false;
        });
        $(scope).find('.less').bind('click', function() {
            $(this).parent().toggle();
            $(this).parents('.itemLine2').find('.itemText').eq(0).toggle();
            return false;
        });
    };

    return {
        onDOMReady: _initDom,
        //modify_item.html view
        modify_item: function() {
            var siteId = $('#site-id').text();
            $.facebox.setHeader(evalTemplateUtils.pages.modify_item_page);
            if ($('.act .submit').attr('name').search(/templateBBean.saveTemplateItemToGroupAction/) !== -1) {
                //proper submit  skip validation - it is not important
            } else if ($('.act .submit').attr('name').search(/templateBBean.saveItemAction/) === -1) {
                $('.act .submit').bind('click', function() {
                    evalTemplateData.postFCKform('#item-form', 'item-text::input', 'modify_item', $(this));
                    return false;
                });
            }
        },
        //modify_block.html view
        modify_block: function(){
            _modify_block();
        },
        //modify_template.html view
        modify_template: function(){
            var title = "",
                description = "",
                 o = {
                    beforeSubmit: function() {
                        title = $('#basic-form input[name=title]').val();
                        description = $('#basic-form textarea[name=description]').val();
                        if (!title) {
                            alert( evalTemplateUtils.messageLocator("general.blank.required.field.user.message",
                                    evalTemplateUtils.messageLocator('modifytemplatetitledesc.title.header').toLowerCase())); //TODO: Make unobtrusive
                            return false;
                        }
                        $("#facebox .content").html('<img src="/library/image/sakai/spinner.gif"/>');
                    },
                    success: function() {
                        $('h3.viewNav > span#title').text(title);
                        $('span[id=description-switch::description]').text(description);
                        $(document).trigger('close.facebox');
                    }
                };
                $.facebox.setHeader(evalTemplateUtils.pages.modify_template_page);
                evalTemplateUtils.frameGrow(0);
                $('#basic-form').ajaxForm(o);
                $('input.cancelButtonLightbox').bind("click", function() {
                    $(document).trigger('close.facebox');
                });
        },
        //choose expert items view
        choose_expert_category: function(){
            $.facebox.setHeader(evalTemplateUtils.pages.choose_expert_page);
            $('a[rel*=facebox]').facebox();
        },
        //modify expert item view
        modify_expert_item: function(){
            $.facebox.setHeader(evalTemplateUtils.pages.modify_expert_item_page);
            $('a[rel*=facebox]').facebox();
        },
        //preview expert item view
        preview_expert_item: function(){
            $.facebox.setHeader(evalTemplateUtils.pages.preview_expert_item_page);
            $('a[rel*=facebox]').facebox();
        },
        //remove_expert_item view
        remove_expert_item: function(){
            $.facebox.setHeader(evalTemplateUtils.pages.remove_expert_item_page);
            $('a[rel*=facebox]').facebox();
        },
        preview_item: function(){
            evalsys.instrumentItems("#item_container");
            $.facebox.setHeader(evalTemplateUtils.pages.preview_item_page);
        },
        bindDeleteIcons : bindDeleteIcons,
        unBindDeleteIcons : unBindDeleteIcons,
        bindRowEditPreviewIcons : bindRowEditPreviewIcons,
        unBindRowEditPreviewIcons : unBindRowEditPreviewIcons,
        bindGroupParentTextControls : bindGroupParentTextControls,
        //functions for manipulating the blocks eg: clicking on 'create block items'
        block : {
            countCheckBox : function(){
                    //1)if total cout of checked checkbox > 2, enable "Create Block" button
                    //2) disable all boxes which are not using the same scale as the first one that is checked
                    //3)if no check box is checked, all the check box should be enabled
                    var checkBoxes_ALL = $("label.itemCheckbox input[type=checkbox]"),
                        checkBoxes_CHECKED = $("label.itemCheckbox input[type=checkbox]:checked"),
                        checkBoxes_ALL_array = checkBoxes_ALL.get(),
                        checkBoxes_CHECKED_array = checkBoxes_CHECKED.get(),
                        submitButton = document.getElementById("createBlockBtn"),
                        submitButtonBlock = document.getElementById("blockInputs");

                    var count_CheckBoxes_CHECKED = checkBoxes_CHECKED.length; //enforce at least 2 check box are checked

                    $(".itemLine2").removeAttr('style');
                    if (count_CheckBoxes_CHECKED > 0){
                        for (var a=0; a< checkBoxes_CHECKED_array.length;a++) {
                            var target = $(checkBoxes_CHECKED_array[a]),
                                targetId = target.attr('id');
                                target.parents(".itemLine2:eq(0)").attr('style', 'background-color:#FFFFCC;');
                            var scaleId = targetId.substring(targetId.indexOf('-')+1, targetId.lastIndexOf('-'));
                            //disable other check box which has different scale id
                             for(var b=0;b<checkBoxes_ALL_array.length;b++){
                                 var other = $(checkBoxes_ALL_array[b]),
                                    otherId = other.attr('id');
                                 if(other !== target){
                                    var otherScaleId = otherId.substring(otherId.indexOf('-')+1, otherId.lastIndexOf('-'));
                                    if(otherScaleId !== scaleId){
                                        other.attr("disabled", true);
                                        other.parents("label").addClass("notselectable");
                                    } else {
                                        other.attr("disabled", false);
                                        other.parents("label").addClass("selectable");
                                    }
                                 }
                             }
                        }
                    }

                    //alert("scaleId= "+scaleId);
                    if(count_CheckBoxes_CHECKED === 0){ //no check box is checked, enable all the checkboxes
                        checkBoxes_ALL.attr("disabled", false);
                        checkBoxes_ALL.parents("label").removeClass("selectable");
                        checkBoxes_ALL.parents("label").removeClass("notselectable");
                        submitButton.disabled = true;
                        submitButtonBlock.className="itemOperations";
                    }else if(count_CheckBoxes_CHECKED < 2){
                        //alert("select less than 2 items,disable submit button");
                        submitButton.disabled = true;
                        submitButtonBlock.className="itemOperations";
                    }else{
                        //alert("select 2 or more items,enable submit button");
                        submitButton.disabled = false;
                        submitButtonBlock.className="itemOperationsEnabled";
                    }
            },
            extractSelectedItems : function(e){
                var submitButton = this,
                    checkBoxes_CHECKED = $("label.itemCheckbox input[type=checkbox]:checked"),
                    checkBoxes_CHECKED_array = checkBoxes_CHECKED.get(),
                    destinationForm = submitButton.form;

                if (checkBoxes_CHECKED.length > 0 && destinationForm) {
                    var idList = [];
                    // look for checkboxes which have IDs of the form "block-12-11" and keep track of the ones that are checked.
                    for (var a=0;a<checkBoxes_CHECKED_array.length;a++) {
                        var target = $(checkBoxes_CHECKED_array[a]),
                            targetId = target.attr('id'),
                            scaleId = targetId.substr(targetId.lastIndexOf('-')+1);
                            idList.push(scaleId);
                    }

                    destinationForm.templateItemIds.value=idList.toString();

                    if (checkBoxes_CHECKED.length < 2) {
                        alert(evalTemplateUtils.messageLocator('modifytemplate.group.warn.minimum'));
                         return false;
                    } else {
                        $(submitButton).parent().ajaxSubmit({
                            success: function(msg){
                                //Unbind current reveal event
                                $(document).unbind('reveal.facebox');
                                //Bind new reveal event
                                $(document).bind('reveal.facebox', function() {
                                    evalTemplateLoaderEvents.modify_block();
                                    $('#saveBlockAction')
                                            .unbind("click")
                                            .bind("click", function(){
                                                    var childIdList = [],
                                                    reuseBlockText = $('.blockText input[type=radio][checked][value!=new1]').length > 0;
                                                    $('#blockForm input[name*=hidden-item-id]').each(function(){
                                                        childIdList.push($(this).val());
                                                    });
                                                    $("#ordered-child-ids").val(childIdList.toString());
                                                    return true;
                                                });

                                });
                                $.facebox.setHeader(evalTemplateUtils.pages.modify_block_page);
                                evalTemplateUtils.frameScrollHeight = e.pageY;
                                evalTemplateUtils.frameGrow(0);
                                $.facebox(msg);
                            }
                        });
                        return false;
                    }
                }
                return false;
            }
        }
    };
})($);
<|endoftext|>


<commit_before>const webpack = require('webpack')

module.exports = {
  entry: 'mocha!./test/bootstrap.js',
  output: {
    path: './test',
    filename: 'specs.js',
    publicPath: 'http://localhost:8080/'
  },
  module: {
    loaders: [{
      test: /\.js$/,
      //exclude: /(dist|.git|node_modules)/,
      loader: 'babel-loader'
    }]
  },
  devServer: {
    contentBase: './test',
    port: 8080,
    noInfo: true,
	hot: true,
    inline: true
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin()
  ]
}
<commit_msg>version bump<commit_after>const webpack = require('webpack')

module.exports = {
  entry: 'mocha!./test/bootstrap.js',
  output: {
    path: './test',
    filename: 'specs.js',
    publicPath: 'http://localhost:8080/'
  },
  module: {
    loaders: [{
      test: /\.js$/,
      exclude: /(dist|.git)/,
      loader: 'babel-loader'
    }]
  },
  devServer: {
    contentBase: './test',
    port: 8080,
    noInfo: true,
	hot: true,
    inline: true
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin()
  ]
}
<|endoftext|>


<commit_before>var Our = Our || {};
Our.Umbraco = Our.Umbraco || {};
Our.Umbraco.uGoLive = Our.Umbraco.uGoLive || {};

(function ($) {

    Our.Umbraco.uGoLive.Dashboard = (function() {

        var checks = [];
        var currentCheckIndex = -1;
		var basePath = "/base";
		var umbracoPath = "/umbraco";

        function performNextCheck() {
            var checkId = checks[currentCheckIndex];
            performCheck(checkId, function(data) {
				// Re-enable the check button
				$("a.check[data-check-id=" + checkId + "]").removeClass("disabled");
				// Trigger next check, or finish
                if(currentCheckIndex + 1 == checks.length) {
                    // Re-enable the "Run All Checks" button
                    var $btn = $("#btnRunChecks");
                    $btn.text("Re-Run All Checks");
                    $btn.removeClass("disabled");
                    $("a.check").removeAttr("disabled");
                } else {
                    // Run the next check
                    currentCheckIndex++;
                    performNextCheck();
                }
            });
        }

        function performCheck(checkId, callBack) {
            $("span.status[data-check-id=" + checkId + "]").html(" Checking...");
            $.getJSON(basePath + '/uGoLive/Check/'+ checkId +'.aspx', function(data) {

                var $checkEl = $("span.status[data-check-id=" + checkId + "]");

                $checkEl.empty();

                switch(data.Status.Value) {
                    case "Passed":
                        $checkEl.append("");
                        $("a.rectify[data-check-id=" + checkId + "][data-check-can-rectify='true']").addClass("disabled");
                        break;
                    case "Indeterminate":
                        $checkEl.append("");
                        $("a.rectify[data-check-id=" + checkId + "][data-check-can-rectify='true']").removeClass("disabled");
                        break;
                    case "Failed":
                        $checkEl.append("");
                        $("a.rectify[data-check-id=" + checkId + "][data-check-can-rectify='true']").removeClass("disabled");
                        break;
                }

                if($.trim(data.Message) != "")
                    $checkEl.append(data.Message);

                if(callBack != undefined)
                    callBack(data);
            });
        }

        function performRectify(checkId, callBack) {
            $("span.status[data-check-id=" + checkId + "]").html(" Rectifying...");
            $.getJSON(basePath + '/uGoLive/Rectify/'+ checkId +'.aspx', function(data) {

                var $checkEl = $("span.status[data-check-id=" + checkId + "]");

                $checkEl.empty();

                switch(data.Status.Value) {
                    case "Success":
                        $checkEl.append("");
                        $("a.rectify[data-check-id=" + checkId + "][data-check-can-rectify='true']").addClass("disabled");
                        break;
                    case "Failed":
                        $checkEl.append("");
                        $("a.rectify[data-check-id=" + checkId + "][data-check-can-rectify='true']").removeClass("disabled");
                        break;
                }

                if($.trim(data.Message) != "")
                    $checkEl.append(data.Message);

                if(callBack != undefined)
                    callBack(data);
            });
        }

        return {

            init: function (o) {

				// Set the paths
				if (typeof(o.umbracoPath) != 'undefined')
					umbracoPath = o.umbracoPath;
				if (typeof(o.basePath) != 'undefined')
					basePath = o.basePath;

                // Parse all checks
                $("span.status").each(function (idx, el)
                {
                    checks.push($(el).attr("data-check-id"));
                });

                // Hookup run all check button
                $("#btnRunChecks").click(function(e) {

                    e.preventDefault();

                    var $this = $(this);

                    if(!$this.hasClass("disabled")) {

                        // Clear out previous checks
                        $("span.status").empty();

                        // Update buttons
                        $this.text("Running checks...");
                        $this.addClass("disabled");
                        $("a.check").addClass("disabled");
                        $("a.rectify").addClass("disabled");

                        // Start checks
                        currentCheckIndex = 0;
                        performNextCheck();

                    }
                });

                // Hookup individual check buttons
                $("a.check").click(function(e) {

                    e.preventDefault();

                    var $this = $(this);

                    if(!$this.hasClass("disabled")) {

                        $this.addClass("disabled");
                        var checkId = $this.attr("data-check-id");
                        $("a.rectify[data-check-id="+ checkId +"]").addClass("disabled");
                        performCheck(checkId, function(data) {
                            $this.removeClass("disabled");
                        });

                    }
                });

                // Hookup individual rectify buttons
                $("a.rectify").click(function(e) {

                    e.preventDefault();

                    var $this = $(this);

                    if(!$this.hasClass("disabled")) {

                        $this.addClass("disabled");
                        var checkId = $this.attr("data-check-id");
                        performRectify(checkId, function(data) {
                            //$this.removeAttr("disabled");
                        });

                    }
                });
            }

        };

    })();

})(jQuery)<commit_msg>Updated uGoLive js script to latest<commit_after>var Our = Our || {};
Our.Umbraco = Our.Umbraco || {};
Our.Umbraco.uGoLive = Our.Umbraco.uGoLive || {};

(function ($) {

    Our.Umbraco.uGoLive.Dashboard = (function() {

        var checks = [];
        var currentCheckIndex = -1;
		var opts = {
			basePath: "/base",
			umbracoPath: "/umbraco"
		};

        function performNextCheck() {

			// Get the current check id
            var checkId = checks[currentCheckIndex];

			// Trigger check
            performCheck(checkId, function(data) {

				// Trigger next check, or finish
                if(currentCheckIndex + 1 == checks.length) {

                    // Re-enable the "Run All Checks" button
                    var $btn = $("#btnRunChecks");
                    $btn.text("Re-Run All Checks");
                    $btn.removeClass("disabled");

                } else {

                    // Run the next check
                    currentCheckIndex++;
                    performNextCheck();

                }
            });
        }

        function performCheck(checkId, callBack) {

			// Get references
			var $checkEl = $("span.status[data-check-id=" + checkId + "]");
			var $checkButton = $("a.check[data-check-id=" + checkId + "]");
			var $rectifyButton = $("a.rectify[data-check-id=" + checkId + "][data-check-can-rectify='true']");

			// Disable buttons
			$checkButton.addClass("disabled");
			$rectifyButton.addClass("disabled");

			// Display throbber
            $checkEl.html(" Checking...");

			// Perform check
			$.getJSON(opts.basePath + '/uGoLive/Check/'+ checkId +'.aspx', function(data) {

				// Remove throbber
                $checkEl.empty();

				// Display icon & enable / disable rectify button
                switch(data.Status.Value) {
                    case "Passed":
                        $checkEl.append("");
                        $rectifyButton.addClass("disabled");
                        break;
                    case "Indeterminate":
                        $checkEl.append("");
                        $rectifyButton.removeClass("disabled");
                        break;
                    case "Failed":
                        $checkEl.append("");
                        $rectifyButton.removeClass("disabled");
                        break;
                }

				// Display message
                if($.trim(data.Message) != "")
                    $checkEl.append(data.Message);

				// Re-enable check button
				$checkButton.removeClass("disabled");

				// Execute callback
                if(callBack != undefined)
                    callBack(data);
            });
        }

        function performRectify(checkId, callBack) {

			// Get references
			var $checkEl = $("span.status[data-check-id=" + checkId + "]");
			var $checkButton = $("a.check[data-check-id=" + checkId + "]");
			var $rectifyButton = $("a.rectify[data-check-id=" + checkId + "][data-check-can-rectify='true']");

			// Disable buttons
			$checkButton.addClass("disabled");
			$rectifyButton.addClass("disabled");

			// Display throbber
            $checkEl.html(" Rectifying...");

			// Perform rectify
			$.getJSON(opts.basePath + '/uGoLive/Rectify/'+ checkId +'.aspx', function(data) {

				// Remove throbber
                $checkEl.empty();

				// Display icon & enable / disable rectify button
                switch(data.Status.Value) {
                    case "Success":
                        $checkEl.append("");
                        $rectifyButton.addClass("disabled");
                        break;
                    case "Failed":
                        $checkEl.append("");
                        $rectifyButton.removeClass("disabled");
                        break;
                }

				// Display message
                if($.trim(data.Message) != "")
                    $checkEl.append(data.Message);

				// Re-enable check button
				$checkButton.removeClass("disabled");

				// Execute callback
                if(callBack != undefined)
                    callBack(data);
            });
        }

        return {

            init: function (o) {

				// Merge options
				opts = $.extend(opts, o);

                // Parse all checks
                $("span.status").each(function (idx, el) {
                    checks.push($(el).attr("data-check-id"));
                });

                // Hookup run all check button
                $("#btnRunChecks").click(function(e) {

                    e.preventDefault();

                    var $this = $(this);

                    if(!$this.hasClass("disabled")) {

                        // Clear out previous checks
                        $("span.status").empty();

						// Disable check/rectify buttons
                        $("a.check").addClass("disabled");
                        $("a.rectify").addClass("disabled");

                        // Update run checks button
                        $this.text("Running checks...");
                        $this.addClass("disabled");

                        // Start checks
                        currentCheckIndex = 0;
                        performNextCheck();

                    }
                });

                // Hookup individual check buttons
                $("a.check").click(function(e) {

                    e.preventDefault();

                    var $this = $(this);

                    if(!$this.hasClass("disabled")) {
                        performCheck($this.attr("data-check-id"));
                    }
                });

                // Hookup individual rectify buttons
                $("a.rectify").click(function(e) {

                    e.preventDefault();

                    var $this = $(this);

                    if(!$this.hasClass("disabled")) {
                        performRectify($this.attr("data-check-id"));
                    }
                });
            }

        };

    })();

})(jQuery)<|endoftext|>


<commit_before>var D4H_STRING = "D4H";
var YNL_STRING = "Y / N / L";

var BRIGHT_GREEN = "#48FF05";

/**
 * @OnlyCurrentDoc  Limits the script to only accessing the current spreadsheet.
 */

var TOKEN_DIALOG_TITLE = 'Set D4H API Token';
var SIDEBAR_TITLE = 'Example Sidebar';

function test() {
  var t = 2130;
  String(t).trim();
}

function getToken() {
  var token = PropertiesService.getUserProperties().getProperty("D4H_TOKEN");
  Logger.log("D4H token: " + token);
  return token;
}

/* Saves the specified token to the user's properties */
function saveToken(token) {
  PropertiesService.getUserProperties().setProperty("D4H_TOKEN", token);
}

/* Checks the responses anytime the sheet is edited and makes appropriate
 * formatting changes
 *
 * Specifically:
 * - Checks the "Responding" string and sets the background color accordingly
 */
function checkResponse(e) {
  var sheet = SpreadsheetApp.getActiveSheet();

  /* checks response, if Y, turns cell green */
  /* Andy: I tried changing only those fields that
   * come in as part of e.range and it's not stable
   * Not sure what the problem is so just looping for now
   * There was no noticeable speed increase changing only
   * e.range
   */
  var range = sheet.getRange("D3:J100");
  for (var i=1; i<range.getNumRows(); i++) {
    var cell = range.getCell(i, 1);
    var respondingValue = cell.getValue().trim().toUpperCase();
    // sets it to green if Y
    if (respondingValue == "Y") {
      cell.setBackground(BRIGHT_GREEN);

      var homeSafe = range.getCell(i, 7);
      if (String(homeSafe.getValue()).trim() != "") {
        homeSafe.setBackground("white");
      }
      else {
        homeSafe.setBackground("orange");
      }
    }
    else if (respondingValue == "N") {
      cell.setBackground("red");
    }
    // in case we set it back to D4H
    else if (respondingValue == D4H_STRING) {
      cell.setBackground("red");
    }
    else {
      cell.setBackground("white");
    }
    // sets everything to upper case
    cell.setValue(respondingValue);
  }
}

/* Sets up the a trigger to call checkResponse() on any
 * edits of the sheet
 *
 * Not the most efficient but there shouldn't be much
 * editing except for the "responding" column
 */
function setupCheckResponseTrigger() {
  // debugging to see how many triggers are registered
  var triggers = ScriptApp.getProjectTriggers();
  Logger.log("---> Num registered triggers: " + triggers.length);

  for (var i=0; i<triggers.length; i++) {
    var t = triggers[i];
    Logger.log("type(t)----->" + typeof t);
    ScriptApp.deleteTrigger(t);
  }

  /* Can't seem to register non-time-driven triggers in UI so
   * adding programmatically.  But, don't need this anymore
   * once the trigger has been added
   */
  ScriptApp.newTrigger("checkResponse")
    .forSpreadsheet(SpreadsheetApp.getActive())
    .onEdit()
    .create()
}

/**
 * Adds a custom menu with items to show the sidebar and dialog.
 *
 * @param {Object} e The event parameter for a simple onOpen trigger.
 */
function onOpen(e) {
  SpreadsheetApp.getUi()
      .createAddonMenu()
      .addItem("Populate Call Sheet", 'populateAllCall')
      .addItem("Set D4H Token", "showTokenDialog")
      //.addItem('Show sidebar', 'showSidebar')
      .addToUi();
}

/* Takes a person dictionary and phonetype key
 * If phonetype isn't defined, returns the emptry string
 * Otherwise, returns a formatted phone number, dropping the
 * leading 1 if present
 */
function phoneFormat(person, phonetype) {
  if (phonetype in person) {
    phone = person[phonetype];
    if (phone.length == 10) {
      return "(" + phone.slice(0,3) + ") " + phone.slice(2,5) + "-" + phone.slice(5,9);
    }
    else if (phone.length == 11) {
      // currently removes the first character which is a '1'
      return "(" + phone.slice(1,4) + ") " + phone.slice(3,6) + "-" + phone.slice(6,10);
    }
    return person[phonetype];
  }
  else {
    return "";
  }
}

/* Returns a string of the provided date as YYYY-MM-DD */
function dateString(date) {
  var day = date.getDate();
  if (day < 10) {
    day = "0" + day;
  }
  var month = date.getMonth() + 1;
  if (month < 10) {
    month = "0" + month;
  }
  return date.getFullYear() + "-" + month + "-" + day;
}

/* Takes the list of person dictionaries and populates the
 * spreadsheet
 *
 * This function does the bulk of the work in creating
 * the spreadsheet
 */
function populateAllCall() {
  // remove this function call if trying to test add-on without
  // deploying it since it uses functionality that is not supported
  // in test mode
  setupCheckResponseTrigger();

  var all_call = getAllCall();
  var spreadsheet = SpreadsheetApp.getActive();
  var sheet = SpreadsheetApp.getActiveSheet();

  // names the spreadsheet "SMCSAR YYYY-MM-DD "
  var today = new Date();
  var spreadsheetName = "SMCSAR " + dateString(today) + " ";
  spreadsheet.rename(spreadsheetName);

  // perhaps we want to remove this since users should be
  // starting with a clean spreadsheet... may consider
  // displaying an error if it's not an empty sheet
  sheet.clear();

  // sets up the counting of available responders
  sheet.appendRow([
    "",
    "",
    "Available:",
    "=COUNTIF(D2:D,\"Y\")"
  ]);
  sheet.getRange("C1:D1").setBackground(BRIGHT_GREEN);

  // sets up header row
  sheet.appendRow([
    "Name",
    "Position",
    "Badge",
    "Responding",
    "Marshall or DR",
    "ETA ",
    "Time In",
    "Time Out",
    "Role ",
    "Home Safe",
    "Email",
    "Home Phone",
    "Mobile Phone",
    "Work Phone"
  ]);

  // bolds the first two rows
  sheet.getRange("A1:Z2").setFontWeight("bold");

  var currentRow = 3; // ignore header and count row

  // cycles through everyone and appends a new row for each
  for (var i=0; i<all_call.length; i++) {
    var person = all_call[i];
    sheet.appendRow([
      person.name,
      person.position,
      person.ref,
      person.responding,
      "", // marshall/dr
      "", // eta
      "", // time in
      "", // time out
      "", // role
      "", // home safe
      person.email,
      phoneFormat(person, "homephone"),
      phoneFormat(person, "mobilephone"),
      phoneFormat(person, "workphone")
    ]);

    // sets those off call in D4H to red
    if (person.responding == D4H_STRING) {
       sheet.getRange(currentRow, 4).setBackground("red");
    }
    currentRow++;
  }

  // Resizes all columns A-Z
  for (var i=1; i<27; i++) {
  sheet.autoResizeColumn(i);
  }
}

/* performs REST API call to D4H */
function getMembers(on_call, offset, limit) {
  // sets up arguments per D4H docs
  on_call = typeof on_call !== 'undefined' ? on_call : "off";
  offset = typeof offset !== 'undefined' ? offset : 0;
  limit = typeof limit !== 'undefined' ? limit : 25;

  var url = Utilities.formatString('https://api.d4h.org:443/v2/team/members?'
    + 'access_token=%s'
    + '&on_call=%s'
    + '&offset=%s'
    + '&limit=%s', getToken(), on_call, offset, limit);

  var response = UrlFetchApp.fetch(url);
  //Logger.log(response);

  // Returns JSON without any explicit processing
  return JSON.parse(response.getContentText());
}

/* Returns true if the person is operational */
function isOperational(person) {
  return person.status.id == 1
}

/* Repeatedly invokes getMembers() to handle paging
 * since D4H limits to 25 members per call
 */
function getRoster(on_off) {
  var all_people = [];
  var offset = 0;
  var limit = 25;
  var people = null;
  do {
    var response = getMembers(on_off, offset, limit);
    var data = response.data;

    // map over people to trim names since some have
    // spurious whitespace
    people = data.map(function (e) {
      e.name = e.name.trim();
      return e;
    });

    // building the overall list of people
    all_people = all_people.concat(people);
    offset += limit;
  } while (people.length == 25); // if we got 25 responses, repeat

  return all_people;
}

/* Gets on-call and off-call separately then combines them
 * and sorts by name
 */
function getAllCall() {
  var on_call = getRoster("on").map(function(person) {
    person.responding = YNL_STRING;
    return person;
  });
  var off_call = getRoster("off").map(function(person) {
    person.responding = D4H_STRING;
    return person
  });

  var everyone = on_call.concat(off_call).filter(isOperational);

  everyone = everyone.sort(function (left, right) {
    return left.name.localeCompare(right.name);
  });

  return everyone;
}

/**
 ** EVERYTHING BELOW HERE WAS AUTOGENERATED WITH THE NEW PROJECT
 **/

/**
 * Runs when the add-on is installed; calls onOpen() to ensure menu creation and
 * any other initializion work is done immediately.
 *
 * @param {Object} e The event parameter for a simple onInstall trigger.
 */
function onInstall(e) {
  onOpen(e);
}

/**
 * Opens a sidebar. The sidebar structure is described in the Sidebar.html
 * project file.
 */
function showSidebar() {
  var ui = HtmlService.createTemplateFromFile('Sidebar')
      .evaluate()
      .setTitle(SIDEBAR_TITLE);
  SpreadsheetApp.getUi().showSidebar(ui);
}

/**
 * Opens a dialog to set the D4H API Token. The dialog structure is described in
 * the TokenDialog.html project file.
 */
function showTokenDialog() {
  var ui = HtmlService.createTemplateFromFile('TokenDialog')
      .evaluate()
      .setWidth(400)
      .setHeight(190);
  SpreadsheetApp.getUi().showModalDialog(ui, TOKEN_DIALOG_TITLE);
}

/**
 * Returns the value in the active cell.
 *
 * @return {String} The value of the active cell.
 */
function getActiveValue() {
  // Retrieve and return the information requested by the sidebar.
  var cell = SpreadsheetApp.getActiveSheet().getActiveCell();
  return cell.getValue();
}

/**
 * Replaces the active cell value with the given value.
 *
 * @param {Number} value A reference number to replace with.
 */
function setActiveValue(value) {
  // Use data collected from sidebar to manipulate the sheet.
  var cell = SpreadsheetApp.getActiveSheet().getActiveCell();
  cell.setValue(value);
}

/**
 * Executes the specified action (create a new sheet, copy the active sheet, or
 * clear the current sheet).
 *
 * @param {String} action An identifier for the action to take.
 */
function modifySheets(action) {
  // Use data collected from dialog to manipulate the spreadsheet.
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var currentSheet = ss.getActiveSheet();
  if (action == "create") {
    ss.insertSheet();
  } else if (action == "copy") {
    currentSheet.copyTo(ss);
  } else if (action == "clear") {
    currentSheet.clear();
  }
}

<commit_msg>Fix #6 - invalid phone numbers<commit_after>var D4H_STRING = "D4H";
var YNL_STRING = "Y / N / L";

var BRIGHT_GREEN = "#48FF05";

/**
 * @OnlyCurrentDoc  Limits the script to only accessing the current spreadsheet.
 */

var TOKEN_DIALOG_TITLE = 'Set D4H API Token';
var SIDEBAR_TITLE = 'Example Sidebar';

function test() {
  var t = 2130;
  String(t).trim();
}

function getToken() {
  var token = PropertiesService.getUserProperties().getProperty("D4H_TOKEN");
  Logger.log("D4H token: " + token);
  return token;
}

/* Saves the specified token to the user's properties */
function saveToken(token) {
  PropertiesService.getUserProperties().setProperty("D4H_TOKEN", token);
}

/* Checks the responses anytime the sheet is edited and makes appropriate
 * formatting changes
 *
 * Specifically:
 * - Checks the "Responding" string and sets the background color accordingly
 */
function checkResponse(e) {
  var sheet = SpreadsheetApp.getActiveSheet();

  /* checks response, if Y, turns cell green */
  /* Andy: I tried changing only those fields that
   * come in as part of e.range and it's not stable
   * Not sure what the problem is so just looping for now
   * There was no noticeable speed increase changing only
   * e.range
   */
  var range = sheet.getRange("D3:J100");
  for (var i=1; i<range.getNumRows(); i++) {
    var cell = range.getCell(i, 1);
    var respondingValue = cell.getValue().trim().toUpperCase();
    // sets it to green if Y
    if (respondingValue == "Y") {
      cell.setBackground(BRIGHT_GREEN);

      var homeSafe = range.getCell(i, 7);
      if (String(homeSafe.getValue()).trim() != "") {
        homeSafe.setBackground("white");
      }
      else {
        homeSafe.setBackground("orange");
      }
    }
    else if (respondingValue == "N") {
      cell.setBackground("red");
    }
    // in case we set it back to D4H
    else if (respondingValue == D4H_STRING) {
      cell.setBackground("red");
    }
    else {
      cell.setBackground("white");
    }
    // sets everything to upper case
    cell.setValue(respondingValue);
  }
}

/* Sets up the a trigger to call checkResponse() on any
 * edits of the sheet
 *
 * Not the most efficient but there shouldn't be much
 * editing except for the "responding" column
 */
function setupCheckResponseTrigger() {
  // debugging to see how many triggers are registered
  var triggers = ScriptApp.getProjectTriggers();
  Logger.log("---> Num registered triggers: " + triggers.length);

  for (var i=0; i<triggers.length; i++) {
    var t = triggers[i];
    Logger.log("type(t)----->" + typeof t);
    ScriptApp.deleteTrigger(t);
  }

  /* Can't seem to register non-time-driven triggers in UI so
   * adding programmatically.  But, don't need this anymore
   * once the trigger has been added
   */
  ScriptApp.newTrigger("checkResponse")
    .forSpreadsheet(SpreadsheetApp.getActive())
    .onEdit()
    .create()
}

/**
 * Adds a custom menu with items to show the sidebar and dialog.
 *
 * @param {Object} e The event parameter for a simple onOpen trigger.
 */
function onOpen(e) {
  SpreadsheetApp.getUi()
      .createAddonMenu()
      .addItem("Populate Call Sheet", 'populateAllCall')
      .addItem("Set D4H Token", "showTokenDialog")
      //.addItem('Show sidebar', 'showSidebar')
      .addToUi();
}

/* Takes a person dictionary and phonetype key
 * If phonetype isn't defined, returns the emptry string
 * Otherwise, returns a formatted phone number, dropping the
 * leading 1 if present
 */
function phoneFormat(person, phonetype) {
  if (phonetype in person) {
    phone = person[phonetype];
    if (phone.length == 10) {
      return "(" + phone.slice(0,3) + ") " + phone.slice(3,6) + "-" + phone.slice(6,10);
    }
    else if (phone.length == 11) {
      // currently removes the first character which is a '1'
      return "(" + phone.slice(1,4) + ") " + phone.slice(4,7) + "-" + phone.slice(7,11);
    }
    return person[phonetype];
  }
  else {
    return "";
  }
}

/* Returns a string of the provided date as YYYY-MM-DD */
function dateString(date) {
  var day = date.getDate();
  if (day < 10) {
    day = "0" + day;
  }
  var month = date.getMonth() + 1;
  if (month < 10) {
    month = "0" + month;
  }
  return date.getFullYear() + "-" + month + "-" + day;
}

/* Takes the list of person dictionaries and populates the
 * spreadsheet
 *
 * This function does the bulk of the work in creating
 * the spreadsheet
 */
function populateAllCall() {
  // remove this function call if trying to test add-on without
  // deploying it since it uses functionality that is not supported
  // in test mode
  setupCheckResponseTrigger();

  var all_call = getAllCall();
  var spreadsheet = SpreadsheetApp.getActive();
  var sheet = SpreadsheetApp.getActiveSheet();

  // names the spreadsheet "SMCSAR YYYY-MM-DD "
  var today = new Date();
  var spreadsheetName = "SMCSAR " + dateString(today) + " ";
  spreadsheet.rename(spreadsheetName);

  // perhaps we want to remove this since users should be
  // starting with a clean spreadsheet... may consider
  // displaying an error if it's not an empty sheet
  sheet.clear();

  // sets up the counting of available responders
  sheet.appendRow([
    "",
    "",
    "Available:",
    "=COUNTIF(D2:D,\"Y\")"
  ]);
  sheet.getRange("C1:D1").setBackground(BRIGHT_GREEN);

  // sets up header row
  sheet.appendRow([
    "Name",
    "Position",
    "Badge",
    "Responding",
    "Marshall or DR",
    "ETA ",
    "Time In",
    "Time Out",
    "Role ",
    "Home Safe",
    "Email",
    "Home Phone",
    "Mobile Phone",
    "Work Phone"
  ]);

  // bolds the first two rows
  sheet.getRange("A1:Z2").setFontWeight("bold");

  var currentRow = 3; // ignore header and count row

  // cycles through everyone and appends a new row for each
  for (var i=0; i<all_call.length; i++) {
    var person = all_call[i];
    sheet.appendRow([
      person.name,
      person.position,
      person.ref,
      person.responding,
      "", // marshall/dr
      "", // eta
      "", // time in
      "", // time out
      "", // role
      "", // home safe
      person.email,
      phoneFormat(person, "homephone"),
      phoneFormat(person, "mobilephone"),
      phoneFormat(person, "workphone")
    ]);

    // sets those off call in D4H to red
    if (person.responding == D4H_STRING) {
       sheet.getRange(currentRow, 4).setBackground("red");
    }
    currentRow++;
  }

  // Resizes all columns A-Z
  for (var i=1; i<27; i++) {
  sheet.autoResizeColumn(i);
  }
}

/* performs REST API call to D4H */
function getMembers(on_call, offset, limit) {
  // sets up arguments per D4H docs
  on_call = typeof on_call !== 'undefined' ? on_call : "off";
  offset = typeof offset !== 'undefined' ? offset : 0;
  limit = typeof limit !== 'undefined' ? limit : 25;

  var url = Utilities.formatString('https://api.d4h.org:443/v2/team/members?'
    + 'access_token=%s'
    + '&on_call=%s'
    + '&offset=%s'
    + '&limit=%s', getToken(), on_call, offset, limit);

  var response = UrlFetchApp.fetch(url);
  //Logger.log(response);

  // Returns JSON without any explicit processing
  return JSON.parse(response.getContentText());
}

/* Returns true if the person is operational */
function isOperational(person) {
  return person.status.id == 1
}

/* Repeatedly invokes getMembers() to handle paging
 * since D4H limits to 25 members per call
 */
function getRoster(on_off) {
  var all_people = [];
  var offset = 0;
  var limit = 25;
  var people = null;
  do {
    var response = getMembers(on_off, offset, limit);
    var data = response.data;

    // map over people to trim names since some have
    // spurious whitespace
    people = data.map(function (e) {
      e.name = e.name.trim();
      return e;
    });

    // building the overall list of people
    all_people = all_people.concat(people);
    offset += limit;
  } while (people.length == 25); // if we got 25 responses, repeat

  return all_people;
}

/* Gets on-call and off-call separately then combines them
 * and sorts by name
 */
function getAllCall() {
  var on_call = getRoster("on").map(function(person) {
    person.responding = YNL_STRING;
    return person;
  });
  var off_call = getRoster("off").map(function(person) {
    person.responding = D4H_STRING;
    return person
  });

  var everyone = on_call.concat(off_call).filter(isOperational);

  everyone = everyone.sort(function (left, right) {
    return left.name.localeCompare(right.name);
  });

  return everyone;
}

/**
 ** EVERYTHING BELOW HERE WAS AUTOGENERATED WITH THE NEW PROJECT
 **/

/**
 * Runs when the add-on is installed; calls onOpen() to ensure menu creation and
 * any other initializion work is done immediately.
 *
 * @param {Object} e The event parameter for a simple onInstall trigger.
 */
function onInstall(e) {
  onOpen(e);
}

/**
 * Opens a sidebar. The sidebar structure is described in the Sidebar.html
 * project file.
 */
function showSidebar() {
  var ui = HtmlService.createTemplateFromFile('Sidebar')
      .evaluate()
      .setTitle(SIDEBAR_TITLE);
  SpreadsheetApp.getUi().showSidebar(ui);
}

/**
 * Opens a dialog to set the D4H API Token. The dialog structure is described in
 * the TokenDialog.html project file.
 */
function showTokenDialog() {
  var ui = HtmlService.createTemplateFromFile('TokenDialog')
      .evaluate()
      .setWidth(400)
      .setHeight(190);
  SpreadsheetApp.getUi().showModalDialog(ui, TOKEN_DIALOG_TITLE);
}

/**
 * Returns the value in the active cell.
 *
 * @return {String} The value of the active cell.
 */
function getActiveValue() {
  // Retrieve and return the information requested by the sidebar.
  var cell = SpreadsheetApp.getActiveSheet().getActiveCell();
  return cell.getValue();
}

/**
 * Replaces the active cell value with the given value.
 *
 * @param {Number} value A reference number to replace with.
 */
function setActiveValue(value) {
  // Use data collected from sidebar to manipulate the sheet.
  var cell = SpreadsheetApp.getActiveSheet().getActiveCell();
  cell.setValue(value);
}

/**
 * Executes the specified action (create a new sheet, copy the active sheet, or
 * clear the current sheet).
 *
 * @param {String} action An identifier for the action to take.
 */
function modifySheets(action) {
  // Use data collected from dialog to manipulate the spreadsheet.
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var currentSheet = ss.getActiveSheet();
  if (action == "create") {
    ss.insertSheet();
  } else if (action == "copy") {
    currentSheet.copyTo(ss);
  } else if (action == "clear") {
    currentSheet.clear();
  }
}

<|endoftext|>


<commit_before>// Global config
var GRAPHIC_DEFAULT_WIDTH = 600;
var MOBILE_THRESHOLD = 500;
var COLOR_BINS = [ -4, -2, 0, 2, 4, 6, 8, 10 ];
var COLOR_RANGE = [COLORS['red5'], '#ccc', COLORS['blue5'], COLORS['blue4'], COLORS['blue3'], COLORS['blue2']];

// Global vars
var pymChild = null;
var isMobile = false;
var graphicData = null;
var binnedData = [];

/*
 * Initialize the graphic.
 */
var onWindowLoaded = function() {
    if (Modernizr.svg) {
        loadLocalData(GRAPHIC_DATA);
        //loadCSV('data.csv')
    } else {
        pymChild = new pym.Child({});
    }
}

/*
 * Load graphic data from a local source.
 */
var loadLocalData = function(data) {
    graphicData = data;

    formatData();

    pymChild = new pym.Child({
        renderCallback: render
    });
}

/*
 * Load graphic data from a CSV.
 */
var loadCSV = function(url) {
    d3.csv(url, function(error, data) {
        graphicData = data;

        formatData();

        pymChild = new pym.Child({
            renderCallback: render
        });
    });
}

/*
 * Format graphic data for processing by D3.
 */
var formatData = function() {
    var numBins = COLOR_BINS.length - 1;

    // init the bins
    for (var i = 0; i < numBins; i++) {
        binnedData[i] = [];
    }

    // put states in bins
    _.each(graphicData, function(d) {
        if (d['amt'] != null) {
            var amt = +d['amt'];
            var state = d['usps'];

            for (var i = 0; i < numBins; i++) {
                if (amt >= COLOR_BINS[i] && amt < COLOR_BINS[i + 1]) {
                    binnedData[i].unshift(state);
                    break;
                }
            }
        }
    });
}

/*
 * Render the graphic(s). Called by pym with the container width.
 */
var render = function(containerWidth) {
    if (!containerWidth) {
        containerWidth = GRAPHIC_DEFAULT_WIDTH;
    }

    if (containerWidth <= MOBILE_THRESHOLD) {
        isMobile = true;
    } else {
        isMobile = false;
    }

    // Render the chart!
    renderBlockHistogram({
        container: '#graphic',
        width: containerWidth,
        data: binnedData,
        bins: COLOR_BINS,
        colors: COLOR_RANGE
    });

    // Update iframe
    if (pymChild) {
        pymChild.sendHeight();
    }
}

/*
 * Render a bar chart.
 */
var renderBlockHistogram = function(config) {
    /*
     * Setup
     */
    var labelColumn = 'usps';
    var valueColumn = 'amt';

    var blockHeight = 30;
    if (isMobile) {
        blockHeight = 18;
    }
    var blockGap = 1;

    var margins = {
        top: 20,
        right: 12,
        bottom: 20,
        left: 10
    };

    var ticksY = 4;

    // Determine largest bin
    var largestBin = _.max(binnedData, function(bin) {
        return bin.length;
    }).length;

    // Calculate actual chart dimensions
    var chartWidth = config['width'] - margins['left'] - margins['right'];
    var chartHeight = ((blockHeight + blockGap) * largestBin);

    // Clear existing graphic (for redraw)
    var containerElement = d3.select(config['container']);
    containerElement.html('');

    /*
     * Create the root SVG element.
     */
    var chartWrapper = containerElement.append('div')
        .attr('class', 'graphic-wrapper');

    var chartElement = chartWrapper.append('svg')
        .attr('width', chartWidth + margins['left'] + margins['right'])
        .attr('height', chartHeight + margins['top'] + margins['bottom'])
        .append('g')
        .attr('transform', makeTranslate(margins['left'], margins['top']));

    /*
     * Create D3 scale objects.
     */
    var xScale = d3.scale.ordinal()
        .domain(config['bins'].slice(0, -1))
        .rangeRoundBands([0, chartWidth], .1);

    var yScale = d3.scale.linear()
        .domain([ 0, largestBin ])
        .rangeRound([ chartHeight, 0 ]);

    var colorScale = d3.scale.ordinal()
        .domain(config['bins'])
        .range(config['colors']);

    /*
     * Create D3 axes.
     */
    var xAxis = d3.svg.axis()
        .scale(xScale)
        .orient('bottom')
        .outerTickSize(0)
        .tickFormat(function(d) {
            if (d > 0) {
                return '+' + d + '%';
            } else {
                return d + '%';
            }
        });

    var yAxis = d3.svg.axis()
        .scale(yScale)
        .orient('left')
        .ticks(ticksY);

    /*
     * Render axes to chart.
     */
    chartElement.append('g')
        .attr('class', 'x axis')
        .attr('transform', makeTranslate(0, chartHeight))
        .call(xAxis);

    /*
     * Render grid to chart.
     */
    var yAxisGrid = function() {
        return yAxis;
    };

    chartElement.append('g')
        .attr('class', 'y grid')
        .call(yAxisGrid()
            .tickSize(-chartWidth, 0)
            .tickFormat('')
        );

    /*
     * Shift tick marks
     */
    chartElement.selectAll('.x.axis .tick')
        .attr('transform', function() {
            var el = d3.select(this);
            var transform = d3.transform(el.attr('transform'));

            transform.translate[0] = transform.translate[0] - (xScale.rangeBand() / 2) - ((xScale.rangeBand() * .1) / 2);
            transform.translate[1] = 3;

            return transform.toString();
        })

    var lastTick = chartElement.select('.x.axis')
        .append('g')
        .attr('class', 'tick')
        .attr('transform', function() {
            var transform = d3.transform();
            var lastBin = xScale.domain()[xScale.domain().length - 1];

            transform.translate[0] = xScale(lastBin) + xScale.rangeBand() + ((xScale.rangeBand() * .1) / 2);
            transform.translate[1] = 3;

            return transform.toString();
        })

    lastTick.append('line')
        .attr('x1', 0)
        .attr('x2', 0)
        .attr('y1', 0)
        .attr('y2', 6)

    lastTick.append('text')
        .attr('text-anchor', 'middle')
        .attr('x', 0)
        .attr('y', 9)
        .attr('dy', '0.71em')
        .text(function() {
            var t = config['bins'][config['bins'].length - 1];
            if (t > 0) {
                return '+' + t + '%';
            } else {
                return t + '%';
            }
        });

    /*
     * Render bins to chart.
     */
    var bins = chartElement.selectAll('.bin')
        .data(config['data'])
        .enter().append('g')
            .attr('class', function(d,i) {
                return 'bin bin-' + i;
            })
            .attr('transform', function(d, i) {
                return makeTranslate(xScale(COLOR_BINS[i]), 0);
            });

    bins.selectAll('rect')
        .data(function(d) {
            return d3.entries(d);
        })
        .enter().append('rect')
            .attr('width', xScale.rangeBand())
            .attr('x', 0)
            .attr('y', function(d,i) {
                return chartHeight - ((blockHeight + blockGap) * (i + 1));
            })
            .attr('height', blockHeight)
            .attr('class', function(d) {
                return classify(d['value']);
            });

    /*
     * Render bin values.
     */
    bins.append('g')
        .attr('class', 'value')
        .selectAll('text')
            .data(function(d) {
                return d3.entries(d);
            })
        .enter().append('text')
            .attr('x', (xScale.rangeBand() / 2))
            .attr('y', function(d,i) {
                return chartHeight - ((blockHeight + blockGap) * (i + 1));
            })
            .attr('dy', (blockHeight / 2) + 4)
            .text(function(d) {
                return d['value'];
            });

    /*
     * Render annotations
     */
    var annotations = chartElement.append('g')
        .attr('class', 'annotations');

    annotations.append('text')
        .attr('class', 'label-top')
        .attr('x', xScale(0))
        .attr('dx', -15)
        .attr('text-anchor', 'end')
        .attr('y', -10)
        .html(ANNOTATION_LEFT);

    annotations.append('text')
        .attr('class', 'label-top')
        .attr('x', xScale(0))
        .attr('dx', 5)
        .attr('text-anchor', 'begin')
        .attr('y', -10)
        .html(ANNOTATION_RIGHT);

    annotations.append('line')
        .attr('class', 'axis-0')
        .attr('x1', xScale(0) - ((xScale.rangeBand() * .1) / 2))
        .attr('y1', -margins['top'])
        .attr('x2', xScale(0) - ((xScale.rangeBand() * .1) / 2))
        .attr('y2', chartHeight);
}

/*
 * Initially load the graphic
 * (NB: Use window.load to ensure all images have loaded)
 */
window.onload = onWindowLoaded;
<commit_msg>update colors in block_histogram<commit_after>// Global config
var GRAPHIC_DEFAULT_WIDTH = 600;
var MOBILE_THRESHOLD = 500;
var COLOR_BINS = [ -4, -2, 0, 2, 4, 6, 8, 10 ];
var COLOR_RANGE = ['#cc203b', '#e8604d', '#f6883e', '#f1bb4f', '#449970', '#70a99a', '#31716e'];

// Global vars
var pymChild = null;
var isMobile = false;
var graphicData = null;
var binnedData = [];

/*
 * Initialize the graphic.
 */
var onWindowLoaded = function() {
    if (Modernizr.svg) {
        loadLocalData(GRAPHIC_DATA);
        //loadCSV('data.csv')
    } else {
        pymChild = new pym.Child({});
    }
}

/*
 * Load graphic data from a local source.
 */
var loadLocalData = function(data) {
    graphicData = data;

    formatData();

    pymChild = new pym.Child({
        renderCallback: render
    });
}

/*
 * Load graphic data from a CSV.
 */
var loadCSV = function(url) {
    d3.csv(url, function(error, data) {
        graphicData = data;

        formatData();

        pymChild = new pym.Child({
            renderCallback: render
        });
    });
}

/*
 * Format graphic data for processing by D3.
 */
var formatData = function() {
    var numBins = COLOR_BINS.length - 1;

    // init the bins
    for (var i = 0; i < numBins; i++) {
        binnedData[i] = [];
    }

    // put states in bins
    _.each(graphicData, function(d) {
        if (d['amt'] != null) {
            var amt = +d['amt'];
            var state = d['usps'];

            for (var i = 0; i < numBins; i++) {
                if (amt >= COLOR_BINS[i] && amt < COLOR_BINS[i + 1]) {
                    binnedData[i].unshift(state);
                    break;
                }
            }
        }
    });
}

/*
 * Render the graphic(s). Called by pym with the container width.
 */
var render = function(containerWidth) {
    if (!containerWidth) {
        containerWidth = GRAPHIC_DEFAULT_WIDTH;
    }

    if (containerWidth <= MOBILE_THRESHOLD) {
        isMobile = true;
    } else {
        isMobile = false;
    }

    // Render the chart!
    renderBlockHistogram({
        container: '#graphic',
        width: containerWidth,
        data: binnedData,
        bins: COLOR_BINS,
        colors: COLOR_RANGE
    });

    // Update iframe
    if (pymChild) {
        pymChild.sendHeight();
    }
}

/*
 * Render a bar chart.
 */
var renderBlockHistogram = function(config) {
    /*
     * Setup
     */
    var labelColumn = 'usps';
    var valueColumn = 'amt';

    var blockHeight = 30;
    if (isMobile) {
        blockHeight = 18;
    }
    var blockGap = 1;

    var margins = {
        top: 20,
        right: 12,
        bottom: 20,
        left: 10
    };

    var ticksY = 4;

    // Determine largest bin
    var largestBin = _.max(binnedData, function(bin) {
        return bin.length;
    }).length;

    // Calculate actual chart dimensions
    var chartWidth = config['width'] - margins['left'] - margins['right'];
    var chartHeight = ((blockHeight + blockGap) * largestBin);

    // Clear existing graphic (for redraw)
    var containerElement = d3.select(config['container']);
    containerElement.html('');

    /*
     * Create the root SVG element.
     */
    var chartWrapper = containerElement.append('div')
        .attr('class', 'graphic-wrapper');

    var chartElement = chartWrapper.append('svg')
        .attr('width', chartWidth + margins['left'] + margins['right'])
        .attr('height', chartHeight + margins['top'] + margins['bottom'])
        .append('g')
        .attr('transform', makeTranslate(margins['left'], margins['top']));

    /*
     * Create D3 scale objects.
     */
    var xScale = d3.scale.ordinal()
        .domain(config['bins'].slice(0, -1))
        .rangeRoundBands([0, chartWidth], .1);

    var yScale = d3.scale.linear()
        .domain([ 0, largestBin ])
        .rangeRound([ chartHeight, 0 ]);

    var colorScale = d3.scale.ordinal()
        .domain(config['bins'])
        .range(config['colors']);

    /*
     * Create D3 axes.
     */
    var xAxis = d3.svg.axis()
        .scale(xScale)
        .orient('bottom')
        .outerTickSize(0)
        .tickFormat(function(d) {
            if (d > 0) {
                return '+' + d + '%';
            } else {
                return d + '%';
            }
        });

    var yAxis = d3.svg.axis()
        .scale(yScale)
        .orient('left')
        .ticks(ticksY);

    /*
     * Render axes to chart.
     */
    chartElement.append('g')
        .attr('class', 'x axis')
        .attr('transform', makeTranslate(0, chartHeight))
        .call(xAxis);

    /*
     * Render grid to chart.
     */
    var yAxisGrid = function() {
        return yAxis;
    };

    chartElement.append('g')
        .attr('class', 'y grid')
        .call(yAxisGrid()
            .tickSize(-chartWidth, 0)
            .tickFormat('')
        );

    /*
     * Shift tick marks
     */
    chartElement.selectAll('.x.axis .tick')
        .attr('transform', function() {
            var el = d3.select(this);
            var transform = d3.transform(el.attr('transform'));

            transform.translate[0] = transform.translate[0] - (xScale.rangeBand() / 2) - ((xScale.rangeBand() * .1) / 2);
            transform.translate[1] = 3;

            return transform.toString();
        })

    var lastTick = chartElement.select('.x.axis')
        .append('g')
        .attr('class', 'tick')
        .attr('transform', function() {
            var transform = d3.transform();
            var lastBin = xScale.domain()[xScale.domain().length - 1];

            transform.translate[0] = xScale(lastBin) + xScale.rangeBand() + ((xScale.rangeBand() * .1) / 2);
            transform.translate[1] = 3;

            return transform.toString();
        })

    lastTick.append('line')
        .attr('x1', 0)
        .attr('x2', 0)
        .attr('y1', 0)
        .attr('y2', 6)

    lastTick.append('text')
        .attr('text-anchor', 'middle')
        .attr('x', 0)
        .attr('y', 9)
        .attr('dy', '0.71em')
        .text(function() {
            var t = config['bins'][config['bins'].length - 1];
            if (t > 0) {
                return '+' + t + '%';
            } else {
                return t + '%';
            }
        });

    /*
     * Render bins to chart.
     */
    var bins = chartElement.selectAll('.bin')
        .data(config['data'])
        .enter().append('g')
            .attr('class', function(d,i) {
                return 'bin bin-' + i;
            })
            .attr('transform', function(d, i) {
                return makeTranslate(xScale(COLOR_BINS[i]), 0);
            });

    bins.selectAll('rect')
        .data(function(d) {
            return d3.entries(d);
        })
        .enter().append('rect')
            .attr('width', xScale.rangeBand())
            .attr('x', 0)
            .attr('y', function(d,i) {
                return chartHeight - ((blockHeight + blockGap) * (i + 1));
            })
            .attr('height', blockHeight)
            .attr('class', function(d) {
                return classify(d['value']);
            });

    /*
     * Render bin values.
     */
    bins.append('g')
        .attr('class', 'value')
        .selectAll('text')
            .data(function(d) {
                return d3.entries(d);
            })
        .enter().append('text')
            .attr('x', (xScale.rangeBand() / 2))
            .attr('y', function(d,i) {
                return chartHeight - ((blockHeight + blockGap) * (i + 1));
            })
            .attr('dy', (blockHeight / 2) + 4)
            .text(function(d) {
                return d['value'];
            });

    /*
     * Render annotations
     */
    var annotations = chartElement.append('g')
        .attr('class', 'annotations');

    annotations.append('text')
        .attr('class', 'label-top')
        .attr('x', xScale(0))
        .attr('dx', -15)
        .attr('text-anchor', 'end')
        .attr('y', -10)
        .html(ANNOTATION_LEFT);

    annotations.append('text')
        .attr('class', 'label-top')
        .attr('x', xScale(0))
        .attr('dx', 5)
        .attr('text-anchor', 'begin')
        .attr('y', -10)
        .html(ANNOTATION_RIGHT);

    annotations.append('line')
        .attr('class', 'axis-0')
        .attr('x1', xScale(0) - ((xScale.rangeBand() * .1) / 2))
        .attr('y1', -margins['top'])
        .attr('x2', xScale(0) - ((xScale.rangeBand() * .1) / 2))
        .attr('y2', chartHeight);
}

/*
 * Initially load the graphic
 * (NB: Use window.load to ensure all images have loaded)
 */
window.onload = onWindowLoaded;
<|endoftext|>


<commit_before>var cl = require('ciel');
var fidoconfig = require('fidoconfig');
var Squish = require('fidonet-squish');

var clog = console.log;

module.exports = filenameHPT => {
   cl.status(`Operating on area descriptions from ${filenameHPT}`);
   var echoconf = fidoconfig.areas(filenameHPT);
   var areaPaths = echoconf.getAreaNames().reduce((prevArr, nextName) => {
      var nextArea = echoconf[nextName];
      if( nextArea.passthrough ){
         cl.skip(`Area ${nextArea.configName} is passthough. Skipped.`);
         return prevArr;
      }
      return prevArr.concat({
         areaName: nextArea.configName,
         areaPath: nextArea.path
      });
   }, []);
   var varPaths = areaPaths.filter(
      nextAreaPath => /\[.*\]/.test(nextAreaPath.areaPath)
   );
   if( varPaths.length > 0 ){
      cl.fail('Unsquish cannot process [variables] inechobasepaths.');
      varPaths.forEach(nextVarPath =>
         clog(`${nextVarPath.areaName}: ${nextVarPath.areaPath}.`)
      );
      clog('');
      return;
   }
};<commit_msg>bugfix: the encoding of a source file should be UTF-8<commit_after>var cl = require('ciel');
var fidoconfig = require('fidoconfig');
var Squish = require('fidonet-squish');

var clog = console.log;

module.exports = filenameHPT => {
   cl.status(`Operating on area descriptions from ${filenameHPT}`);
   var echoconf = fidoconfig.areas(filenameHPT);
   var areaPaths = echoconf.getAreaNames().reduce((prevArr, nextName) => {
      var nextArea = echoconf[nextName];
      if( nextArea.passthrough ){
         cl.skip(`Area ${nextArea.configName} is passthough. Skipped.`);
         return prevArr;
      }
      return prevArr.concat({
         areaName: nextArea.configName,
         areaPath: nextArea.path
      });
   }, []);
   var varPaths = areaPaths.filter(
      nextAreaPath => /\[.*\]/.test(nextAreaPath.areaPath)
   );
   if( varPaths.length > 0 ){
      cl.fail('Unsquish cannot process [variables] in echobase paths.');
      varPaths.forEach(nextVarPath =>
         clog(`${nextVarPath.areaName}: ${nextVarPath.areaPath}.`)
      );
      clog('');
      return;
   }
};<|endoftext|>


<commit_before>var AutodafePart = require('autodafe_part');

module.exports = DbCommand.inherits( AutodafePart );

function DbCommand( params ) {
  this._init( params );
}

DbCommand.prototype._init = function( params ) {
  this.super_._init( params );

  var DbConnection = require('./db_connection');
  if ( !params || !( params.db_connection instanceof DbConnection ) )
    throw new Error( '`db_connection` is not instance of DbConnection in DbCommand.init' );

  this._.db_connection = params.db_connection;

  this.text         = params.text || '';

  this._params    = {};
  this._qm_params = [];
};

DbCommand.prototype.bind_values = function ( params ) {
  if ( !Object.isObject( params ) )
    throw new Error( "`params` should be instance of Object or Array in DbCommand.bind_values" );

  if ( Object.empty( params ) ) return this;
  this[ Array.isArray( params ) ? '_qm_params' : '_params' ] = Object.not_deep_clone( params );

  return this;
};

DbCommand.prototype.bind_value = function( name, value ) {
  if ( name == Number( name ) ) {
    this._qm_params[ name ] = value;
    return this;
  }

  this._params[ name ] = value;
  return this;
};

DbCommand.prototype.execute = function( callback ) {
  callback = typeof callback == "function" ? callback : function( e ) { throw e; }

  try {
    this._apply_params();
  }
  catch( e ) {
    callback( e );
  }

  this.db_connection.query( this.text, callback );
};

DbCommand.prototype._apply_params = function () {
  var i     = 0;
  var self  = this;

  this.text = this.text.replace( /\?/g, function(){
    return self.db_connection.quote_value( self._qm_params[ i++ ] );
  } );

  for ( var name in this._params ) {
    var true_name = name[0] == ':' ? name : ':' + name;
    this.text = this.text.replace( true_name, this.db_connection.quote_value( this._params[ name ] ) );
  }
};<commit_msg>issue#4 - рефакторинг DbCommand<commit_after>var AutodafePart = require('autodafe_part');

module.exports = DbCommand.inherits( AutodafePart );

function DbCommand( params ) {
  this._init( params );
}

DbCommand.prototype._init = function( params ) {
  this.super_._init( params );

  var DbConnection = require('./db_connection');
  if ( !params || !( params.db_connection instanceof DbConnection ) )
    throw new Error( '`db_connection` is not instance of DbConnection in DbCommand.init' );

  this._.db_connection = params.db_connection;

  this._text            = params.text || '';
  this._params          = {};
  this._params_applied  = false;
};

DbCommand.prototype.reset = function () {
  this._text            = '';
  this._params          = {};
  this._params_applied  = false;

  return this;
};

DbCommand.prototype.get_text = function () {
  this._apply_params();
  return this._text;
};

DbCommand.prototype.set_text = function ( text ) {
  this._params_applied  = false;
  this._text            = text;

  return this;
};

DbCommand.prototype.bind_values = function ( params ) {
  if ( !Object.isObject( params ) || Array.isArray( params ) )
    throw new Error( "DbCommand.bind_values: `params` should be instance of Object and not an Array" );

  if ( Object.empty( params ) ) return this;
  this._params         = Object.not_deep_clone( params );
  this._params_applied = false;

  return this;
};

DbCommand.prototype.bind_value = function( name, value ) {
  this._params[ name ] = value;
  this._params_applied = false;
  return this;
};

DbCommand.prototype.execute = function( callback ) {
  callback = typeof callback == "function" ? callback : function( e ) { throw e; }

  try {
    this._apply_params();
  }
  catch( e ) {
    callback( e );
  }

  this.db_connection.query( this._text, callback );
  return this;
};

DbCommand.prototype._apply_params = function () {
  if ( this._params_applied ) return;

  for ( var name in this._params ) {
    var true_name = name[0] == ':' ? name : ':' + name;
    this._text = this._text.replace( true_name, this.db_connection.quote_value( this._params[ name ] ) );
  }

  this._params_applied = true;
};<|endoftext|>


<commit_before>'use strict';

var app = angular.module('fireoflondonApp');

app.factory('Posts', ['$resource', function ($resource) {
    var Posts = $resource('http://localhost/wp-json/posts',
        {
            query: {
                isArray: true,
                transformResponse: function (data) {
                    data = angular.fromJson(data);
                    return data.content;
                }
            }
        });
    return Posts;
}]);

app.factory('Post', ['$resource', function($resource) {
  return $resource('http://localhost/wp-json/posts/:articleId', { articleId: '@articleId'})
}]);

<commit_msg>LOL. So I thought localhost was working for the Wordpress - but this is client side and the content was working from wordpress from MY localhost.  What a fucking knobber. Switching to dev.fireoflondon.org for now and we'll see if I can configure this shit with vhosts in apache.<commit_after>'use strict';

var app = angular.module('fireoflondonApp');

app.factory('Posts', ['$resource', function ($resource) {
    var Posts = $resource('http://dev.fireoflondon.org/wp-json/posts',
        {
            query: {
                isArray: true,
                transformResponse: function (data) {
                    data = angular.fromJson(data);
                    return data.content;
                }
            }
        });
    return Posts;
}]);

app.factory('Post', ['$resource', function($resource) {
  return $resource('http://dev.fireoflondon.org/wp-json/posts/:articleId', { articleId: '@articleId'})
}]);

<|endoftext|>