<commit_before>
$(document).ready(function() {

	$.getJSON('/backend/complex/' + complex['complex_accession'], function(data) {

	  	var complex_table = create_complex_table(data);

		if(data != null && data["graph"]["nodes"].length > 1) {

		    var graph = create_cytoscape_vis("cy", layout, graph_style, data["graph"], null, true, "complex_diagram");
		    create_cy_download_button(graph, "cy_download", complex['complex_accession'] + '_subunit_graph')

		}
		else {
                    hide_section("diagram");
                }

		if (data != null && data["network_graph"]["nodes"].length > 1) {

		    var graph2 = create_cytoscape_vis("cy2", layout, graph_style, data["network_graph"], null, true, "complex_network");
		    create_cy_download_button(graph2, "cy2_download", complex['complex_accession'] + '_complex_network_graph')

		    // create_filter_bar("union_radio", graph, all_filter);
		    // create_filter_bar("subunit_radio", graph, subunit_filter);
		    // create_filter_bar("go_radio", graph, go_filter);
		    // $("#filter_bar").show();

		}
		else {
		    hide_section("network");
		}
	});

});

function create_complex_table(data) {
    var evidence = data['subunit'];
    var datatable = [];
    var subunits = {};
    for (var i = 0; i < evidence.length; i++) {
	datatable.push(complex_subunit_data_to_table(evidence[i]));
	subunits[evidence[i]["display_name"]] = true;
    }

    set_up_header(
		  "complex_table",
		  datatable.length,
		  "entry",
		  "entries",
		  Object.keys(subunits).length,
		  "subunit",
		  "subunits"
		  );

    var options = {};
    options["bPaginate"] = false;
    options["bDestroy"] = true;
    options["aoColumns"] = [
			  null,
			  null,
			  null
			  ];
  options["aaData"] = datatable;
  options["oLanguage"] = {
      sEmptyTable: "No subunits for this complex???."
  };

  return create_table("complex_table", options);

}

function create_filter_bar(radio_id, graph, target_filter) {
    var radio = $("#" + radio_id);
    radio.click(function() {
	    graph.filters['discrete'] = target_filter();
	    graph.applyFilters();
	});
}

function all_filter() {
    return "node, edge";
}

function subunit_filter() {
    return "node, edge[class_type = 'complex_gene']";
}

function go_filter() {
    return "node, edge[class_type = 'complex_go']";
}

var graph_style = cytoscape.stylesheet()
    .selector('node')
    .css({
	    'content': 'data(name)',
	    'font-family': 'helvetica',
	    'font-size': 14,
	    'text-outline-width': 3,
	    'text-outline-color': '#888',
	    'text-valign': 'center',
	    'color': '#fff',
	    'width': 30,
	    'height': 30,
	    'border-color': '#fff'
        })
    .selector("node[type='small-molecule']")
    .css({
	    'background-color': "#338AFF",
	})
    .selector("node[type='subcomplex']")
    .css({
	    'background-color': "#FF8933",
        })
    .selector("node[type='other_subunit']")
    .css({
	    'background-color': "#A133FF",
        })

    .selector("node[type='Gene']")
    .css({
            'text-outline-color': "#FF8933",
	    'background-color': "#FF8933",
        })
    .selector("node[type='Go']")
    .css({
            'text-outline-color': "#A133FF",
	    'background-color': "#A133FF",
        })
    .selector("node[type='Complex']")
    .css({
            'text-outline-color': "#86908C",
            'background-color': "#86908C",
        })
    .selector("node[type='Current_complex']")
    .css({
            'text-outline-color': "#0E9F36",
	    'background-color': "#86908C",
        })
    .selector('edge')
    .css({
	    'width': 2,
	    'target-arrow-shape': 'triangle',
	    'line-color': '#848484',
	    'target-arrow-color': '#848484'
        })
    .selector("node[sub_type='FOCUS']")
    .css({
	    'background-color': "#fade71",
	    'text-outline-color': '#fff',
	    'color': '#888'
        })
    .selector("edge[class_type = 'complex_go']")
    .css({
            'line-color': "#7233FF"
        })
    .selector("edge[class_type = 'complex_gene']")
    .css({
            'line-color': "#74FF33"
        })
    .selector("edge[class_type = 'complex']")
    .css({
	    'line-color': "#74FF33"
        });

var layout = {
    "name": "arbor",
    "liveUpdate": true,
    "ungrabifyWhileSimulating": true,
    "nodeMass":function(data) {
	if(data.sub_type == 'FOCUS') {
	    return 10;
	}
	else {
	    return 1;
	}
    }
};
<commit_msg>in progress<commit_after>
$(document).ready(function() {

	$.getJSON('/backend/complex/' + complex['complex_accession'], function(data) {

	  	var complex_table = create_complex_table(data);

		if(data != null && data["graph"]["nodes"].length > 1) {

		    var graph = create_cytoscape_vis("cy", layout, graph_style, data["graph"], null, true, "complex_diagram");
		    create_cy_download_button(graph, "cy_download", complex['complex_accession'] + '_subunit_graph')

		}
		else {
                    hide_section("diagram");
                }

		if (data != null && data["network_graph"]["nodes"].length > 1) {

		    var graph2 = create_cytoscape_vis("cy2", layout, graph_style, data["network_graph"], null, true, "complex_network");
		    create_cy_download_button(graph2, "cy2_download", complex['complex_accession'] + '_complex_network_graph')

		    // create_filter_bar("union_radio", graph, all_filter);
		    // create_filter_bar("subunit_radio", graph, subunit_filter);
		    // create_filter_bar("go_radio", graph, go_filter);
		    // $("#filter_bar").show();

		}
		else {
		    hide_section("network");
		}
	});

});

function create_complex_table(data) {
    var evidence = data['subunit'];
    var datatable = [];
    var subunits = {};
    for (var i = 0; i < evidence.length; i++) {
	datatable.push(complex_subunit_data_to_table(evidence[i]));
	subunits[evidence[i]["display_name"]] = true;
    }

    set_up_header(
		  "complex_table",
		  datatable.length,
		  "entry",
		  "entries",
		  Object.keys(subunits).length,
		  "subunit",
		  "subunits"
		  );

    var options = {};
    options["bPaginate"] = false;
    options["bDestroy"] = true;
    options["aoColumns"] = [
			  null,
			  null,
			  null
			  ];
  options["aaData"] = datatable;
  options["oLanguage"] = {
      sEmptyTable: "No subunits for this complex???."
  };

  return create_table("complex_table", options);

}

function create_filter_bar(radio_id, graph, target_filter) {
    var radio = $("#" + radio_id);
    radio.click(function() {
	    graph.filters['discrete'] = target_filter();
	    graph.applyFilters();
	});
}

function all_filter() {
    return "node, edge";
}

function subunit_filter() {
    return "node, edge[class_type = 'complex_gene']";
}

function go_filter() {
    return "node, edge[class_type = 'complex_go']";
}

var graph_style = cytoscape.stylesheet()
    .selector('node')
    .css({
	    'content': 'data(name)',
	    'font-family': 'helvetica',
	    'font-size': 14,
	    'text-outline-width': 3,
	    'text-outline-color': '#888',
	    'text-valign': 'center',
	    'color': '#fff',
	    'width': 30,
	    'height': 30,
	    'border-color': '#fff'
        })
    .selector("node[type='small-molecule']")
    .css({
	    'background-color': "0D85F3",
	})
    .selector("node[type='subcomplex']")
    .css({
	    'background-color': "F3750D",
        })
    .selector("node[type='other_subunit']")
    .css({
	    'background-color': "#A133FF",
        })

    .selector("node[type='Gene']")
    .css({
            'text-outline-color': "#FF8933",
	    'background-color': "#FF8933",
        })
    .selector("node[type='Go']")
    .css({
            'text-outline-color': "#A133FF",
	    'background-color': "#A133FF",
        })
    .selector("node[type='Complex']")
    .css({
            'text-outline-color': "#86908C",
            'background-color': "#86908C",
        })
    .selector("node[type='Current_complex']")
    .css({
            'text-outline-color': "#0E9F36",
	    'background-color': "#86908C",
        })
    .selector('edge')
    .css({
	    'width': 2,
	    'target-arrow-shape': 'triangle',
	    'line-color': '#848484',
	    'target-arrow-color': '#848484'
        })
    .selector("node[sub_type='FOCUS']")
    .css({
	    'background-color': "#fade71",
	    'text-outline-color': '#fff',
	    'color': '#888'
        })
    .selector("edge[class_type = 'complex_go']")
    .css({
            'line-color': "#7233FF"
        })
    .selector("edge[class_type = 'complex_gene']")
    .css({
            'line-color': "#74FF33"
        })
    .selector("edge[class_type = 'complex']")
    .css({
	    'line-color': "#74FF33"
        });

var layout = {
    "name": "arbor",
    "liveUpdate": true,
    "ungrabifyWhileSimulating": true,
    "nodeMass":function(data) {
	if(data.sub_type == 'FOCUS') {
	    return 10;
	}
	else {
	    return 1;
	}
    }
};
<|endoftext|>


<commit_before>import objectPool from '../../../../object-pool';
import { centerOfObject } from '../../../../utils';

export default function loadFromMap() {
  objects.call(this, 'trees', 'tree', Tree);
  objects.call(this, 'water', 'water', Water);
}

function objects(name, objectType, objectClass) {
  const objArr = this.map.objects[name];
  for (let i = 0, len = objArr.length; i < len; i++) {
    const start = centerOfObject(objArr[i], this.map);

    const object = objectPool.new(objectType, objectClass, {
      game: this.game,
      x: start.x,
      y: start.y,
    });
  }
}
<commit_msg>Add forgotten imports<commit_after>import objectPool from '../../../../object-pool';
import { centerOfObject } from '../../../../utils';

import Tree from '../../../../sprites/object/Tree';
import Water from '../../../../sprites/object/Water';

export default function loadFromMap() {
  objects.call(this, 'trees', 'tree', Tree);
  objects.call(this, 'water', 'water', Water);
}

function objects(name, objectType, objectClass) {
  const objArr = this.map.objects[name];
  for (let i = 0, len = objArr.length; i < len; i++) {
    const start = centerOfObject(objArr[i], this.map);

    const object = objectPool.new(objectType, objectClass, {
      game: this.game,
      x: start.x,
      y: start.y,
    });
  }
}
<|endoftext|>


<commit_before>/**
 * @author Serhii Maksymchuk from Ubrainians for imCode
 * 20.02.18
 */
Imcms.define(
    "imcms-document-profile-select-window-builder",
    [
        "imcms-window-builder", "imcms-bem-builder", "imcms-i18n-texts", "imcms-components-builder",
        "imcms-profiles-rest-api"
    ],
    function (WindowBuilder, BEM, texts, components, profilesRestApi) {

        texts = texts.editors.newDocumentProfile;

        var $radioButtonsGroup, $parentSelect, $profilesSelect;

        function loadProfiles($profilesSelect) {
            profilesRestApi.read().done(function (profiles) {
                var profilesDataMapped = profiles.map(function (profile) {
                    /** @namespace profile.documentName */
                    return {
                        text: profile.name,
                        "data-value": profile.documentName
                    }
                });

                components.selects.addOptionsToSelect(profilesDataMapped, $profilesSelect);
            });
        }

        function buildProfileSelect() {
            var $profilesSelectContainer = components.selects.selectContainer("<div>", {
                id: "doc-profiles",
                text: texts.selectProfile,
                name: "profile",
                emptySelect: true
            });

            $profilesSelect = $profilesSelectContainer.getSelect();

            loadProfiles($profilesSelect);

            return new BEM({
                block: "imcms-profile-select",
                elements: {
                    "select": $profilesSelectContainer
                }
            }).buildBlockStructure("<div>");
        }

        function buildParentSelect() {
            var $parentDocIdInput = components.texts.textBox("<div>", {
                name: "title",
                text: texts.selectParent
            });

            return new BEM({
                block: "imcms-parent-select",
                elements: {
                    "text-box": $parentDocIdInput
                }
            }).buildBlockStructure("<div>", {"style": "display: none;"});
        }

        function buildChoosingRadio($profileSelect, $parentSelect) {
            var $choosingTitle = components.texts.titleText("<div>", texts.chooseProfileOrParent);

            var $profilesOption = components.radios.imcmsRadio("<div>", {
                text: texts.buildByProfile,
                name: "select-profile-or-doc",
                value: "profile",
                checked: true,
                click: function () {
                    $parentSelect.slideUp(400);
                    $profileSelect.slideDown(400);
                }
            });

            var $docIdOption = components.radios.imcmsRadio("<div>", {
                text: texts.buildByParent,
                name: "select-profile-or-doc",
                value: "docId",
                click: function () {
                    $parentSelect.slideDown(400);
                    $profileSelect.slideUp(400);
                }
            });

            $radioButtonsGroup = components.radios.group($profilesOption, $docIdOption);

            return new BEM({
                block: "new-doc-parent-options",
                elements: {
                    "title": $choosingTitle,
                    "by-profile": $profilesOption,
                    "by-doc-id": $docIdOption
                }
            }).buildBlockStructure("<div>");
        }

        function buildBody() {
            var $profileSelect = buildProfileSelect();
            $parentSelect = buildParentSelect();
            var $radioBlock = buildChoosingRadio($profileSelect, $parentSelect);

            return new BEM({
                block: "imcms-document-profile",
                elements: {
                    "choose-the-way": $radioBlock,
                    "profile-select": $profileSelect,
                    "parent-select": $parentSelect
                }
            }).buildBlockStructure("<div>");
        }

        function onSubmit() {
            var checkedValue = $radioButtonsGroup.getCheckedValue();

            if ("docId" === checkedValue) {
                var selectedParentDoc = $parentSelect.val().trim();

                if (selectedParentDoc) {
                    // validation here
                    windowBuilder.closeWindow();
                    onProfileOrParentSelectedCallback(selectedParentDoc, null);
                    return;
                }
            }

            if ("profile" === checkedValue) {
                var selectedValue = $profilesSelect.getSelectedValue();

                if (selectedValue) {
                    var profileId = selectedValue;

                    windowBuilder.closeWindow();
                    onProfileOrParentSelectedCallback(null, profileId);
                }
            }
        }

        function buildFooter() {
            return windowBuilder.buildFooter([
                components.buttons.positiveButton({
                    text: texts.createDocButton,
                    click: onSubmit
                })
            ]);
        }

        function buildProfileSelectWindow() {
            return new BEM({
                block: "imcms-document-profile-select-window",
                elements: {
                    "head": windowBuilder.buildHead(texts.title),
                    "body": buildBody(),
                    "footer": buildFooter()
                }
            }).buildBlockStructure("<div>");
        }

        var windowBuilder = new WindowBuilder({
            factory: buildProfileSelectWindow
        });

        var onProfileOrParentSelectedCallback;

        return {
            build: function (onParentSelected) {
                onProfileOrParentSelectedCallback = onParentSelected;
                windowBuilder.buildWindowWithShadow();
            }
        };
    }
);
<commit_msg>IMCMS-277 - Profiles: - Correct receiving parent doc input value while doc creation.<commit_after>/**
 * @author Serhii Maksymchuk from Ubrainians for imCode
 * 20.02.18
 */
Imcms.define(
    "imcms-document-profile-select-window-builder",
    [
        "imcms-window-builder", "imcms-bem-builder", "imcms-i18n-texts", "imcms-components-builder",
        "imcms-profiles-rest-api"
    ],
    function (WindowBuilder, BEM, texts, components, profilesRestApi) {

        texts = texts.editors.newDocumentProfile;

        var $radioButtonsGroup, $parentDocIdInput, $profilesSelect;

        function loadProfiles($profilesSelect) {
            profilesRestApi.read().done(function (profiles) {
                var profilesDataMapped = profiles.map(function (profile) {
                    /** @namespace profile.documentName */
                    return {
                        text: profile.name,
                        "data-value": profile.documentName
                    }
                });

                components.selects.addOptionsToSelect(profilesDataMapped, $profilesSelect);
            });
        }

        function buildProfileSelect() {
            var $profilesSelectContainer = components.selects.selectContainer("<div>", {
                id: "doc-profiles",
                text: texts.selectProfile,
                name: "profile",
                emptySelect: true
            });

            $profilesSelect = $profilesSelectContainer.getSelect();

            loadProfiles($profilesSelect);

            return new BEM({
                block: "imcms-profile-select",
                elements: {
                    "select": $profilesSelectContainer
                }
            }).buildBlockStructure("<div>");
        }

        function buildParentSelect() {
            $parentDocIdInput = components.texts.textBox("<div>", {
                name: "title",
                text: texts.selectParent
            });

            return new BEM({
                block: "imcms-parent-select",
                elements: {
                    "text-box": $parentDocIdInput
                }
            }).buildBlockStructure("<div>", {"style": "display: none;"});
        }

        function buildChoosingRadio($profileSelect, $parentSelect) {
            var $choosingTitle = components.texts.titleText("<div>", texts.chooseProfileOrParent);

            var $profilesOption = components.radios.imcmsRadio("<div>", {
                text: texts.buildByProfile,
                name: "select-profile-or-doc",
                value: "profile",
                checked: true,
                click: function () {
                    $parentSelect.slideUp(400);
                    $profileSelect.slideDown(400);
                }
            });

            var $docIdOption = components.radios.imcmsRadio("<div>", {
                text: texts.buildByParent,
                name: "select-profile-or-doc",
                value: "docId",
                click: function () {
                    $parentSelect.slideDown(400);
                    $profileSelect.slideUp(400);
                }
            });

            $radioButtonsGroup = components.radios.group($profilesOption, $docIdOption);

            return new BEM({
                block: "new-doc-parent-options",
                elements: {
                    "title": $choosingTitle,
                    "by-profile": $profilesOption,
                    "by-doc-id": $docIdOption
                }
            }).buildBlockStructure("<div>");
        }

        function buildBody() {
            var $profileSelect = buildProfileSelect();
            var $parentSelect = buildParentSelect();
            var $radioBlock = buildChoosingRadio($profileSelect, $parentSelect);

            return new BEM({
                block: "imcms-document-profile",
                elements: {
                    "choose-the-way": $radioBlock,
                    "profile-select": $profileSelect,
                    "parent-select": $parentSelect
                }
            }).buildBlockStructure("<div>");
        }

        function onSubmit() {
            var checkedValue = $radioButtonsGroup.getCheckedValue();

            if ("docId" === checkedValue) {
                var selectedParentDoc = $parentDocIdInput.getValue().trim();

                if (selectedParentDoc) {
                    // validation here
                    windowBuilder.closeWindow();
                    onProfileOrParentSelectedCallback(selectedParentDoc, null);
                    return;
                }
            }

            if ("profile" === checkedValue) {
                var selectedValue = $profilesSelect.getSelectedValue();

                if (selectedValue) {
                    var profileId = selectedValue;

                    windowBuilder.closeWindow();
                    onProfileOrParentSelectedCallback(null, profileId);
                }
            }
        }

        function buildFooter() {
            return windowBuilder.buildFooter([
                components.buttons.positiveButton({
                    text: texts.createDocButton,
                    click: onSubmit
                })
            ]);
        }

        function buildProfileSelectWindow() {
            return new BEM({
                block: "imcms-document-profile-select-window",
                elements: {
                    "head": windowBuilder.buildHead(texts.title),
                    "body": buildBody(),
                    "footer": buildFooter()
                }
            }).buildBlockStructure("<div>");
        }

        var windowBuilder = new WindowBuilder({
            factory: buildProfileSelectWindow
        });

        var onProfileOrParentSelectedCallback;

        return {
            build: function (onParentSelected) {
                onProfileOrParentSelectedCallback = onParentSelected;
                windowBuilder.buildWindowWithShadow();
            }
        };
    }
);
<|endoftext|>


<commit_before>'use strict';

describe('Content', function() {

    describe('word content', function() {
        var scope;
        var element;
        var compile;
        var template;
        beforeEach(function(){
            module('thumbnailModule');
        });

        beforeEach(inject(function($rootScope,$compile,$templateCache) {
            scope = $rootScope.$new();
            compile = $compile;
            template = $templateCache;
        }));

        it('Should initialize word with details', function() {
            scope.name1='some Name';
            scope.customStyle1='someStyle';
            scope.introduction1='meaning';
            scope.overlay1='overlayId',

            element = angular.element('<word-thumbnail overlay-id="{{overlay1}}" custom-style="{{customStyle1}}" transliteration="{{name1}}" introduction-summary="{{introduction1}}"></word-thumbnail>');
            template.put('/user-js/common/templates/thumbnail/wordThumbnail.html', '
{{overlayId}} {{customStyle}} {{transliteration}} {{introductionSummary}}
');
            compile(element)(scope);
            scope.$apply();

            expect(element.html()).toBe('overlayId someStyle some Name meaning');
        });
    });
});
<commit_msg>Fixing test<commit_after>'use strict';

describe('Content', function() {

    describe('word content', function() {
        var scope;
        var element;
        var compile;
        var template;
        beforeEach(function(){
            module('thumbnailModule');
        });

        beforeEach(inject(function($rootScope,$compile,$templateCache) {
            scope = $rootScope.$new();
            compile = $compile;
            template = $templateCache;
        }));

        it('Should initialize word with details', function() {
            scope.name1='some Name';
            scope.customStyle1='someStyle';
            scope.introduction1='meaning';
            scope.overlay1='overlayId',

            element = angular.element('<word-thumbnail overlay-id="{{overlay1}}" custom-style="{{customStyle1}}" transliteration="{{name1}}" english-intro-excerpt="{{introduction1}}"></word-thumbnail>');
            template.put('/user-js/common/templates/thumbnail/wordThumbnail.html', '
{{overlayId}} {{customStyle}} {{transliteration}} {{englishIntroExcerpt}}
');
            compile(element)(scope);
            scope.$apply();

            expect(element.html()).toBe('overlayId someStyle some Name meaning');
        });
    });
});
<|endoftext|>


<commit_before>/*
  jQuery ui.timepickr - @VERSION
  http://code.google.com/p/jquery-utils/

  (c) Maxime Haineault <haineault@gmail.com>
  http://haineault.com

  MIT License (http://www.opensource.org/licenses/mit-license.php

  Note: if you want the original experimental plugin checkout the rev 224

  Dependencies
  ------------
  - jquery.utils.js
  - jquery.strings.js
  - ui.dropslide.js

*/

(function($) {
    $.widget('ui.timepickr', {
        init: function() {
            var menu    = this._buildMenu(this.options);
            var element = this.element;
            element.data('timepickr.initialValue', element.val());
            menu.insertAfter(this.element);
            element
                .addClass('ui-timepickr')
                .dropslide(this.options.dropslide)
                .bind('select', this.select);

            element.blur(function(e) {
                $(this).dropslide('hide');
                $(this).val($(this).data('timepickr.initialValue'));
            });

            if (this.options.val) {
                element.val(this.options.val);
            }

            if (this.options.handle) {
                $(this.options.handle).click(function() {
                    $(element).dropslide('show');
                });
            }

            if (this.options.resetOnBlur) {
                menu.find('li > span').bind('mousedown.timepickr', function(){
                    $(element).data('timepickr.initialValue', $(element).val());
                });
            }

            if (this.options.updateLive) {
                menu.find('li').bind('mouseover.timepickr', function() {
                    $(element).timepickr('update');
                });
            }

            var hrs = menu.find('ol:eq(1)').find('li:first').addClass('hover').find('span').addClass('ui-hover-state').end().end();
            var min = menu.find('ol:eq(2)').find('li:first').addClass('hover').find('span').addClass('ui-hover-state').end().end();
            var sec = menu.find('ol:eq(3)').find('li:first').addClass('hover').find('span').addClass('ui-hover-state').end().end();

            if (this.options.convention === 24) {
                var day        = menu.find('ol:eq(0) li:eq(0)');
                var night      = menu.find('ol:eq(0) li:eq(1)');
                var dayHours   = hrs.find('li').slice(0, 12);
                var nightHours = hrs.find('li').slice(12, 24);
                var index      = 0;
                var selectHr   = function(id) {
                    hrs.find('li').removeClass('hover');
                    hrs.find('span').removeClass('ui-hover-state');
                    hrs.find('li').eq(id).addClass('hover').find('span').addClass('ui-hover-state')
                };

                day.mouseover(function() {
                    nightHours.hide();
                    dayHours.show(0);
                    index = hrs.find('li.hover').data('id') || hrs.find('li:first').data('id');
                    selectHr(index > 11 && index - 12 || index);
                    element.dropslide('redraw');
                });

                night.mouseover(function() {
                    dayHours.hide();
                    nightHours.show(0);
                    index = hrs.find('li.hover').data('id') || hrs.find('li:first').data('id');
                    selectHr(index < 12 && index + 12 || index);
                    element.dropslide('redraw');
                });
            }
            element.dropslide('redraw');
            element.data('timepickr', this);
        },

        update: function() {
            var frmt = this.options.convention === 24 && 'format24' || 'format12';
            var val = {
                h: this.getValue('hour'),
                m: this.getValue('minute'),
                s: this.getValue('second'),
                prefix: this.getValue('prefix'),
                suffix: this.getValue('suffix')
            };
            var o = $.format(this.options[frmt], val);

            $(this.element).val(o);
        },

        select: function(e) {
            var dropslide = $(this).data('dropslide');
            $(dropslide.element).timepickr('update');
            e.stopPropagation();
        },

        getHour: function(selection) {
            return this.getValue('hour');
        },

        getMinute: function(selection) {
            return this.getValue('minute');
        },

        getSecond: function(selection) {
            return this.getValue('second');
        },

        getValue: function(type) {
            return $('.ui-timepickr.'+ type +'.hover', this.element.next()).text();
        },

        activate: function() {
            this.element.dropslide('activate');
        },

        destroy: function() {
            this.element.dropslide('destroy');
        },

        /* UI private methods */

        _createButton: function(i, format, className) {
            var o  = format && $.format(format, i) || i;
            var cn = className && 'ui-timepickr '+ className || 'ui-timepickr';
            return $('
').addClass(cn).data('id', i).append($('').text(o));
        },

        _createRow: function(obj, format, className) {
            var row = $('
');
            for (var x in obj) {
                row.append(this._createButton(obj[x], format || false, className || false));
            }
            return row;
        },

        _getRanges12: function(options) {
            var o = [];
            if (options.hours)   { o.push(this._createRow($.range(1, 13),   '{0:0.2d}', 'hour')); }
            if (options.minutes) { o.push(this._createRow(options.rangeMin, '{0:0.2d}', 'minute')); }
            if (options.seconds) { o.push(this._createRow(options.rangeSec, '{0:0.2d}', 'second')); }
            if (options.suffix)  { o.push(this._createRow(options.suffix,   false,      'suffix')); }
            return o;
        },

        _getRanges24: function(options) {
            var o = [];
            o.push(this._createRow(options.prefix, false, 'prefix')); // prefix is required in 24h mode
            if (options.hours)   { o.push(this._createRow($.range(0, 24),   '{0:0.2d}', 'hour')); }
            if (options.minutes) { o.push(this._createRow(options.rangeMin, '{0:0.2d}', 'minute')); }
            if (options.seconds) { o.push(this._createRow(options.rangeSec, '{0:0.2d}', 'second')); }
            return o;
        },

        _buildMenu: function(options) {
            var ranges = options.convention === 24 && this._getRanges24(options) || this._getRanges12(options);
            var menu   = $('');
            //if () {options.convention}
            for (var x in ranges) {
                menu.append(ranges[x]);
            }
            return menu;
        }
    });

    $.ui.timepickr.defaults = {
        convention:  24, // 24, 12
        dropslide:   { trigger: 'focus' },
        format12:    '{h:02.d}:{m:02.d} {suffix:s}',
        format24:    '{h:02.d}:{m:02.d}',
        handle:      false,
        hours:       true,
        minutes:     true,
        seconds:     false,
        prefix:      ['am', 'pm'],
        suffix:      ['am', 'pm'],
        rangeMin:    ['00', '15', '30', '45'],
        rangeSec:    ['00', '15', '30', '45'],
        updateLive:  true,
        resetOnBlur: true,
        val:         false
    };

})(jQuery);
<commit_msg>- removed unused arguments<commit_after>/*
  jQuery ui.timepickr - @VERSION
  http://code.google.com/p/jquery-utils/

  (c) Maxime Haineault <haineault@gmail.com>
  http://haineault.com

  MIT License (http://www.opensource.org/licenses/mit-license.php

  Note: if you want the original experimental plugin checkout the rev 224

  Dependencies
  ------------
  - jquery.utils.js
  - jquery.strings.js
  - ui.dropslide.js

*/

(function($) {
    $.widget('ui.timepickr', {
        init: function() {
            var menu    = this._buildMenu(this.options);
            var element = this.element;
            element.data('timepickr.initialValue', element.val());
            menu.insertAfter(this.element);
            element
                .addClass('ui-timepickr')
                .dropslide(this.options.dropslide)
                .bind('select', this.select);

            element.blur(function(e) {
                $(this).dropslide('hide');
                $(this).val($(this).data('timepickr.initialValue'));
            });

            if (this.options.val) {
                element.val(this.options.val);
            }

            if (this.options.handle) {
                $(this.options.handle).click(function() {
                    $(element).dropslide('show');
                });
            }

            if (this.options.resetOnBlur) {
                menu.find('li > span').bind('mousedown.timepickr', function(){
                    $(element).data('timepickr.initialValue', $(element).val());
                });
            }

            if (this.options.updateLive) {
                menu.find('li').bind('mouseover.timepickr', function() {
                    $(element).timepickr('update');
                });
            }

            var hrs = menu.find('ol:eq(1)').find('li:first').addClass('hover').find('span').addClass('ui-hover-state').end().end();
            var min = menu.find('ol:eq(2)').find('li:first').addClass('hover').find('span').addClass('ui-hover-state').end().end();
            var sec = menu.find('ol:eq(3)').find('li:first').addClass('hover').find('span').addClass('ui-hover-state').end().end();

            if (this.options.convention === 24) {
                var day        = menu.find('ol:eq(0) li:eq(0)');
                var night      = menu.find('ol:eq(0) li:eq(1)');
                var dayHours   = hrs.find('li').slice(0, 12);
                var nightHours = hrs.find('li').slice(12, 24);
                var index      = 0;
                var selectHr   = function(id) {
                    hrs.find('li').removeClass('hover');
                    hrs.find('span').removeClass('ui-hover-state');
                    hrs.find('li').eq(id).addClass('hover').find('span').addClass('ui-hover-state')
                };

                day.mouseover(function() {
                    nightHours.hide();
                    dayHours.show(0);
                    index = hrs.find('li.hover').data('id') || hrs.find('li:first').data('id');
                    selectHr(index > 11 && index - 12 || index);
                    element.dropslide('redraw');
                });

                night.mouseover(function() {
                    dayHours.hide();
                    nightHours.show(0);
                    index = hrs.find('li.hover').data('id') || hrs.find('li:first').data('id');
                    selectHr(index < 12 && index + 12 || index);
                    element.dropslide('redraw');
                });
            }
            element.dropslide('redraw');
            element.data('timepickr', this);
        },

        update: function() {
            var frmt = this.options.convention === 24 && 'format24' || 'format12';
            var val = {
                h: this.getValue('hour'),
                m: this.getValue('minute'),
                s: this.getValue('second'),
                prefix: this.getValue('prefix'),
                suffix: this.getValue('suffix')
            };
            var o = $.format(this.options[frmt], val);

            $(this.element).val(o);
        },

        select: function(e) {
            var dropslide = $(this).data('dropslide');
            $(dropslide.element).timepickr('update');
            e.stopPropagation();
        },

        getHour: function() {
            return this.getValue('hour');
        },

        getMinute: function() {
            return this.getValue('minute');
        },

        getSecond: function() {
            return this.getValue('second');
        },

        getValue: function(type) {
            return $('.ui-timepickr.'+ type +'.hover', this.element.next()).text();
        },

        activate: function() {
            this.element.dropslide('activate');
        },

        destroy: function() {
            this.element.dropslide('destroy');
        },

        /* UI private methods */

        _createButton: function(i, format, className) {
            var o  = format && $.format(format, i) || i;
            var cn = className && 'ui-timepickr '+ className || 'ui-timepickr';
            return $('
').addClass(cn).data('id', i).append($('').text(o));
        },

        _createRow: function(obj, format, className) {
            var row = $('
');
            for (var x in obj) {
                row.append(this._createButton(obj[x], format || false, className || false));
            }
            return row;
        },

        _getRanges12: function(options) {
            var o = [];
            if (options.hours)   { o.push(this._createRow($.range(1, 13),   '{0:0.2d}', 'hour')); }
            if (options.minutes) { o.push(this._createRow(options.rangeMin, '{0:0.2d}', 'minute')); }
            if (options.seconds) { o.push(this._createRow(options.rangeSec, '{0:0.2d}', 'second')); }
            if (options.suffix)  { o.push(this._createRow(options.suffix,   false,      'suffix')); }
            return o;
        },

        _getRanges24: function(options) {
            var o = [];
            o.push(this._createRow(options.prefix, false, 'prefix')); // prefix is required in 24h mode
            if (options.hours)   { o.push(this._createRow($.range(0, 24),   '{0:0.2d}', 'hour')); }
            if (options.minutes) { o.push(this._createRow(options.rangeMin, '{0:0.2d}', 'minute')); }
            if (options.seconds) { o.push(this._createRow(options.rangeSec, '{0:0.2d}', 'second')); }
            return o;
        },

        _buildMenu: function(options) {
            var ranges = options.convention === 24 && this._getRanges24(options) || this._getRanges12(options);
            var menu   = $('');
            //if () {options.convention}
            for (var x in ranges) {
                menu.append(ranges[x]);
            }
            return menu;
        }
    });

    $.ui.timepickr.defaults = {
        convention:  24, // 24, 12
        dropslide:   { trigger: 'focus' },
        format12:    '{h:02.d}:{m:02.d} {suffix:s}',
        format24:    '{h:02.d}:{m:02.d}',
        handle:      false,
        hours:       true,
        minutes:     true,
        seconds:     false,
        prefix:      ['am', 'pm'],
        suffix:      ['am', 'pm'],
        rangeMin:    ['00', '15', '30', '45'],
        rangeSec:    ['00', '15', '30', '45'],
        updateLive:  true,
        resetOnBlur: true,
        val:         false
    };

})(jQuery);
<|endoftext|>


<commit_before>(function() {

   /**
    * Changes value from one to another within certain period of time, invoking callbacks as value is being changed.
    * @memberOf fabric.util
    * @param {Object} [options] Animation options
    * @param {Function} [options.onChange] Callback; invoked on every value change
    * @param {Function} [options.onComplete] Callback; invoked when value change is completed
    * @param {Number} [options.startValue=0] Starting value
    * @param {Number} [options.endValue=100] Ending value
    * @param {Number} [options.byValue=100] Value to modify the property by
    * @param {Function} [options.easing] Easing function
    * @param {Number} [options.duration=500] Duration of change
    */
  function animate(options) {

    options || (options = { });

    var start = +new Date(),
      duration = options.duration || 500,
      finish = start + duration, time,
      onChange = options.onChange || function() { },
      abort = options.abort || function() { return false; },
      easing = options.easing || function(t, b, c, d) {return -c * Math.cos(t/d * (Math.PI/2)) + c + b;},
      startValue = 'startValue' in options ? options.startValue : 0,
      endValue = 'endValue' in options ? options.endValue : 100,
      byValue = options.byValue || endValue - startValue;

    options.onStart && options.onStart();

    (function tick() {
      time = +new Date();
      var currentTime = time > finish ? duration : (time - start);
      if (abort()) {
        options.onComplete && options.onComplete();
        return;
      }
      onChange(easing(currentTime, startValue, byValue, duration));
      if (time > finish) {
        options.onComplete && options.onComplete();
        return;
      }
      requestAnimFrame(tick);
    })();
  }

  var _requestAnimFrame = fabric.window.requestAnimationFrame       ||
                          fabric.window.webkitRequestAnimationFrame ||
                          fabric.window.mozRequestAnimationFrame    ||
                          fabric.window.oRequestAnimationFrame      ||
                          fabric.window.msRequestAnimationFrame     ||
                          function(callback) {
                            fabric.window.setTimeout(callback, 1000 / 60);
                          };
  /**
    * requestAnimationFrame polyfill based on http://paulirish.com/2011/requestanimationframe-for-smart-animating/
    * @memberOf fabric.util
    * @param {Function} callback Callback to invoke
    * @param {DOMElement} element optional Element to associate with animation
    */
  var requestAnimFrame = function() {
    return _requestAnimFrame.apply(fabric.window, arguments);
  };

  fabric.util.animate = animate;
  fabric.util.requestAnimFrame = requestAnimFrame;

})();
<commit_msg>change animate to use sub-millisecond where possible<commit_after>(function() {

  /**
   * Changes value from one to another within certain period of time, invoking callbacks as value is being changed.
   * @memberOf fabric.util
   * @param {Object} [options] Animation options
   * @param {Function} [options.onChange] Callback; invoked on every value change
   * @param {Function} [options.onComplete] Callback; invoked when value change is completed
   * @param {Number} [options.startValue=0] Starting value
   * @param {Number} [options.endValue=100] Ending value
   * @param {Number} [options.byValue=100] Value to modify the property by
   * @param {Function} [options.easing] Easing function
   * @param {Number} [options.duration=500] Duration of change
   */
  function animate(options) {

    requestAnimFrame(function(timestamp) {
      options || (options = { });

      var start = timestamp || +new Date(),
          duration = options.duration || 500,
          finish = start + duration, time,
          onChange = options.onChange || function() { },
          abort = options.abort || function() { return false; },
          easing = options.easing || function(t, b, c, d) {return -c * Math.cos(t/d * (Math.PI/2)) + c + b;},
          startValue = 'startValue' in options ? options.startValue : 0,
          endValue = 'endValue' in options ? options.endValue : 100,
          byValue = options.byValue || endValue - startValue;

      options.onStart && options.onStart();

      (function tick(ticktime) {
        time = ticktime || +new Date();
        var currentTime = time > finish ? duration : (time - start);
        if (abort()) {
          options.onComplete && options.onComplete();
          return;
        }
        onChange(easing(currentTime, startValue, byValue, duration));
        if (time > finish) {
          options.onComplete && options.onComplete();
          return;
        }
        requestAnimFrame(tick);
      })(start);
    });

  }

  var _requestAnimFrame = fabric.window.requestAnimationFrame       ||
      fabric.window.webkitRequestAnimationFrame ||
      fabric.window.mozRequestAnimationFrame    ||
      fabric.window.oRequestAnimationFrame      ||
      fabric.window.msRequestAnimationFrame     ||
      function(callback) {
        fabric.window.setTimeout(callback, 1000 / 60);
      };
  /**
   * requestAnimationFrame polyfill based on http://paulirish.com/2011/requestanimationframe-for-smart-animating/
   * @memberOf fabric.util
   * @param {Function} callback Callback to invoke
   * @param {DOMElement} element optional Element to associate with animation
   */
  var requestAnimFrame = function() {
    return _requestAnimFrame.apply(fabric.window, arguments);
  };

  fabric.util.animate = animate;
  fabric.util.requestAnimFrame = requestAnimFrame;

})();
<|endoftext|>


<commit_before>const chalk = require('chalk')
const { extensions } = require('interpret')
const Liftoff = require('liftoff')

/**
 * Lifts off the module using js-liftoff.
 * @param <T> The type of the module to load
 * @param {string} name The name of the module
 * @param {object} options The options
 * @param {boolean} [options.configIsOptional] True iff the config file is optional. Default is false.
 * @param {boolean} [options.moduleIsOptional] True iff the config file is optional. Default is false.
 * @return {Promise<T>} The module interface
 */
module.exports = (name, options) => {
  options = options || {}

  const logger = console
  const configName = options.configName || `${name}file`

  return new Promise((resolve, reject) => {
    new Liftoff({ name, configName, extensions })

    .on('require', moduleName => { logger.log('Requiring external module', chalk.magenta(moduleName)) })

    .on('requireFail', moduleName => { logger.log(chalk.red(`Failed to load external module ${moduleName}`)) })

    .launch({}, env => {
      if (!options.moduleIsOptional && !env.modulePath) {
        logger.log(chalk.red(`Error: Local ${name} module not found`))
        logger.log('Try running:', chalk.green(`npm install ${name}`))

        process.exit(1)
      }

      let module = null
      if (env.modulePath) {
        module = require(env.modulePath)

        module.setLogger(require('./logger')(name))
      }

      if (options.configIsOptional && !env.configPath) {
        return resolve({ module })
      }

      if (!env.configPath) {
        logger.log(chalk.red(`Error: No ${configName} found`))

        process.exit(1)
      }

      logger.log('Using:', chalk.magenta(env.configPath))

      try {
        const config = require(env.configPath)

        return resolve({ config, module })
      } catch (e) {
        logger.log(chalk.red(e.stack))

        process.exit(1)
      }
    })
  })
}
<commit_msg>fix: call setLogger only when it is a function<commit_after>const chalk = require('chalk')
const { extensions } = require('interpret')
const Liftoff = require('liftoff')

/**
 * Lifts off the module using js-liftoff.
 * @param <T> The type of the module to load
 * @param {string} name The name of the module
 * @param {object} options The options
 * @param {boolean} [options.configIsOptional] True iff the config file is optional. Default is false.
 * @param {boolean} [options.moduleIsOptional] True iff the config file is optional. Default is false.
 * @return {Promise<T>} The module interface
 */
module.exports = (name, options) => {
  options = options || {}

  const logger = console
  const configName = options.configName || `${name}file`

  return new Promise((resolve, reject) => {
    new Liftoff({ name, configName, extensions })

    .on('require', moduleName => { logger.log('Requiring external module', chalk.magenta(moduleName)) })

    .on('requireFail', moduleName => { logger.log(chalk.red(`Failed to load external module ${moduleName}`)) })

    .launch({}, env => {
      if (!options.moduleIsOptional && !env.modulePath) {
        logger.log(chalk.red(`Error: Local ${name} module not found`))
        logger.log('Try running:', chalk.green(`npm install ${name}`))

        process.exit(1)
      }

      let module = null
      if (env.modulePath) {
        module = require(env.modulePath)

        if (typeof module.setLogger === 'function') {
          module.setLogger(require('./logger')(name))
        }
      }

      if (options.configIsOptional && !env.configPath) {
        return resolve({ module })
      }

      if (!env.configPath) {
        logger.log(chalk.red(`Error: No ${configName} found`))

        process.exit(1)
      }

      logger.log('Using:', chalk.magenta(env.configPath))

      try {
        const config = require(env.configPath)

        return resolve({ config, module })
      } catch (e) {
        logger.log(chalk.red(e.stack))

        process.exit(1)
      }
    })
  })
}
<|endoftext|>


<commit_before>const units = ['B', 'kB', 'MB', 'GB', 'TB', 'PB']

export function humanStorageSize (bytes) {
  let u = 0

  while (parseInt(bytes) >= 1024 && u < units.length - 1) {
    bytes /= 1024
    ++u
  }

  return `${bytes.toFixed(1)} ${units[u]}`
}

export function capitalize (str) {
  return str.charAt(0).toUpperCase() + str.slice(1)
}

export function between (v, min, max) {
  if (max <= min) {
    return min
  }
  return Math.min(max, Math.max(min, v))
}

export function normalizeToInterval (v, min, max) {
  if (max <= min) {
    return min
  }

  const size = (max - min + 1)

  let index = v % size
  if (index < min) {
    index = size + index
  }

  return index
}

export function pad (v, length = 2, char = '0') {
  let val = '' + v
  return val.length >= length
    ? val
    : new Array(length - val.length + 1).join(char) + val
}
<commit_msg>fix: Small fix for humanStorageSize<commit_after>const units = ['B', 'kB', 'MB', 'GB', 'TB', 'PB']

export function humanStorageSize (bytes) {
  let u = 0

  while (parseInt(bytes, 10) >= 1024 && u < units.length - 1) {
    bytes /= 1024
    ++u
  }

  return `${bytes.toFixed(1)} ${units[u]}`
}

export function capitalize (str) {
  return str.charAt(0).toUpperCase() + str.slice(1)
}

export function between (v, min, max) {
  if (max <= min) {
    return min
  }
  return Math.min(max, Math.max(min, v))
}

export function normalizeToInterval (v, min, max) {
  if (max <= min) {
    return min
  }

  const size = (max - min + 1)

  let index = v % size
  if (index < min) {
    index = size + index
  }

  return index
}

export function pad (v, length = 2, char = '0') {
  let val = '' + v
  return val.length >= length
    ? val
    : new Array(length - val.length + 1).join(char) + val
}
<|endoftext|>


<commit_before>goog.provide('utils.parser');
goog.require('config');
goog.require('utils.tab');

utils.parser = {};
utils.parser.redmine = {};

/**
 * @param {string} redmineUrl
 * @return {string}
 */
utils.parser.getTicket = function(redmineUrl) {
	var mask = config.redmine.host + '/issues/';
	var pos = redmineUrl.indexOf(mask) + mask.length;
	var ticket = '';
	if (redmineUrl.indexOf(mask) !== 0) {
		ticket = redmineUrl.substr(pos);
	}
	return ticket;
};

/**
 * @param {string} html
 * @return {Array.<string>}
 */
utils.parser.getBranchesFromHTML = function(html) {
	var result;
	var textBlocks = [];
	var exp = /(?:data-branch-name=")(.*)(?:">)/g;

	while (result = exp.exec(html)) {
		textBlocks.push(result[1]);
	}

	return textBlocks;
};

utils.parser.getBranch = function(url) {
	return 'localhost';
};

utils.parser.getPull = function(url) {
	return 'localhost';
};

/**
 * @args {string}
 * @return {string}
 */
utils.parser.joinUrl = function() {
	return Array.prototype.join.call(arguments, '/').replace('//', '/');
};

/**
 * @param {string} url
 * @return {string}
 */
utils.parser.findTicket = function(url) {
	var exp = /(((pull-request|branch).*(hotfix|feature|release)\D*)([0-9]*))/;

	var ticketExp = exp.exec(url);
	return ticketExp && ticketExp[5];
};

/**
 * @deprecated
 * @see utils.parser.redmine.getRedmineProjectId
 * @return {Promise.<string>}
 */
utils.parser.redmine.getProjectId = function() {
	return new Promise(function(resolve, reject) {
		var listener = function(request, sender) {
			if (request.action === 'get-redmine-project-id') {
				chrome.extension.onMessage.removeListener(listener);
				resolve(request.source);
			}
		};

		chrome.extension.onMessage.addListener(listener);
		chrome.tabs.executeScript(null, {file: "/src/injections/get-redmine-project-id.js"}, function() {
			if (chrome.extension.lastError) {
				var message = 'There was an error injecting script : \n' + chrome.extension.lastError.message;
				chrome.extension.onMessage.removeListener(listener);
				reject('error:', message);
			}
		});
	});
};

/**
 * @return {IThenable.<string>}
 */
utils.parser.redmine.getRedmineProjectId = function(redmineUrl) {
	var tab = utils.tab.getChromeTabByUrl(redmineUrl);
	if (tab) {
		return Promise.reject('tab not find');
	}

	return utils.tab.inject(utils.tab.Injections.GET_REDMINE_PROJECT_ID);
};
<commit_msg>Fix *utils.parser.getRedmineProjectId*<commit_after>goog.provide('utils.parser');
goog.require('config');
goog.require('utils.tab');

utils.parser = {};
utils.parser.redmine = {};

/**
 * @param {string} redmineUrl
 * @return {string}
 */
utils.parser.getTicket = function(redmineUrl) {
	var mask = config.redmine.host + '/issues/';
	var pos = redmineUrl.indexOf(mask) + mask.length;
	var ticket = '';
	if (redmineUrl.indexOf(mask) !== 0) {
		ticket = redmineUrl.substr(pos);
	}
	return ticket;
};

/**
 * @param {string} html
 * @return {Array.<string>}
 */
utils.parser.getBranchesFromHTML = function(html) {
	var result;
	var textBlocks = [];
	var exp = /(?:data-branch-name=")(.*)(?:">)/g;

	while (result = exp.exec(html)) {
		textBlocks.push(result[1]);
	}

	return textBlocks;
};

utils.parser.getBranch = function(url) {
	return 'localhost';
};

utils.parser.getPull = function(url) {
	return 'localhost';
};

/**
 * @args {string}
 * @return {string}
 */
utils.parser.joinUrl = function() {
	return Array.prototype.join.call(arguments, '/').replace('//', '/');
};

/**
 * @param {string} url
 * @return {string}
 */
utils.parser.findTicket = function(url) {
	var exp = /(((pull-request|branch).*(hotfix|feature|release)\D*)([0-9]*))/;

	var ticketExp = exp.exec(url);
	return ticketExp && ticketExp[5];
};

/**
 * @deprecated
 * @see utils.parser.getRedmineProjectId
 * @return {Promise.<string>}
 */
utils.parser.redmine.getProjectId = function() {
	return new Promise(function(resolve, reject) {
		var listener = function(request, sender) {
			if (request.action === 'get-redmine-project-id') {
				chrome.extension.onMessage.removeListener(listener);
				resolve(request.source);
			}
		};

		chrome.extension.onMessage.addListener(listener);
		chrome.tabs.executeScript(null, {file: "/src/injections/get-redmine-project-id.js"}, function() {
			if (chrome.extension.lastError) {
				var message = 'There was an error injecting script : \n' + chrome.extension.lastError.message;
				chrome.extension.onMessage.removeListener(listener);
				reject('error:', message);
			}
		});
	});
};

/**
 * @param {string} redmineUrl
 * @return {IThenable.<string>}
 */
utils.parser.getRedmineProjectId = function(redmineUrl) {
	return utils.tab
		.getChromeTabByUrl(redmineUrl)
		.then(function(tab) {
			if (!tab) {
				return Promise.reject('tab not find');
			}

			return utils.tab.inject(utils.tab.Injections.GET_REDMINE_PROJECT_ID, tab);
		});

};
<|endoftext|>


<commit_before>/*
    Computes the size of the Visualization CardText component according to the gridItem
    Arguments:
    * gridItem: the gridItem
    Returns:
        An object with computed { width, height } for passing to visualizations as props.
*/
export const resizeVisualization = (gridItem) => {
    if (!gridItem || gridItem.childNodes.length === 0 || gridItem.childNodes[0].childNodes.length === 0)
        return {
            width: 0,
            height: 0
        };

    const card = gridItem.childNodes[0];
    const innerCard = card.childNodes[0].childNodes;
    const width = card.clientWidth;
    let height = card.clientHeight;

    // Handle the case that the title bar is present.
    if (innerCard.length > 1) {
        height -= innerCard[0].clientHeight;
    }

    return {
        width: width,
        height: height
    };
}
<commit_msg>Computed card height based on title and filters bar<commit_after>/*
    Computes the size of the Visualization CardText component according to the gridItem
    Arguments:
    * gridItem: the gridItem
    Returns:
        An object with computed { width, height } for passing to visualizations as props.
*/
export const resizeVisualization = (gridItem) => {
    if (!gridItem || gridItem.childNodes.length === 0 || gridItem.childNodes[0].childNodes.length === 0)
        return {
            width: 0,
            height: 0
        };

    const card = gridItem.childNodes[0];
    const innerCard = card.childNodes[0].childNodes;
    const width = card.clientWidth;
    let height = card.clientHeight;

    // Handle the case that the title bar is present.
    if (innerCard.length > 1) {

        for (var i = 0; i < innerCard.length - 1; i++)
            height -= innerCard[i].clientHeight;
    }

    return {
        width: width,
        height: height
    };
}
<|endoftext|>


<commit_before>const combinePaths = (...paths) => {
  return paths.join('/').replace(/\/+/g, '/');
}

const flattenTabNestedRoutes = (pageRoute, tabRoute, tabNestedRoutes) => {
	return tabNestedRoutes.map(tabNestedRoute => {
    return {
      path: combinePaths(pageRoute.path, tabRoute.path, tabNestedRoute.path),
      pagePath: pageRoute.path,
      component: pageRoute.component,
      tab: {
        tabId: tabRoute.tabId,
        component: tabNestedRoute.component
      }
    }
	});
};

const flattenTabRoutes = (pageRoute, tabRoutes) => {
	return tabRoutes.reduce((accumulatedFlattenedRoutes, nextTabRoute) => {
		let flattenedTabRoutes;

		if (nextTabRoute.routes) {
			flattenedTabRoutes = flattenTabNestedRoutes(pageRoute, nextTabRoute, nextTabRoute.routes);
		} else {
			flattenedTabRoutes = [{
        path: combinePaths(pageRoute.path, nextTabRoute.path),
        pagePath: pageRoute.path,
				component: pageRoute.component,
				tab: {
					tabId: nextTabRoute.tabId,
					component: nextTabRoute.component
				}
			}];
		}

		return  [
			...accumulatedFlattenedRoutes,
			...flattenedTabRoutes
		];
	}, []);
};

const flattenRoutes = (routes = []) => {
	return routes.reduce((accumulatedFlattenedRoutes, nextRoute) => {
		let flattenedNextRoute;

		if (nextRoute.tabs) {
			flattenedNextRoute = flattenTabRoutes(nextRoute, nextRoute.tabs);
		} else {
			flattenedNextRoute = [Object.assign({}, nextRoute, {
        pagePath: nextRoute.path
      })];
		}

		return [
			...accumulatedFlattenedRoutes,
			...flattenedNextRoute
		];
	}, []);
};

const parseRoute = str => {
  var parts = [];
  str.split('/').forEach(function (part) {
    if (part !== '') {
      if (part.indexOf(':') === 0) {
        parts.push({name: part.replace(':', '')});
      }
      else parts.push(part);
    }
  });
  return parts;
}

function handleRouteChangeFromFramework7(view, options, changeRouteCallback) {
  if (!view.allowPageChange) return false;

  var url = options.url;
  var pageElement = options.pageElement;

  if (url && pageElement || !url || url === '#') {
    return true;
  }

  var inHistory = view.history.indexOf(url) >= 0;
  var inDomCache = view.pagesCache[url];

  if (inHistory && inDomCache) return true;

  return changeRouteCallback(url, view, options);
}

export default class Framework7Router {
  constructor(originalRoutes, framework7, dom7) {
    this.routeChangeHandler = null;
    this.routes = flattenRoutes(originalRoutes);
    this.framework7 = framework7;
    this.dom7 = dom7;

    //Hook router into Framework7 routing events
    const initialPreroute = framework7.params.preroute;

    framework7.params.routes = originalRoutes;
    framework7.params.routerRemoveTimeout = true;
    framework7.params.preroute = (view, options) => {
      var passToVueRouter = true;

      if (initialPreroute && !options.pageElement) {
        passToVueRouter = initialPreroute(view, options);
      }
      if (passToVueRouter) {
        return handleRouteChangeFromFramework7(view, options, this.changeRoute.bind(this));
      } else {
        return false;
      }
    };
  }

  setRouteChangeHandler(routeChangeHandler) {
    this.routeChangeHandler = routeChangeHandler;
  }

  changeRoute(url, view = null, options) {
    const getMainView = () => this.framework7.views && this.framework7.views.reduce((mainView, nextView) => {
        if (nextView.main) {
            return nextView;
        } else {
            return mainView;
        }
    }, null);

    const matchingRoute = this.findMatchingRoute(url);

    if (!matchingRoute) return true;

    return this.routeChangeHandler(
      Object.assign({}, matchingRoute, {
        view: view || getMainView(),
        options,
        router: this
      })
    );
  }

  findMatchingRoute(url) {
    var matchingRoute;
    if (!url) return matchingRoute;

    var routes = this.routes;
    var query = this.dom7.parseUrlQuery(url);
    var hash = url.split('#')[1];
    var params = {};
    var path = url.split('#')[0].split('?')[0];
    var urlParts = path.split('/').filter(function (part) {
      if (part !== '') return part;
    });

    var i, j, k;
    for (i = 0; i < routes.length; i++) {
      if (matchingRoute) continue;
      var route = routes[i];
      var parsedRoute = parseRoute(route.path);
      if (parsedRoute.length !== urlParts.length) continue;
      var matchedParts = 0;
      for (j = 0; j < parsedRoute.length; j++) {
          if (typeof parsedRoute[j] === 'string' && urlParts[j] === parsedRoute[j]) matchedParts ++;
          if (typeof parsedRoute[j] === 'object') {
            params[parsedRoute[j].name] = urlParts[j];
            matchedParts ++;
          }
      }
      if (matchedParts === urlParts.length) {
        matchingRoute = {
          query: query,
          hash: hash,
          params: params,
          url: url,
          path: path,
          route: route
        };
      }
    }
    return matchingRoute;
  }
}
<commit_msg>Fixes edge case<commit_after>const combinePaths = (...paths) => {
  return paths.join('/').replace(/\/+/g, '/');
}

const flattenTabNestedRoutes = (pageRoute, tabRoute, tabNestedRoutes) => {
	return tabNestedRoutes.map(tabNestedRoute => {
    return {
      path: combinePaths(pageRoute.path, tabRoute.path, tabNestedRoute.path),
      pagePath: pageRoute.path,
      component: pageRoute.component,
      tab: {
        tabId: tabRoute.tabId,
        component: tabNestedRoute.component
      }
    }
	});
};

const flattenTabRoutes = (pageRoute, tabRoutes) => {
	return tabRoutes.reduce((accumulatedFlattenedRoutes, nextTabRoute) => {
		let flattenedTabRoutes;

		if (nextTabRoute.routes) {
			flattenedTabRoutes = flattenTabNestedRoutes(pageRoute, nextTabRoute, nextTabRoute.routes);
		} else {
			flattenedTabRoutes = [{
        path: combinePaths(pageRoute.path, nextTabRoute.path),
        pagePath: pageRoute.path,
				component: pageRoute.component,
				tab: {
					tabId: nextTabRoute.tabId,
					component: nextTabRoute.component
				}
			}];
		}

		return  [
			...accumulatedFlattenedRoutes,
			...flattenedTabRoutes
		];
	}, []);
};

const flattenRoutes = (routes = []) => {
	return routes.reduce((accumulatedFlattenedRoutes, nextRoute) => {
		let flattenedNextRoute;

		if (nextRoute.tabs) {
			flattenedNextRoute = flattenTabRoutes(nextRoute, nextRoute.tabs);
		} else {
			flattenedNextRoute = [Object.assign({}, nextRoute, {
        pagePath: nextRoute.path
      })];
		}

		return [
			...accumulatedFlattenedRoutes,
			...flattenedNextRoute
		];
	}, []);
};

const parseRoute = str => {
  var parts = [];
  str.split('/').forEach(function (part) {
    if (part !== '') {
      if (part.indexOf(':') === 0) {
        parts.push({name: part.replace(':', '')});
      }
      else parts.push(part);
    }
  });
  return parts;
}

function handleRouteChangeFromFramework7(view, options, changeRouteCallback) {
  if (!view.allowPageChange) return false;

  var url = options.url;
  var pageElement = options.pageElement;

  if (url && pageElement || !url || url === '#') {
    return true;
  }

  var inHistory = view.history.indexOf(url) >= 0;
  var inDomCache = view.pagesCache[url];

  if (inHistory && inDomCache) return true;

  return changeRouteCallback(url, view, options);
}

export default class Framework7Router {
  constructor(originalRoutes, framework7, dom7) {
    this.routeChangeHandler = null;
    this.routes = flattenRoutes(originalRoutes);
    this.framework7 = framework7;
    this.dom7 = dom7;

    //Hook router into Framework7 routing events
    const initialPreroute = framework7.params.preroute;

    framework7.params.routes = originalRoutes;
    framework7.params.routerRemoveTimeout = true;
    framework7.params.preroute = (view, options) => {
      var passToVueRouter = true;

      if (initialPreroute && !options.pageElement) {
        passToVueRouter = initialPreroute(view, options);
      }
      if (passToVueRouter) {
        return handleRouteChangeFromFramework7(view, options, this.changeRoute.bind(this));
      } else {
        return false;
      }
    };
  }

  setRouteChangeHandler(routeChangeHandler) {
    this.routeChangeHandler = routeChangeHandler;
  }

  changeRoute(url, view = null, options) {
    const getMainView = () => this.framework7.views && this.framework7.views.reduce((mainView, nextView) => {
        if (nextView.main) {
            return nextView;
        } else {
            return mainView;
        }
    }, null);

    const matchingRoute = this.findMatchingRoute(url);

    if (!matchingRoute) return true;

    return this.routeChangeHandler(
      Object.assign({}, matchingRoute, {
        view: view || getMainView(),
        options,
        router: this
      })
    );
  }

  findMatchingRoute(url) {
    var matchingRoute;
    if (!url) return matchingRoute;
    url = ""+url; //Insures that the url is of type string so url.split does not crash app in weird situations.

    var routes = this.routes;
    var query = this.dom7.parseUrlQuery(url);
    var hash = url.split('#')[1];
    var params = {};
    var path = url.split('#')[0].split('?')[0];
    var urlParts = path.split('/').filter(function (part) {
      if (part !== '') return part;
    });

    var i, j, k;
    for (i = 0; i < routes.length; i++) {
      if (matchingRoute) continue;
      var route = routes[i];
      var parsedRoute = parseRoute(route.path);
      if (parsedRoute.length !== urlParts.length) continue;
      var matchedParts = 0;
      for (j = 0; j < parsedRoute.length; j++) {
          if (typeof parsedRoute[j] === 'string' && urlParts[j] === parsedRoute[j]) matchedParts ++;
          if (typeof parsedRoute[j] === 'object') {
            params[parsedRoute[j].name] = urlParts[j];
            matchedParts ++;
          }
      }
      if (matchedParts === urlParts.length) {
        matchingRoute = {
          query: query,
          hash: hash,
          params: params,
          url: url,
          path: path,
          route: route
        };
      }
    }
    return matchingRoute;
  }
}
<|endoftext|>


<commit_before>import remote from "remote"
import Screen from "screen"

var saveDims = function () {
  window.localStorage.setItem("windowDimensions", JSON.stringify({
    x: window.screenX,
    y: window.screenY,
    width: window.outerWidth,
    height: window.outerHeight,
    maximized: remote.getCurrentWindow().isMaximized()
  }))
}

export default function initWindow() {
  window.addEventListener("unload", saveDims)
  window.addEventListener("resize", saveDims)

  var dims = JSON.parse(window.localStorage.getItem("windowDimensions"))

  if (dims) {
    if (dims.maximized) {
      remote.getCurrentWindow().maximize()
    } else {
      window.resizeTo(dims.width, dims.height)
      window.moveTo(dims.x, dims.y)
    }
  }

  remote.getCurrentWindow().show()
}
<commit_msg>Fix initial window sizing for Linux<commit_after>import remote from "remote"
import Screen from "screen"

var saveDims = function () {
  window.localStorage.setItem("windowDimensions", JSON.stringify({
    x: window.screenX,
    y: window.screenY,
    width: window.outerWidth,
    height: window.outerHeight,
    maximized: remote.getCurrentWindow().isMaximized()
  }))
}

export default function initWindow() {
  window.addEventListener("unload", saveDims)
  window.addEventListener("resize", saveDims)

  var dims = JSON.parse(window.localStorage.getItem("windowDimensions"))

  if (dims) {
    if (dims.maximized === "true") {
      remote.getCurrentWindow().show()
      remote.getCurrentWindow().maximize()
    } else {
      window.resizeTo(dims.width, dims.height)
      window.moveTo(dims.x, dims.y)
    }
  }

  remote.getCurrentWindow().show()
}
<|endoftext|>


<commit_before>/*
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2017 Vector Creations Ltd
Copyright 2018 New Vector Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Require common CSS here; this will make webpack process it into bundle.css.
// Our own CSS (which is themed) is imported via separate webpack entry points
// in webpack.config.js
require('gemini-scrollbar/gemini-scrollbar.css');
require('gfm.css/gfm.css');
require('highlight.js/styles/github.css');
require('draft-js/dist/Draft.css');

import React from 'react';
// add React and ReactPerf to the global namespace, to make them easier to
// access via the console
global.React = React;
if (process.env.NODE_ENV !== 'production') {
    global.Perf = require('react-addons-perf');
}

import RunModernizrTests from './modernizr'; // this side-effects a global
import ReactDOM from 'react-dom';
import sdk from 'matrix-react-sdk';
import PlatformPeg from 'matrix-react-sdk/lib/PlatformPeg';
sdk.loadSkin(require('../component-index'));
import VectorConferenceHandler from 'matrix-react-sdk/lib/VectorConferenceHandler';
import Promise from 'bluebird';
import request from 'browser-request';
import * as languageHandler from 'matrix-react-sdk/lib/languageHandler';
// Also import _t directly so we can call it just `_t` as this is what gen-i18n.js expects
import { _t } from 'matrix-react-sdk/lib/languageHandler';

import url from 'url';

import {parseQs, parseQsFromFragment} from './url_utils';
import Platform from './platform';

import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg';
import SettingsStore, {SettingLevel} from "matrix-react-sdk/lib/settings/SettingsStore";
import Tinter from 'matrix-react-sdk/lib/Tinter';
import SdkConfig from "matrix-react-sdk/lib/SdkConfig";

import rageshake from "matrix-react-sdk/lib/rageshake/rageshake";

import CallHandler from 'matrix-react-sdk/lib/CallHandler';

import {getVectorConfig} from './getconfig';

let lastLocationHashSet = null;

function initRageshake() {
    rageshake.init().then(() => {
        console.log("Initialised rageshake: See https://bugs.chromium.org/p/chromium/issues/detail?id=583193 to fix line numbers on Chrome.");

        window.addEventListener('beforeunload', (e) => {
            console.log('riot-web closing');
            // try to flush the logs to indexeddb
            rageshake.flush();
        });

        rageshake.cleanup();
    }, (err) => {
        console.error("Failed to initialise rageshake: " + err);
    });
}

function checkBrowserFeatures(featureList) {
    if (!window.Modernizr) {
        console.error("Cannot check features - Modernizr global is missing.");
        return false;
    }
    var featureComplete = true;
    for (var i = 0; i < featureList.length; i++) {
        if (window.Modernizr[featureList[i]] === undefined) {
            console.error(
                "Looked for feature '%s' but Modernizr has no results for this. " +
                "Has it been configured correctly?", featureList[i]
            );
            return false;
        }
        if (window.Modernizr[featureList[i]] === false) {
            console.error("Browser missing feature: '%s'", featureList[i]);
            // toggle flag rather than return early so we log all missing features
            // rather than just the first.
            featureComplete = false;
        }
    }
    return featureComplete;
}

// Parse the given window.location and return parameters that can be used when calling
// MatrixChat.showScreen(screen, params)
function getScreenFromLocation(location) {
    const fragparts = parseQsFromFragment(location);
    return {
        screen: fragparts.location.substring(1),
        params: fragparts.params,
    }
}

// Here, we do some crude URL analysis to allow
// deep-linking.
function routeUrl(location) {
    if (!window.matrixChat) return;

    console.log("Routing URL ", location.href);
    const s = getScreenFromLocation(location);
    window.matrixChat.showScreen(s.screen, s.params);
}

function onHashChange(ev) {
    if (decodeURIComponent(window.location.hash) == lastLocationHashSet) {
        // we just set this: no need to route it!
        return;
    }
    routeUrl(window.location);
}

// This will be called whenever the SDK changes screens,
// so a web page can update the URL bar appropriately.
function onNewScreen(screen) {
    console.log("newscreen "+screen);
    var hash = '#/' + screen;
    lastLocationHashSet = hash;
    window.location.hash = hash;
};

// We use this to work out what URL the SDK should
// pass through when registering to allow the user to
// click back to the client having registered.
// It's up to us to recognise if we're loaded with
// this URL and tell MatrixClient to resume registration.
//
// If we're in electron, we should never pass through a file:// URL otherwise
// the identity server will try to 302 the browser to it, which breaks horribly.
// so in that instance, hardcode to use riot.im/app for now instead.
function makeRegistrationUrl(params) {
    let url;
    if (window.location.protocol === "file:") {
        url = 'https://riot.im/app/#/register';
    } else {
        url = (
            window.location.protocol + '//' +
            window.location.host +
            window.location.pathname +
            '#/register'
        );
    }

    const keys = Object.keys(params);
    for (let i = 0; i < keys.length; ++i) {
        if (i == 0) {
            url += '?';
        } else {
            url += '&';
        }
        const k = keys[i];
        url += k + '=' + encodeURIComponent(params[k]);
    }
    return url;
}

function getConfig(configJsonFilename) {
    let deferred = Promise.defer();

    request(
        { method: "GET", url: configJsonFilename },
        (err, response, body) => {
            if (err || response.status < 200 || response.status >= 300) {
                // Lack of a config isn't an error, we should
                // just use the defaults.
                // Also treat a blank config as no config, assuming
                // the status code is 0, because we don't get 404s
                // from file: URIs so this is the only way we can
                // not fail if the file doesn't exist when loading
                // from a file:// URI.
                if (response) {
                    if (response.status == 404 || (response.status == 0 && body == '')) {
                        deferred.resolve({});
                    }
                }
                deferred.reject({err: err, response: response});
                return;
            }

            // We parse the JSON ourselves rather than use the JSON
            // parameter, since this throws a parse error on empty
            // which breaks if there's no config.json and we're
            // loading from the filesystem (see above).
            deferred.resolve(JSON.parse(body));
        }
    );

    return deferred.promise;
}

function onTokenLoginCompleted() {
    // if we did a token login, we're now left with the token, hs and is
    // url as query params in the url; a little nasty but let's redirect to
    // clear them.
    var parsedUrl = url.parse(window.location.href);
    parsedUrl.search = "";
    var formatted = url.format(parsedUrl);
    console.log("Redirecting to " + formatted + " to drop loginToken " +
                "from queryparams");
    window.location.href = formatted;
}

async function loadApp() {
    initRageshake();
    MatrixClientPeg.setIndexedDbWorkerScript(window.vector_indexeddb_worker_script);
    CallHandler.setConferenceHandler(VectorConferenceHandler);

    window.addEventListener('hashchange', onHashChange);

    await loadLanguage();

    const fragparts = parseQsFromFragment(window.location);
    const params = parseQs(window.location);

    // set the platform for react sdk (our Platform object automatically picks the right one)
    PlatformPeg.set(new Platform());

    // Load the config file. First try to load up a domain-specific config of the
    // form "config.$domain.json" and if that fails, fall back to config.json.
    let configJson;
    let configError;
    try {
        configJson = await getVectorConfig();
    } catch (e) {
        configError = e;
    }

    // XXX: We call this twice, once here and once in MatrixChat as a prop. We call it here to ensure
    // granular settings are loaded correctly and to avoid duplicating the override logic for the theme.
    SdkConfig.put(configJson);

    // don't try to redirect to the native apps if we're
    // verifying a 3pid (but after we've loaded the config)
    const preventRedirect = Boolean(fragparts.params.client_secret);

    if (!preventRedirect) {
        const isIos = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
        const isAndroid = /Android/.test(navigator.userAgent);
        if (isIos || isAndroid) {
            if (!document.cookie.split(';').some((c) => c.startsWith('mobile_redirect_to_guide'))) {
                window.location = "mobile_guide/";
                return;
            }
        }
    }

    // as quickly as we possibly can, set a default theme...
    const styleElements = Object.create(null);
    let a;
    const theme = SettingsStore.getValue("theme");
    for (let i = 0; (a = document.getElementsByTagName("link")[i]); i++) {
        const href = a.getAttribute("href");
        if (!href) continue;
        // shouldn't we be using the 'title' tag rather than the href?
        const match = href.match(/^bundles\/.*\/theme-(.*)\.css$/);
        if (match) {
            if (match[1] === theme) {
                // remove the disabled flag off the stylesheet

                // Firefox requires setting the attribute to false, so do
                // that instead of removing it. Related:
                // https://bugzilla.mozilla.org/show_bug.cgi?id=1281135
                a.disabled = false;

                // in case the Tinter.tint() in MatrixChat fires before the
                // CSS has actually loaded (which in practice happens)...

                // FIXME: we should probably block loading the app or even
                // showing a spinner until the theme is loaded, to avoid
                // flashes of unstyled content.
                a.onload = () => {
                    Tinter.setTheme(theme);
                };
            } else {
                // Firefox requires this to not be done via `setAttribute`
                // or via HTML.
                // https://bugzilla.mozilla.org/show_bug.cgi?id=1281135
                a.disabled = true;
            }
        }
    }

    const validBrowser = checkBrowserFeatures([
        "displaytable", "flexbox", "es5object", "es5function", "localstorage",
        "objectfit", "indexeddb", "webworkers",
    ]);

    const acceptInvalidBrowser = window.localStorage && window.localStorage.getItem('mx_accepts_unsupported_browser');

    console.log("Vector starting at "+window.location);
    if (configError) {
        window.matrixChat = ReactDOM.render(<div className="error">
            Unable to load config file: please refresh the page to try again.
        </div>, document.getElementById('matrixchat'));
    } else if (validBrowser || acceptInvalidBrowser) {
        const platform = PlatformPeg.get();
        platform.startUpdater();

        const MatrixChat = sdk.getComponent('structures.MatrixChat');
        window.matrixChat = ReactDOM.render(
            <MatrixChat
                onNewScreen={onNewScreen}
                makeRegistrationUrl={makeRegistrationUrl}
                ConferenceHandler={VectorConferenceHandler}
                config={configJson}
                realQueryParams={params}
                startingFragmentQueryParams={fragparts.params}
                enableGuest={!configJson.disable_guests}
                onTokenLoginCompleted={onTokenLoginCompleted}
                initialScreenAfterLogin={getScreenFromLocation(window.location)}
                defaultDeviceDisplayName={platform.getDefaultDeviceDisplayName()}
            />,
            document.getElementById('matrixchat')
        );
    } else {
        console.error("Browser is missing required features.");
        // take to a different landing page to AWOOOOOGA at the user
        var CompatibilityPage = sdk.getComponent("structures.CompatibilityPage");
        window.matrixChat = ReactDOM.render(
            <CompatibilityPage onAccept={function() {
                if (window.localStorage) window.localStorage.setItem('mx_accepts_unsupported_browser', true);
                console.log("User accepts the compatibility risks.");
                loadApp();
            }} />,
            document.getElementById('matrixchat')
        );
    }
}

async function loadLanguage() {
    const prefLang = SettingsStore.getValue("language", null, /*excludeDefault=*/true);
    let langs = [];

    if (!prefLang) {
        languageHandler.getLanguagesFromBrowser().forEach((l) => {
            langs.push(...languageHandler.getNormalizedLanguageKeys(l));
        });
    } else {
        langs = [prefLang];
    }
    try {
        await languageHandler.setLanguage(langs);
        document.documentElement.setAttribute("lang", languageHandler.getCurrentLanguage());
    } catch (e) {
        console.error("Unable to set language", e);
    }
}

loadApp();
<commit_msg>Don't show mobile guide if deep linking<commit_after>/*
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2017 Vector Creations Ltd
Copyright 2018 New Vector Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Require common CSS here; this will make webpack process it into bundle.css.
// Our own CSS (which is themed) is imported via separate webpack entry points
// in webpack.config.js
require('gemini-scrollbar/gemini-scrollbar.css');
require('gfm.css/gfm.css');
require('highlight.js/styles/github.css');
require('draft-js/dist/Draft.css');

import React from 'react';
// add React and ReactPerf to the global namespace, to make them easier to
// access via the console
global.React = React;
if (process.env.NODE_ENV !== 'production') {
    global.Perf = require('react-addons-perf');
}

import RunModernizrTests from './modernizr'; // this side-effects a global
import ReactDOM from 'react-dom';
import sdk from 'matrix-react-sdk';
import PlatformPeg from 'matrix-react-sdk/lib/PlatformPeg';
sdk.loadSkin(require('../component-index'));
import VectorConferenceHandler from 'matrix-react-sdk/lib/VectorConferenceHandler';
import Promise from 'bluebird';
import request from 'browser-request';
import * as languageHandler from 'matrix-react-sdk/lib/languageHandler';
// Also import _t directly so we can call it just `_t` as this is what gen-i18n.js expects
import { _t } from 'matrix-react-sdk/lib/languageHandler';

import url from 'url';

import {parseQs, parseQsFromFragment} from './url_utils';
import Platform from './platform';

import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg';
import SettingsStore, {SettingLevel} from "matrix-react-sdk/lib/settings/SettingsStore";
import Tinter from 'matrix-react-sdk/lib/Tinter';
import SdkConfig from "matrix-react-sdk/lib/SdkConfig";

import rageshake from "matrix-react-sdk/lib/rageshake/rageshake";

import CallHandler from 'matrix-react-sdk/lib/CallHandler';

import {getVectorConfig} from './getconfig';

let lastLocationHashSet = null;

function initRageshake() {
    rageshake.init().then(() => {
        console.log("Initialised rageshake: See https://bugs.chromium.org/p/chromium/issues/detail?id=583193 to fix line numbers on Chrome.");

        window.addEventListener('beforeunload', (e) => {
            console.log('riot-web closing');
            // try to flush the logs to indexeddb
            rageshake.flush();
        });

        rageshake.cleanup();
    }, (err) => {
        console.error("Failed to initialise rageshake: " + err);
    });
}

function checkBrowserFeatures(featureList) {
    if (!window.Modernizr) {
        console.error("Cannot check features - Modernizr global is missing.");
        return false;
    }
    var featureComplete = true;
    for (var i = 0; i < featureList.length; i++) {
        if (window.Modernizr[featureList[i]] === undefined) {
            console.error(
                "Looked for feature '%s' but Modernizr has no results for this. " +
                "Has it been configured correctly?", featureList[i]
            );
            return false;
        }
        if (window.Modernizr[featureList[i]] === false) {
            console.error("Browser missing feature: '%s'", featureList[i]);
            // toggle flag rather than return early so we log all missing features
            // rather than just the first.
            featureComplete = false;
        }
    }
    return featureComplete;
}

// Parse the given window.location and return parameters that can be used when calling
// MatrixChat.showScreen(screen, params)
function getScreenFromLocation(location) {
    const fragparts = parseQsFromFragment(location);
    return {
        screen: fragparts.location.substring(1),
        params: fragparts.params,
    }
}

// Here, we do some crude URL analysis to allow
// deep-linking.
function routeUrl(location) {
    if (!window.matrixChat) return;

    console.log("Routing URL ", location.href);
    const s = getScreenFromLocation(location);
    window.matrixChat.showScreen(s.screen, s.params);
}

function onHashChange(ev) {
    if (decodeURIComponent(window.location.hash) == lastLocationHashSet) {
        // we just set this: no need to route it!
        return;
    }
    routeUrl(window.location);
}

// This will be called whenever the SDK changes screens,
// so a web page can update the URL bar appropriately.
function onNewScreen(screen) {
    console.log("newscreen "+screen);
    var hash = '#/' + screen;
    lastLocationHashSet = hash;
    window.location.hash = hash;
};

// We use this to work out what URL the SDK should
// pass through when registering to allow the user to
// click back to the client having registered.
// It's up to us to recognise if we're loaded with
// this URL and tell MatrixClient to resume registration.
//
// If we're in electron, we should never pass through a file:// URL otherwise
// the identity server will try to 302 the browser to it, which breaks horribly.
// so in that instance, hardcode to use riot.im/app for now instead.
function makeRegistrationUrl(params) {
    let url;
    if (window.location.protocol === "file:") {
        url = 'https://riot.im/app/#/register';
    } else {
        url = (
            window.location.protocol + '//' +
            window.location.host +
            window.location.pathname +
            '#/register'
        );
    }

    const keys = Object.keys(params);
    for (let i = 0; i < keys.length; ++i) {
        if (i == 0) {
            url += '?';
        } else {
            url += '&';
        }
        const k = keys[i];
        url += k + '=' + encodeURIComponent(params[k]);
    }
    return url;
}

function getConfig(configJsonFilename) {
    let deferred = Promise.defer();

    request(
        { method: "GET", url: configJsonFilename },
        (err, response, body) => {
            if (err || response.status < 200 || response.status >= 300) {
                // Lack of a config isn't an error, we should
                // just use the defaults.
                // Also treat a blank config as no config, assuming
                // the status code is 0, because we don't get 404s
                // from file: URIs so this is the only way we can
                // not fail if the file doesn't exist when loading
                // from a file:// URI.
                if (response) {
                    if (response.status == 404 || (response.status == 0 && body == '')) {
                        deferred.resolve({});
                    }
                }
                deferred.reject({err: err, response: response});
                return;
            }

            // We parse the JSON ourselves rather than use the JSON
            // parameter, since this throws a parse error on empty
            // which breaks if there's no config.json and we're
            // loading from the filesystem (see above).
            deferred.resolve(JSON.parse(body));
        }
    );

    return deferred.promise;
}

function onTokenLoginCompleted() {
    // if we did a token login, we're now left with the token, hs and is
    // url as query params in the url; a little nasty but let's redirect to
    // clear them.
    var parsedUrl = url.parse(window.location.href);
    parsedUrl.search = "";
    var formatted = url.format(parsedUrl);
    console.log("Redirecting to " + formatted + " to drop loginToken " +
                "from queryparams");
    window.location.href = formatted;
}

async function loadApp() {
    initRageshake();
    MatrixClientPeg.setIndexedDbWorkerScript(window.vector_indexeddb_worker_script);
    CallHandler.setConferenceHandler(VectorConferenceHandler);

    window.addEventListener('hashchange', onHashChange);

    await loadLanguage();

    const fragparts = parseQsFromFragment(window.location);
    const params = parseQs(window.location);

    // set the platform for react sdk (our Platform object automatically picks the right one)
    PlatformPeg.set(new Platform());

    // Load the config file. First try to load up a domain-specific config of the
    // form "config.$domain.json" and if that fails, fall back to config.json.
    let configJson;
    let configError;
    try {
        configJson = await getVectorConfig();
    } catch (e) {
        configError = e;
    }

    // XXX: We call this twice, once here and once in MatrixChat as a prop. We call it here to ensure
    // granular settings are loaded correctly and to avoid duplicating the override logic for the theme.
    SdkConfig.put(configJson);

    // don't try to redirect to the native apps if we're
    // verifying a 3pid (but after we've loaded the config)
    // or if the user is following a deep link
    // (https://github.com/vector-im/riot-web/issues/7378)
    const preventRedirect = fragparts.params.client_secret || fragparts.location.length > 0;

    if (!preventRedirect) {
        const isIos = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
        const isAndroid = /Android/.test(navigator.userAgent);
        if (isIos || isAndroid) {
            if (!document.cookie.split(';').some((c) => c.startsWith('mobile_redirect_to_guide'))) {
                window.location = "mobile_guide/";
                return;
            }
        }
    }

    // as quickly as we possibly can, set a default theme...
    const styleElements = Object.create(null);
    let a;
    const theme = SettingsStore.getValue("theme");
    for (let i = 0; (a = document.getElementsByTagName("link")[i]); i++) {
        const href = a.getAttribute("href");
        if (!href) continue;
        // shouldn't we be using the 'title' tag rather than the href?
        const match = href.match(/^bundles\/.*\/theme-(.*)\.css$/);
        if (match) {
            if (match[1] === theme) {
                // remove the disabled flag off the stylesheet

                // Firefox requires setting the attribute to false, so do
                // that instead of removing it. Related:
                // https://bugzilla.mozilla.org/show_bug.cgi?id=1281135
                a.disabled = false;

                // in case the Tinter.tint() in MatrixChat fires before the
                // CSS has actually loaded (which in practice happens)...

                // FIXME: we should probably block loading the app or even
                // showing a spinner until the theme is loaded, to avoid
                // flashes of unstyled content.
                a.onload = () => {
                    Tinter.setTheme(theme);
                };
            } else {
                // Firefox requires this to not be done via `setAttribute`
                // or via HTML.
                // https://bugzilla.mozilla.org/show_bug.cgi?id=1281135
                a.disabled = true;
            }
        }
    }

    const validBrowser = checkBrowserFeatures([
        "displaytable", "flexbox", "es5object", "es5function", "localstorage",
        "objectfit", "indexeddb", "webworkers",
    ]);

    const acceptInvalidBrowser = window.localStorage && window.localStorage.getItem('mx_accepts_unsupported_browser');

    console.log("Vector starting at "+window.location);
    if (configError) {
        window.matrixChat = ReactDOM.render(<div className="error">
            Unable to load config file: please refresh the page to try again.
        </div>, document.getElementById('matrixchat'));
    } else if (validBrowser || acceptInvalidBrowser) {
        const platform = PlatformPeg.get();
        platform.startUpdater();

        const MatrixChat = sdk.getComponent('structures.MatrixChat');
        window.matrixChat = ReactDOM.render(
            <MatrixChat
                onNewScreen={onNewScreen}
                makeRegistrationUrl={makeRegistrationUrl}
                ConferenceHandler={VectorConferenceHandler}
                config={configJson}
                realQueryParams={params}
                startingFragmentQueryParams={fragparts.params}
                enableGuest={!configJson.disable_guests}
                onTokenLoginCompleted={onTokenLoginCompleted}
                initialScreenAfterLogin={getScreenFromLocation(window.location)}
                defaultDeviceDisplayName={platform.getDefaultDeviceDisplayName()}
            />,
            document.getElementById('matrixchat')
        );
    } else {
        console.error("Browser is missing required features.");
        // take to a different landing page to AWOOOOOGA at the user
        var CompatibilityPage = sdk.getComponent("structures.CompatibilityPage");
        window.matrixChat = ReactDOM.render(
            <CompatibilityPage onAccept={function() {
                if (window.localStorage) window.localStorage.setItem('mx_accepts_unsupported_browser', true);
                console.log("User accepts the compatibility risks.");
                loadApp();
            }} />,
            document.getElementById('matrixchat')
        );
    }
}

async function loadLanguage() {
    const prefLang = SettingsStore.getValue("language", null, /*excludeDefault=*/true);
    let langs = [];

    if (!prefLang) {
        languageHandler.getLanguagesFromBrowser().forEach((l) => {
            langs.push(...languageHandler.getNormalizedLanguageKeys(l));
        });
    } else {
        langs = [prefLang];
    }
    try {
        await languageHandler.setLanguage(langs);
        document.documentElement.setAttribute("lang", languageHandler.getCurrentLanguage());
    } catch (e) {
        console.error("Unable to set language", e);
    }
}

loadApp();
<|endoftext|>