<commit_before>var URLUtils = require('URLUtils');
var UI = require('ui');
var ajax = require('ajax');

var getroutes = {
  sortRoutesFcn : function(a, b)
  {
    a = a.rt;
    b = b.rt;

    var retValue = null;

    // console.log(a,b);
    var aIsNum = !isNaN(a);
    var bIsNum = !isNaN(b);
    if (aIsNum && bIsNum)
    {
        retValue = Number(a) - Number(b);
    }
    else
    {
        // one of two formats if NaN
        // letterFirst: <letter><number>
        // numberFirst: <number><letter>
        //
        // letters are only ever one character long
        // numbers can be multiple chars
        var aIsLetterFirst = isNaN(a.substr(0,1));
        var bIsLetterFirst = isNaN(b.substr(0,1));

        var aLetter = '-', bLetter = '-';
        var aNumber = Number(a), bNumber = Number(b);

        if (!aIsNum)
        {
            aNumber = Number(aIsLetterFirst ? a.substr(1) : a.substr(0, a.length-1));
            aLetter = aIsLetterFirst ? a.substr(0,1) : a.substr(a.length-1);
        }

        if (!bIsNum)
        {
            bNumber = Number(bIsLetterFirst ? b.substr(1) : b.substr(0, b.length-1));
            bLetter = bIsLetterFirst ? b.substr(0,1) : b.substr(b.length-1);
        }

        if (!aIsLetterFirst && !bIsLetterFirst) /* numbers first */
        {
            if (a == '61A' && b == '70')
            {
                // debugger;
            }
            if (aNumber == bNumber)
            {
                retValue = aLetter < bLetter ? -1 : 1;
            }
            else
            {
                retValue = aNumber - bNumber;
            }
        }
        else if (!aIsLetterFirst && bIsLetterFirst)
        {
            retValue = -1;
        }
        else if (aIsLetterFirst && !bIsLetterFirst)
        {
            retValue = 1;
        }
        else /* both letters first */
        {
            if (aLetter == bLetter)
            {
                retValue = aNumber - bNumber;
            }
            else
            {
                retValue = aLetter < bLetter ? -1 : 1;
            }
        }
    }
    // console.log(a + ' <-> ' + b + ' = ' + retValue);
    return retValue;
  },

  parseRoutes : function(routes)
  {
    console.log('> sorting...');
    routes.sort(getroutes.sortRoutesFcn);
    console.log('> done sorting!');

    var items = [];
    for (var i=0; i<routes.length; i++)
    {
      var route = routes[i];
      var routeNum = route.rt;
      var routeName = route.rtnm;

      // console.log(routeNum + ' - ' + routeName);

      items.push({
        title:routeNum,
        subtitle:routeName
      });
    }
    return items;
  },
  get : function(onSuccess)
  {
    ajax(
      {
        url: URLUtils.constructURL('getroutes', {}),
        type: 'json'
      },
      function(data)
      {
        console.log('success!');
        var routes = data['bustime-response'].routes;
        var menuItems = getroutes.parseRoutes(routes);

        var resultsMenu = new UI.Menu({
          sections: [{
            title: 'Routes',
            items: menuItems
          }]
        });

        onSuccess(resultsMenu);
      }
    );
  }
};
this.exports = getroutes;
<commit_msg>removing debugging info<commit_after>var URLUtils = require('URLUtils');
var UI = require('ui');
var ajax = require('ajax');

var getroutes = {
  sortRoutesFcn : function(a, b)
  {
    a = a.rt;
    b = b.rt;

    var retValue = null;

    // console.log(a,b);
    var aIsNum = !isNaN(a);
    var bIsNum = !isNaN(b);
    if (aIsNum && bIsNum)
    {
        retValue = Number(a) - Number(b);
    }
    else
    {
        // one of two formats if NaN
        // letterFirst: <letter><number>
        // numberFirst: <number><letter>
        //
        // letters are only ever one character long
        // numbers can be multiple chars
        var aIsLetterFirst = isNaN(a.substr(0,1));
        var bIsLetterFirst = isNaN(b.substr(0,1));

        var aLetter = '-', bLetter = '-';
        var aNumber = Number(a), bNumber = Number(b);

        if (!aIsNum)
        {
            aNumber = Number(aIsLetterFirst ? a.substr(1) : a.substr(0, a.length-1));
            aLetter = aIsLetterFirst ? a.substr(0,1) : a.substr(a.length-1);
        }

        if (!bIsNum)
        {
            bNumber = Number(bIsLetterFirst ? b.substr(1) : b.substr(0, b.length-1));
            bLetter = bIsLetterFirst ? b.substr(0,1) : b.substr(b.length-1);
        }

        if (!aIsLetterFirst && !bIsLetterFirst) /* numbers first */
        {
            if (aNumber == bNumber)
            {
                retValue = aLetter < bLetter ? -1 : 1;
            }
            else
            {
                retValue = aNumber - bNumber;
            }
        }
        else if (!aIsLetterFirst && bIsLetterFirst)
        {
            retValue = -1;
        }
        else if (aIsLetterFirst && !bIsLetterFirst)
        {
            retValue = 1;
        }
        else /* both letters first */
        {
            if (aLetter == bLetter)
            {
                retValue = aNumber - bNumber;
            }
            else
            {
                retValue = aLetter < bLetter ? -1 : 1;
            }
        }
    }
    // console.log(a + ' <-> ' + b + ' = ' + retValue);
    return retValue;
  },

  parseRoutes : function(routes)
  {
    console.log('> sorting...');
    routes.sort(getroutes.sortRoutesFcn);
    console.log('> done sorting!');

    var items = [];
    for (var i=0; i<routes.length; i++)
    {
      var route = routes[i];
      var routeNum = route.rt;
      var routeName = route.rtnm;

      // console.log(routeNum + ' - ' + routeName);

      items.push({
        title:routeNum,
        subtitle:routeName
      });
    }
    return items;
  },
  get : function(onSuccess)
  {
    ajax(
      {
        url: URLUtils.constructURL('getroutes', {}),
        type: 'json'
      },
      function(data)
      {
        console.log('success!');
        var routes = data['bustime-response'].routes;
        var menuItems = getroutes.parseRoutes(routes);

        var resultsMenu = new UI.Menu({
          sections: [{
            title: 'Routes',
            items: menuItems
          }]
        });

        onSuccess(resultsMenu);
      }
    );
  }
};
this.exports = getroutes;
<|endoftext|>


<commit_before>define(
  [
    'knockout',
    'text!./multi-select.html',
		'lodash',
    'less!./multi-select.less',
    'extensions/bindings/multiSelect',
    'databindings/eventListenerBinding',
  ],
  function (ko, view, _) {

    function multiSelectFilter(params) {
			var self = this;

      self.multiple = params.multiple;
      self.options = params.options;
      self.selectedValues = ko.observableArray(params.selectedValues());
      self.selectedValue = params.selectedValue;
      self.selectedTextFormat = params.selectedTextFormat || 'count > 2';

      self.optionVals = ko.computed(() => {
        return params.options().map(opt => opt.value);
      });

      self.optionsText = (val) => params.options().find(opt => opt.value === val).label;

			self.onSelectionComplete = function (data, context, event) {
				// only reset the param's selectedValues if the current selections are different
				if (params.multiple && !_.xor(params.selectedValues(), self.selectedValues()).length == 0) {
					params.selectedValues(self.selectedValues());
				}
			};

    }

    const component = {
      viewModel: multiSelectFilter,
      template: view
    };

    ko.components.register('multi-select', component);

    return component;
  });<commit_msg>Fixes broken New Feature Analysis (#2090)<commit_after>define(
  [
    'knockout',
    'text!./multi-select.html',
		'lodash',
    'less!./multi-select.less',
    'extensions/bindings/multiSelect',
    'databindings/eventListenerBinding',
  ],
  function (ko, view, _) {

    function multiSelectFilter(params) {
			var self = this;

      self.multiple = params.multiple;
      self.options = params.options;
      self.selectedValues = ko.observableArray(params.selectedValues && params.selectedValues());
      self.selectedValue = params.selectedValue;
      self.selectedTextFormat = params.selectedTextFormat || 'count > 2';

      self.optionVals = ko.computed(() => {
        return params.options().map(opt => opt.value);
      });

      self.optionsText = (val) => params.options().find(opt => opt.value === val).label;

			self.onSelectionComplete = function (data, context, event) {
				// only reset the param's selectedValues if the current selections are different
				if (params.multiple && !_.xor(params.selectedValues(), self.selectedValues()).length == 0) {
					params.selectedValues(self.selectedValues());
				}
			};

    }

    const component = {
      viewModel: multiSelectFilter,
      template: view
    };

    ko.components.register('multi-select', component);

    return component;
  });<|endoftext|>


<commit_before>export default {
  label: {
    clear: 'Leeren',
    ok: 'Ok',
    cancel: 'Abbrechen',
    close: 'Schließen',
    set: 'Setzen',
    select: 'Auswählen',
    reset: 'Zurücksetzen',
    remove: 'Löschen',
    update: 'Aktualisieren',
    create: 'Erstellen',
    search: 'Suche',
    filter: 'Filter',
    refresh: 'Aktualisieren'
  },
  date: {
    days: 'Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag'.split('_'),
    daysShort: 'So_Mo_Di_Mi_Do_Fr_Sa'.split('_'),
    months: 'Januar_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember'.split('_'),
    monthsShort: 'Jan_Feb_Mar_Apr_Mai_Jun_Jul_Aug_Sep_Okt_Nov_Dez'.split('_'),
    firstDayOfWeek: 1, // 0-6, 0 - Sunday, 1 Monday, ...
    format24h: true
  },
  pullToRefresh: {
    pull: 'Ziehen zum aktualisieren',
    release: 'Loslassen zum aktualisieren',
    refresh: 'Aktualisiere...'
  },
  table: {
    noData: 'Keine Daten vorhanden.',
    noResults: 'Keine Einträge gefunden',
    loader: 'Lade...',
    selectedRows: rows => rows > 1 ? `${rows} ausgewählte Zeilen` : `${rows === 0 ? 'Keine' : '1'} ausgewahlt.`,
    rowsPerPage: 'Zeilen pro Seite',
    allRows: 'Alle',
    pagination: (start, end, total) => `${start}-${end} von ${total}`,
    columns: 'Spalten'
  },
  editor: {
    url: 'URL',
    bold: 'Fett',
    italic: 'Kursiv',
    strikethrough: 'Durchgestrichen',
    underline: 'Unterstrichen',
    unorderedList: 'Ungeordnete Liste',
    orderedList: 'Geordnete Liste',
    subscript: 'tiefgestellt',
    superscript: 'hochgestellt',
    hyperlink: 'Link',
    toggleFullscreen: 'Vollbild umschalten',
    quote: 'Zitat',
    left: 'linksbündig',
    center: 'zentriert',
    right: 'rechtsbündig',
    justify: 'Ausrichten',
    print: 'Drucken',
    outdent: 'ausrücken',
    indent: 'einrücken',
    removeFormat: 'Entferne Formatierung',
    formatting: 'Formatiere',
    fontSize: 'Schriftgröße',
    align: 'Ausrichten',
    hr: 'Horizontale Linie einfügen',
    undo: 'Rückgänging',
    redo: 'Wiederherstellen',
    header1: 'Überschrift 1',
    header2: 'Überschrift 2',
    header3: 'Überschrift 3',
    header4: 'Überschrift 4',
    header5: 'Überschrift 5',
    header6: 'Überschrift 6',
    paragraph: 'Absatz',
    code: 'Code',
    size1: 'Sehr klein',
    size2: 'klein',
    size3: 'Normal',
    size4: 'Groß',
    size5: 'Größer',
    size6: 'Sehr groß',
    size7: 'Maximum',
    defaultFont: 'Standard Schrift'
  }
}
<commit_msg>Update DE translation<commit_after>export default {
  label: {
    clear: 'Leeren',
    ok: 'Ok',
    cancel: 'Abbrechen',
    close: 'Schließen',
    set: 'Setzen',
    select: 'Auswählen',
    reset: 'Zurücksetzen',
    remove: 'Löschen',
    update: 'Aktualisieren',
    create: 'Erstellen',
    search: 'Suche',
    filter: 'Filter',
    refresh: 'Aktualisieren'
  },
  date: {
    days: 'Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag'.split('_'),
    daysShort: 'So_Mo_Di_Mi_Do_Fr_Sa'.split('_'),
    months: 'Januar_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember'.split('_'),
    monthsShort: 'Jan_Feb_Mar_Apr_Mai_Jun_Jul_Aug_Sep_Okt_Nov_Dez'.split('_'),
    firstDayOfWeek: 1, // 0-6, 0 - Sunday, 1 Monday, ...
    format24h: true
  },
  pullToRefresh: {
    pull: 'Ziehen zum aktualisieren',
    release: 'Loslassen zum aktualisieren',
    refresh: 'Aktualisiere...'
  },
  table: {
    noData: 'Keine Daten vorhanden.',
    noResults: 'Keine Einträge gefunden',
    loader: 'Lade...',
    selectedRows: rows => rows > 1 ? `${rows} ausgewählte Zeilen` : `${rows === 0 ? 'Keine' : '1'} ausgewahlt.`,
    rowsPerPage: 'Zeilen pro Seite',
    allRows: 'Alle',
    pagination: (start, end, total) => `${start}-${end} von ${total}`,
    columns: 'Spalten'
  },
  editor: {
    url: 'URL',
    bold: 'Fett',
    italic: 'Kursiv',
    strikethrough: 'Durchgestrichen',
    underline: 'Unterstrichen',
    unorderedList: 'Ungeordnete Liste',
    orderedList: 'Geordnete Liste',
    subscript: 'tiefgestellt',
    superscript: 'hochgestellt',
    hyperlink: 'Link',
    toggleFullscreen: 'Vollbild umschalten',
    quote: 'Zitat',
    left: 'linksbündig',
    center: 'zentriert',
    right: 'rechtsbündig',
    justify: 'Ausrichten',
    print: 'Drucken',
    outdent: 'ausrücken',
    indent: 'einrücken',
    removeFormat: 'Entferne Formatierung',
    formatting: 'Formatiere',
    fontSize: 'Schriftgröße',
    align: 'Ausrichten',
    hr: 'Horizontale Linie einfügen',
    undo: 'Rückgänging',
    redo: 'Wiederherstellen',
    header1: 'Überschrift 1',
    header2: 'Überschrift 2',
    header3: 'Überschrift 3',
    header4: 'Überschrift 4',
    header5: 'Überschrift 5',
    header6: 'Überschrift 6',
    paragraph: 'Absatz',
    code: 'Code',
    size1: 'Sehr klein',
    size2: 'klein',
    size3: 'Normal',
    size4: 'Groß',
    size5: 'Größer',
    size6: 'Sehr groß',
    size7: 'Maximum',
    defaultFont: 'Standard Schrift'
  },
  tree: {
    noNodes: 'Keine Knoten verfügbar',
    noResults: 'Keine passenden Knoten gefunden'
  }
}
<|endoftext|>


<commit_before>var changed;
var imageSelectorOpen = false;

function changeLessonOnClick(event)
{
	getLesson(event.target.dataset.id);
	return false;
}

function getLesson(id, noHistory)
{
	spinner();
	request("/API/v0.9/lesson/" + id, "GET", "", function(response)
		{
			if(response.status === 200)
			{
				lessonListEvent.addCallback(function()
					{
						showLesson(id, response.response, noHistory);
					});
			}
			else
			{
				dialog("Nastala neznámá chyba. Chybová hláška:
" + result.message, "OK");
			}
		});
}

function showLesson(id, markdown, noHistory)
{
	dismissSpinner();
	changed = false;
	var lesson = {};
	outer:
	for(var i = 0; i < FIELDS.length; i++)
	{
		for(var j = 0; j < FIELDS[i].lessons.length; j++)
		{
			if(FIELDS[i].lessons[j].id == id)
			{
				lesson = FIELDS[i].lessons[j];
				break outer;
			}
		}
	}
	var html = '\
\

\
		Zrušit\

\
	<form>\
		<input type="text" class="formText formName" id="name" value="' + lesson.name + '" autocomplete="off">\
	</form>\

\
		Uložit\

\

\
		Vložit obrázek\

\
\

\

\

\

\

'
	html += '
' + markdown + '

';

	document.getElementsByTagName("main")[0].innerHTML = html;
	refreshPreview(lesson.name, markdown);

	if(!noHistory)
	{
		history.pushState({"id": id}, "title", "/admin/");
	}

	document.getElementById("discard").onclick = discard;
	document.getElementById("save").onclick = save;
	document.getElementById("addImageButton").onclick = showImageSelector;

	var editor = ace.edit("editor");
	editor.setOption("scrollPastEnd", 0.9);
	editor.setTheme("ace/theme/odymaterialy");
	editor.getSession().setMode("ace/mode/markdown");
	editor.getSession().setUseWrapMode(true);
	editor.getSession().on("change", change);
	document.getElementById("name").oninput = change;
	document.getElementById("name").onchange = change;

	getImageSelector();
}

function change()
{
	changed = true;
	refreshPreview(document.getElementById("name").value, ace.edit("editor").getValue());
}

function discard()
{
	if(!changed)
	{
		history.back();
	}
	else
	{
		dialog("Opravdu si přejete zahodit všechny změny?", "Ano", function()
			{
				history.back();
			}, "  Ne  ");
	}
}

function save()
{
	if(changed)
	{
		var payload = {"name": encodeURIComponent(document.getElementById("name").value), "body": encodeURIComponent(ace.edit("editor").getValue())};
		spinner();
		retryAction("/API/v0.9/lesson/" + encodeURIComponent(document.getElementById("save").dataset.id), "PUT", payload);
	}
	else
	{
		discard();
	}
}

function showImageSelector()
{
	if(imageSelectorOpen)
	{
		document.getElementById("imageSelector").style.top = "-100%";
	}
	else
	{
		document.getElementById("imageSelector").style.top = "-91px";
	}
	imageSelectorOpen = !imageSelectorOpen;
}

function getImageSelector(page, perPage)
{
	if(!page)
	{
		page = 1;
	}
	if(!perPage)
	{
		perPage = 15;
	}
	request("/API/v0.9/image", "GET", "", function(response)
		{
			if(response.status === 200)
			{
				renderImageSelector(response.response, page, perPage);
			}
			else
			{
				dialog("Nastala neznámá chyba. Chybová hláška:
" + result.message, "OK");
			}
		});
}

function renderImageSelector(list, page, perPage)
{
	var html = "";
	var start = perPage * (page - 1);
	for(var i = start; i < Math.min(list.length, start + perPage); i++)
	{
		html += "";
	}
	if(list.length > perPage)
	{
		var maxPage = Math.ceil(list.length / perPage);

		function renderPage(page)
		{
			html += "
" + page + "
";
		}
		html += "
";
		if(page > 3)
		{
			renderPage(1);
			html += " ... ";
		}
		if(page > 2)
		{
			renderPage(page - 2);
		}
		if(page > 1)
		{
			renderPage(page - 1);
		}
		html += "
" + page + "
";
		if(page < maxPage)
		{
			renderPage(page + 1);
		}
		if(page < maxPage - 1)
		{
			renderPage(page + 2);
		}
		if(page < maxPage - 2)
		{
			html += " ... ";
			renderPage(maxPage);
		}
		html += "
";
	}
	document.getElementById("imageWrapper").innerHTML = html;

	var	nodes = document.getElementById("imageWrapper").getElementsByTagName("img");
	for(var k = 0; k < nodes.length; k++)
	{
		nodes[k].onclick = insertImage;
	}
	nodes = document.getElementsByClassName("paginationButton");
	for(var l = 0; l < nodes.length; l++)
	{
		nodes[l].onclick = function(event)
			{
				getImageSelector(parseInt(event.target.dataset.page), perPage);
			};
	}
}

function insertImage(event)
{
	var markdown = "![Text po najetí kurzorem](https://odymaterialy.skauting.cz/API/v0.9/image/" + event.target.dataset.id + ")"
	var editor = ace.edit("editor");
	editor.session.insert(editor.getCursorPosition(), markdown);
	showImageSelector();
}
<commit_msg>Fixed html being omited by Ace<commit_after>var changed;
var imageSelectorOpen = false;

function changeLessonOnClick(event)
{
	getLesson(event.target.dataset.id);
	return false;
}

function getLesson(id, noHistory)
{
	spinner();
	request("/API/v0.9/lesson/" + id, "GET", "", function(response)
		{
			if(response.status === 200)
			{
				lessonListEvent.addCallback(function()
					{
						showLesson(id, response.response, noHistory);
					});
			}
			else
			{
				dialog("Nastala neznámá chyba. Chybová hláška:
" + result.message, "OK");
			}
		});
}

function showLesson(id, markdown, noHistory)
{
	dismissSpinner();
	changed = false;
	var lesson = {};
	outer:
	for(var i = 0; i < FIELDS.length; i++)
	{
		for(var j = 0; j < FIELDS[i].lessons.length; j++)
		{
			if(FIELDS[i].lessons[j].id == id)
			{
				lesson = FIELDS[i].lessons[j];
				break outer;
			}
		}
	}
	var html = '\
\

\
		Zrušit\

\
	<form>\
		<input type="text" class="formText formName" id="name" value="' + lesson.name + '" autocomplete="off">\
	</form>\

\
		Uložit\

\

\
		Vložit obrázek\

\
\

\

\

\

\

'
	html += '

';

	document.getElementsByTagName("main")[0].innerHTML = html;
	refreshPreview(lesson.name, markdown);

	if(!noHistory)
	{
		history.pushState({"id": id}, "title", "/admin/");
	}

	document.getElementById("discard").onclick = discard;
	document.getElementById("save").onclick = save;
	document.getElementById("addImageButton").onclick = showImageSelector;

	var editor = ace.edit("editor");
	editor.$blockScrolling = Infinity;
	editor.setValue(markdown, -1);
	editor.setOption("scrollPastEnd", 0.9);
	editor.setTheme("ace/theme/odymaterialy");
	editor.getSession().setMode("ace/mode/markdown");
	editor.getSession().setUseWrapMode(true);
	editor.getSession().on("change", change);
	document.getElementById("name").oninput = change;
	document.getElementById("name").onchange = change;

	getImageSelector();
}

function change()
{
	changed = true;
	refreshPreview(document.getElementById("name").value, ace.edit("editor").getValue());
}

function discard()
{
	if(!changed)
	{
		history.back();
	}
	else
	{
		dialog("Opravdu si přejete zahodit všechny změny?", "Ano", function()
			{
				history.back();
			}, "  Ne  ");
	}
}

function save()
{
	if(changed)
	{
		var payload = {"name": encodeURIComponent(document.getElementById("name").value), "body": encodeURIComponent(ace.edit("editor").getValue())};
		spinner();
		retryAction("/API/v0.9/lesson/" + encodeURIComponent(document.getElementById("save").dataset.id), "PUT", payload);
	}
	else
	{
		discard();
	}
}

function showImageSelector()
{
	if(imageSelectorOpen)
	{
		document.getElementById("imageSelector").style.top = "-100%";
	}
	else
	{
		document.getElementById("imageSelector").style.top = "-91px";
	}
	imageSelectorOpen = !imageSelectorOpen;
}

function getImageSelector(page, perPage)
{
	if(!page)
	{
		page = 1;
	}
	if(!perPage)
	{
		perPage = 15;
	}
	request("/API/v0.9/image", "GET", "", function(response)
		{
			if(response.status === 200)
			{
				renderImageSelector(response.response, page, perPage);
			}
			else
			{
				dialog("Nastala neznámá chyba. Chybová hláška:
" + result.message, "OK");
			}
		});
}

function renderImageSelector(list, page, perPage)
{
	var html = "";
	var start = perPage * (page - 1);
	for(var i = start; i < Math.min(list.length, start + perPage); i++)
	{
		html += "";
	}
	if(list.length > perPage)
	{
		var maxPage = Math.ceil(list.length / perPage);

		function renderPage(page)
		{
			html += "
" + page + "
";
		}
		html += "
";
		if(page > 3)
		{
			renderPage(1);
			html += " ... ";
		}
		if(page > 2)
		{
			renderPage(page - 2);
		}
		if(page > 1)
		{
			renderPage(page - 1);
		}
		html += "
" + page + "
";
		if(page < maxPage)
		{
			renderPage(page + 1);
		}
		if(page < maxPage - 1)
		{
			renderPage(page + 2);
		}
		if(page < maxPage - 2)
		{
			html += " ... ";
			renderPage(maxPage);
		}
		html += "
";
	}
	document.getElementById("imageWrapper").innerHTML = html;

	var	nodes = document.getElementById("imageWrapper").getElementsByTagName("img");
	for(var k = 0; k < nodes.length; k++)
	{
		nodes[k].onclick = insertImage;
	}
	nodes = document.getElementsByClassName("paginationButton");
	for(var l = 0; l < nodes.length; l++)
	{
		nodes[l].onclick = function(event)
			{
				getImageSelector(parseInt(event.target.dataset.page), perPage);
			};
	}
}

function insertImage(event)
{
	var markdown = "![Text po najetí kurzorem](https://odymaterialy.skauting.cz/API/v0.9/image/" + event.target.dataset.id + ")"
	var editor = ace.edit("editor");
	editor.session.insert(editor.getCursorPosition(), markdown);
	showImageSelector();
}
<|endoftext|>


<commit_before>var Packages = module.exports = {};

var _ = require('lodash'),
  fs = require('fs-extra'),
  path = require('path'),
  shell = require('shelljs');

// We rely on system git command and its configuration
// In this way it is possible to pick up .netrc
if (!shell.which('git')) {
  shell.echo('Sorry, this script requires git');
  shell.exit(1);
}

var PACKAGE_DIR = process.cwd() + '/packages';

function resolvePath(string) {
  if (string.substr(0, 1) === '~') {
    var homedir = (process.platform.substr(0, 3) === 'win') ? process.env.HOMEPATH : process.env.HOME;
    string = homedir + string.substr(1);
  } else if (string.substr(0, 1) !== '/') {
    string = process.cwd() + '/' + string;
  }
  return path.resolve(string);
}

/**
 * Configure the package directory.
 * @param packageDir The directory to copy the packages to.
 *                             Defaults to cwd/packages
 */
Packages.config = function (packageDir) {
  PACKAGE_DIR = resolvePath(packageDir);
};

/**
 * Load the packages file.
 * @param [file] Defaults to cwd/git-packages.json
 * @param callback
 */
Packages.fromFile = function (file, callback) {
  if (_.isFunction(file)) {
    callback = file;
    file = null;
  }

  var packagesFile = file || process.cwd() + '/git-packages.json';
  fs.readJson(packagesFile, function (err, packages) {
    // XXX check the packages schema
    if (callback) callback(err, packages);
  });
};

// Create a packages document per git url.
// { gitRepo: { version: { packageName: packagePath, .. }, ... } }
var getPackagesDict = function (packages) {
  var resolvedPackages = {};

  _.forOwn(packages, function (definition, packageName) {
    if (!definition) return;

    var git = definition.git;
    if (!git) return;

    var repo = resolvedPackages[git] = resolvedPackages[git] || {};

    // If no version provided - pull HEAD
    version = definition.version || 'HEAD';
    repo[version] = repo[version] || {};
    repo[version][packageName] = definition.path || '';
  });

  return resolvedPackages;
};

// Test if path exists and fail with error if it is not exists
var checkPathExist = function (path, errorMessage) {
  if (!shell.test('-e', path)) {
    shell.echo('Error: ' + errorMessage);
    shell.exit(1);
  }
};

/**
 * Create a git ignore in the package directory for the packages.
 * @param packages
 * @param {Function} callback
 */
Packages.ensureGitIgnore = function (packages, callback) {
  var filePath = PACKAGE_DIR + '/.gitignore';

  fs.ensureFileSync(filePath);
  fs.readFile(filePath, 'utf8', function (err, gitIgnore) {
    // Append packages to the gitignore
    _.forOwn(packages, function (def, packageName) {
      // Convert colons in package names to dashes for Windows
      packageName = packageName.replace(/:/g, '-');

      if (packageName === 'token' || gitIgnore.indexOf(packageName) > -1) return;

      gitIgnore += packageName + '\n';
    });

    fs.writeFile(filePath, gitIgnore, callback);
  });
};

/**
 * Symlink local directories to the packages directory.
 * @param packages The packages to symlink.
 * @param {Function} callback
 */
Packages.link = function (packages, callback) {
  shell.mkdir('-p', PACKAGE_DIR);

  var dirLinked = _.after(_.keys(packages).length, callback);

  _.forOwn(packages, function (def, packageName) {
    if (!def.path || !packageName) return;

    // Convert colons in package names to dashes for Windows
    packageName = packageName.replace(/:/g, '-');
    var dest = PACKAGE_DIR + '/' + packageName;
    shell.rm('-fr', dest);

    var src = resolvePath(def.path);
    checkPathExist(src, 'Cannot find package ' + packageName + ' at ' + src);

    shell.ln('-s', src, dest);
    checkPathExist(src, 'Link failed for ' + dest);

    dirLinked();
  });
};

/**
 * Clones repositories and copy the packages.
 * @param packages The packages to load.
 * @param {Function} callback
 */
Packages.load = function (packages, callback) {
  shell.mkdir('-p', PACKAGE_DIR);

  // Create a temp directory to store the tarballs
  var tempDir = PACKAGE_DIR + '/temp';
  shell.rm('-fr', tempDir);
  shell.mkdir('-p', tempDir);
  shell.cd(tempDir);

  var resolvedPackages = getPackagesDict(packages);

  var repoDirIndex = 0;

  _.forOwn(resolvedPackages, function (repoPackages, gitRepo) {
    var repoDir = tempDir + '/' + repoDirIndex;

    // Change to the temp directory before cloning the repo
    shell.cd(tempDir);

    if (shell.exec('git clone ' + gitRepo + ' ' + repoDirIndex, {
        silent: true
      }).code !== 0) {
      shell.echo('Error: Git clone failed');
      shell.exit(1);
    }

    // Change to the repo directory
    shell.cd(repoDir);

    repoDirIndex++;

    _.forOwn(repoPackages, function (storedPackages, version) {
      _.forOwn(storedPackages, function (src, packageName) {
        if (shell.exec('git reset --hard ' + version, {
            silent: false
          }).code !== 0) {
          shell.echo('Error: Git checkout failed for ' + packageName + '@' + version);
          shell.exit(1);
        }
        packageName = packageName.replace(/:/g, '-');
        shell.echo('\nProcessing ' + packageName + ' at ' + version);

        shell.echo('Cleaning up');
        var dest = PACKAGE_DIR + '/' + packageName;
        shell.rm('-rf', dest);

        src = repoDir + '/' + src + '/';
        checkPathExist(src, 'Cannot find package in repository: ' + src);

        shell.echo('Copying package');
        // Adding the dot after `src` forces it to copy hidden files as well
        shell.cp('-rf', src + '.', dest);
        checkPathExist(dest, 'Cannot copy package: ' + dest);
        shell.echo('Done...\n');
      });
    });

  });

  // Remove the temp directory after the packages are copied.
  shell.cd(process.cwd());
  shell.rm('-fr', tempDir);
  callback();
};

/**
 * Convert github ssh urls to https. This is useful for defining ssh locally and then using .netrc in build tools.
 */
Packages.toHttps = function (packages) {
  packages = _.cloneDeep(packages);

  _.forOwn(packages, function (definition, packageName) {
    if (definition.git && definition.git.indexOf('git@github.com:') > -1) {
      definition.git = 'https://github.com/' + definition.git.substring(15);
    }
  });

  return packages;
};
<commit_msg>Show which repo failed<commit_after>var Packages = module.exports = {};

var _ = require('lodash'),
  fs = require('fs-extra'),
  path = require('path'),
  shell = require('shelljs');

// We rely on system git command and its configuration
// In this way it is possible to pick up .netrc
if (!shell.which('git')) {
  shell.echo('Sorry, this script requires git');
  shell.exit(1);
}

var PACKAGE_DIR = process.cwd() + '/packages';

function resolvePath(string) {
  if (string.substr(0, 1) === '~') {
    var homedir = (process.platform.substr(0, 3) === 'win') ? process.env.HOMEPATH : process.env.HOME;
    string = homedir + string.substr(1);
  } else if (string.substr(0, 1) !== '/') {
    string = process.cwd() + '/' + string;
  }
  return path.resolve(string);
}

/**
 * Configure the package directory.
 * @param packageDir The directory to copy the packages to.
 *                             Defaults to cwd/packages
 */
Packages.config = function (packageDir) {
  PACKAGE_DIR = resolvePath(packageDir);
};

/**
 * Load the packages file.
 * @param [file] Defaults to cwd/git-packages.json
 * @param callback
 */
Packages.fromFile = function (file, callback) {
  if (_.isFunction(file)) {
    callback = file;
    file = null;
  }

  var packagesFile = file || process.cwd() + '/git-packages.json';
  fs.readJson(packagesFile, function (err, packages) {
    // XXX check the packages schema
    if (callback) callback(err, packages);
  });
};

// Create a packages document per git url.
// { gitRepo: { version: { packageName: packagePath, .. }, ... } }
var getPackagesDict = function (packages) {
  var resolvedPackages = {};

  _.forOwn(packages, function (definition, packageName) {
    if (!definition) return;

    var git = definition.git;
    if (!git) return;

    var repo = resolvedPackages[git] = resolvedPackages[git] || {};

    // If no version provided - pull HEAD
    version = definition.version || 'HEAD';
    repo[version] = repo[version] || {};
    repo[version][packageName] = definition.path || '';
  });

  return resolvedPackages;
};

// Test if path exists and fail with error if it is not exists
var checkPathExist = function (path, errorMessage) {
  if (!shell.test('-e', path)) {
    shell.echo('Error: ' + errorMessage);
    shell.exit(1);
  }
};

/**
 * Create a git ignore in the package directory for the packages.
 * @param packages
 * @param {Function} callback
 */
Packages.ensureGitIgnore = function (packages, callback) {
  var filePath = PACKAGE_DIR + '/.gitignore';

  fs.ensureFileSync(filePath);
  fs.readFile(filePath, 'utf8', function (err, gitIgnore) {
    // Append packages to the gitignore
    _.forOwn(packages, function (def, packageName) {
      // Convert colons in package names to dashes for Windows
      packageName = packageName.replace(/:/g, '-');

      if (packageName === 'token' || gitIgnore.indexOf(packageName) > -1) return;

      gitIgnore += packageName + '\n';
    });

    fs.writeFile(filePath, gitIgnore, callback);
  });
};

/**
 * Symlink local directories to the packages directory.
 * @param packages The packages to symlink.
 * @param {Function} callback
 */
Packages.link = function (packages, callback) {
  shell.mkdir('-p', PACKAGE_DIR);

  var dirLinked = _.after(_.keys(packages).length, callback);

  _.forOwn(packages, function (def, packageName) {
    if (!def.path || !packageName) return;

    // Convert colons in package names to dashes for Windows
    packageName = packageName.replace(/:/g, '-');
    var dest = PACKAGE_DIR + '/' + packageName;
    shell.rm('-fr', dest);

    var src = resolvePath(def.path);
    checkPathExist(src, 'Cannot find package ' + packageName + ' at ' + src);

    shell.ln('-s', src, dest);
    checkPathExist(src, 'Link failed for ' + dest);

    dirLinked();
  });
};

/**
 * Clones repositories and copy the packages.
 * @param packages The packages to load.
 * @param {Function} callback
 */
Packages.load = function (packages, callback) {
  shell.mkdir('-p', PACKAGE_DIR);

  // Create a temp directory to store the tarballs
  var tempDir = PACKAGE_DIR + '/temp';
  shell.rm('-fr', tempDir);
  shell.mkdir('-p', tempDir);
  shell.cd(tempDir);

  var resolvedPackages = getPackagesDict(packages);

  var repoDirIndex = 0;

  _.forOwn(resolvedPackages, function (repoPackages, gitRepo) {
    var repoDir = tempDir + '/' + repoDirIndex;

    // Change to the temp directory before cloning the repo
    shell.cd(tempDir);

    if (shell.exec('git clone ' + gitRepo + ' ' + repoDirIndex, {
        silent: true
      }).code !== 0) {
      shell.echo('Error: Git clone failed: ' + gitRepo);
      shell.exit(1);
    }

    // Change to the repo directory
    shell.cd(repoDir);

    repoDirIndex++;

    _.forOwn(repoPackages, function (storedPackages, version) {
      _.forOwn(storedPackages, function (src, packageName) {
        if (shell.exec('git reset --hard ' + version, {
            silent: false
          }).code !== 0) {
          shell.echo('Error: Git checkout failed for ' + packageName + '@' + version);
          shell.exit(1);
        }
        packageName = packageName.replace(/:/g, '-');
        shell.echo('\nProcessing ' + packageName + ' at ' + version);

        shell.echo('Cleaning up');
        var dest = PACKAGE_DIR + '/' + packageName;
        shell.rm('-rf', dest);

        src = repoDir + '/' + src + '/';
        checkPathExist(src, 'Cannot find package in repository: ' + src);

        shell.echo('Copying package');
        // Adding the dot after `src` forces it to copy hidden files as well
        shell.cp('-rf', src + '.', dest);
        checkPathExist(dest, 'Cannot copy package: ' + dest);
        shell.echo('Done...\n');
      });
    });

  });

  // Remove the temp directory after the packages are copied.
  shell.cd(process.cwd());
  shell.rm('-fr', tempDir);
  callback();
};

/**
 * Convert github ssh urls to https. This is useful for defining ssh locally and then using .netrc in build tools.
 */
Packages.toHttps = function (packages) {
  packages = _.cloneDeep(packages);

  _.forOwn(packages, function (definition, packageName) {
    if (definition.git && definition.git.indexOf('git@github.com:') > -1) {
      definition.git = 'https://github.com/' + definition.git.substring(15);
    }
  });

  return packages;
};
<|endoftext|>


<commit_before>"use strict";

Components.utils.import("chrome://tbsync/content/tbsync.jsm");
Components.utils.import("resource://app/modules/mailServices.js"); //using mailservices to open message window
Components.utils.import("resource://gre/modules/osfile.jsm");
Components.utils.import("resource://gre/modules/Task.jsm");

var tbSyncAccountManager = {

    selectedAccount: null,

    onload: function () {
        //scan accounts, update list and select first entry (because no id is passed to updateAccountList)
        //the onSelect event of the List will load the selected account
        this.updateAccountsList();
        let observerService = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
        observerService.addObserver(tbSyncAccountManager.updateAccountSyncStateObserver, "tbsync.changedSyncstate", false);
        observerService.addObserver(tbSyncAccountManager.updateAccountNameObserver, "tbsync.changedAccountName", false);
    },

    onunload: function () {
        let observerService = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
        observerService.removeObserver(tbSyncAccountManager.updateAccountSyncStateObserver, "tbsync.changedSyncstate");
        observerService.removeObserver(tbSyncAccountManager.updateAccountNameObserver, "tbsync.changedAccountName");
        tbSync.prefWindowObj = null;
    },

    addAccount: function () {
        //EAS hardcoded, will by made dynamic as soon as different providers are usable
        window.openDialog("chrome://tbsync/content/provider/eas/newaccount.xul", "easnewaccount", "centerscreen,modal,resizable=no");
    },

    deleteAccount: function () {
        let accountsList = document.getElementById("tbSyncAccountManager.accounts");
        if (accountsList.selectedItem !== null && !isNaN(accountsList.selectedItem.value)) {
            let nextAccount =  -1;
            if (accountsList.selectedIndex > 0) {
                //first try to select the item after this one, otherwise take the one before
                if (accountsList.selectedIndex + 1 < accountsList.getRowCount()) nextAccount = accountsList.getItemAtIndex(accountsList.selectedIndex + 1).value;
                else nextAccount = accountsList.getItemAtIndex(accountsList.selectedIndex - 1).value;
            }

            if (confirm(tbSync.getLocalizedMessage("prompt.DeleteAccount").replace("##accountName##", accountsList.selectedItem.label))) {
                //disconnect (removes ab, triggers changelog cleanup)
                tbSync[tbSync.db.getAccountSetting(accountsList.selectedItem.value, "provider")].disconnectAccount(accountsList.selectedItem.value);
                //delete account from db
                tbSync.db.removeAccount(accountsList.selectedItem.value);

                this.updateAccountsList(nextAccount);
            }
        }
    },

    /* * *
    * Observer to catch synstate changes and to update account icons
    */
    updateAccountSyncStateObserver: {
        observe: function (aSubject, aTopic, aData) {
            //limit execution to a couple of states, not all
            let state = tbSync.currentProzess.state;

            //react on true syncstate changes send by setSyncState()
            if (aData == "" && (state == "syncing" || state == "accountdone")) tbSyncAccountManager.updateAccountStatus(tbSync.currentProzess.account);

            //react on any manual notification
            if (aData != "") tbSyncAccountManager.updateAccountStatus(aData);
        }
    },

    getStatusImage: function (account) {
        let src = "";

        switch (tbSync.db.getAccountSetting(account, "status")) {
            case "OK":
                src = "tick16.png";
                break;

            case "notconnected":
                src = "discon.png";
                break;

            case "notsyncronized":
            case "nolightning":
                src = "warning16.png";
                break;

            case "syncing":
                src = "sync16.png";
                break;

            default:
                src = "error16.png";
        }

        return "chrome://tbsync/skin/" + src;
    },

    updateAccountStatus: function (id) {
        let listItem = document.getElementById("tbSyncAccountManager.accounts." + id);
        let statusimage = this.getStatusImage(id);
        if (listItem.childNodes[1].firstChild.src != statusimage) {
            listItem.childNodes[1].firstChild.src = statusimage;
        }
    },

    updateAccountNameObserver: {
        observe: function (aSubject, aTopic, aData) {
            let pos = aData.indexOf(":");
            let id = aData.substring(0, pos);
            let name = aData.substring(pos+1);
            tbSyncAccountManager.updateAccountName (id, name);
        }
    },

    updateAccountName: function (id, name) {
        let listItem = document.getElementById("tbSyncAccountManager.accounts." + id);
        if (listItem.firstChild.getAttribute("label") != name) listItem.firstChild.setAttribute("label", name);
    },

    updateAccountsList: function (accountToSelect = -1) {
        let accountsList = document.getElementById("tbSyncAccountManager.accounts");
        let accounts = tbSync.db.getAccounts();

        if (accounts.IDs.length > null) {

            //get current accounts in list and remove entries of accounts no longer there
            let listedAccounts = [];
            for (let i=accountsList.getRowCount()-1; i>=0; i--) {
                listedAccounts.push(accountsList.getItemAtIndex (i).value);
                if (accounts.IDs.indexOf(accountsList.getItemAtIndex(i).value) == -1) {
                    accountsList.removeItemAt(i);
                }
            }

            //accounts array is without order, extract keys (ids) and loop over keys
            for (let i = 0; i < accounts.IDs.length; i++) {

                if (listedAccounts.indexOf(accounts.IDs[i]) == -1) {
                    //add all missing accounts (always to the end of the list)
                    let newListItem = document.createElement("richlistitem");
                    newListItem.setAttribute("id", "tbSyncAccountManager.accounts." + accounts.IDs[i]);
                    newListItem.setAttribute("value", accounts.IDs[i]);

                    //add account name
                    let itemLabelCell = document.createElement("listcell");
                    itemLabelCell.setAttribute("class", "label");
                    itemLabelCell.setAttribute("flex", "1");
                    itemLabelCell.setAttribute("label", accounts.data[accounts.IDs[i]].accountname);
                    newListItem.appendChild(itemLabelCell);

                    //add account status
                    let itemStatusCell = document.createElement("listcell");
                    itemStatusCell.setAttribute("class", "img");
                    itemStatusCell.setAttribute("width", "30");
                    itemStatusCell.setAttribute("height", "30");
                    let itemStatus = document.createElement("image");
                    itemStatus.setAttribute("src", this.getStatusImage(accounts.IDs[i]));
                    itemStatus.setAttribute("style", "margin:2px;");
                    itemStatusCell.appendChild(itemStatus);

                    newListItem.appendChild(itemStatusCell);
                    accountsList.appendChild(newListItem);
                } else {
                    //update existing entries in list
                    this.updateAccountName(accounts.IDs[i], accounts.data[accounts.IDs[i]].accountname);
                    this.updateAccountStatus(accounts.IDs[i]);
                }
            }

            //find selected item
            for (let i=0; i<accountsList.getRowCount(); i++) {
                if (accountToSelect == accountsList.getItemAtIndex(i).value || accountToSelect == -1) {
                    accountsList.selectedIndex = i;
                    accountsList.ensureIndexIsVisible(i);
                    break;
                }
            }

        } else {
            //No defined accounts, empty accounts list and load dummy
            for (let i=accountsList.getRowCount()-1; i>=0; i--) {
                accountsList.removeItemAt(i);
            }

            const LOAD_FLAGS_NONE = Components.interfaces.nsIWebNavigation.LOAD_FLAGS_NONE;
            document.getElementById("tbSyncAccountManager.contentFrame").webNavigation.loadURI("chrome://tbsync/content/noaccounts.xul", LOAD_FLAGS_NONE, null, null, null);
        }
    },

    //load the pref page for the currently selected account (triggered by onSelect)
    loadSelectedAccount: function () {
        let accountsList = document.getElementById("tbSyncAccountManager.accounts");
        if (accountsList.selectedItem !== null && !isNaN(accountsList.selectedItem.value)) {
            //get id of selected account from value of selectedItem
            this.selectedAccount = accountsList.selectedItem.value;
            const LOAD_FLAGS_NONE = Components.interfaces.nsIWebNavigation.LOAD_FLAGS_NONE;
            document.getElementById("tbSyncAccountManager.contentFrame").webNavigation.loadURI("chrome://tbsync/content/provider/"+tbSync.db.getAccountSetting(this.selectedAccount, "provider")+"/accountSettings.xul?id=" + this.selectedAccount, LOAD_FLAGS_NONE, null, null, null);
        }
    },

    openFileTab: function (file) {
        return this.openTBtab(tbSync.getAbsolutePath(file));
    },

    openTBtab: function (url) {
        var tabmail = null;
        var mail3PaneWindow =
            Components.classes["@mozilla.org/appshell/window-mediator;1"]
            .getService(Components.interfaces.nsIWindowMediator)
            .getMostRecentWindow("mail:3pane");
        if (mail3PaneWindow) {
            tabmail = mail3PaneWindow.document.getElementById("tabmail");
            mail3PaneWindow.focus();
            tabmail.openTab("contentTab", {
                contentPage: url
            });
        }
        return (tabmail !== null);
    }

};
<commit_msg>Fix missing name in delete dialog<commit_after>"use strict";

Components.utils.import("chrome://tbsync/content/tbsync.jsm");
Components.utils.import("resource://app/modules/mailServices.js"); //using mailservices to open message window
Components.utils.import("resource://gre/modules/osfile.jsm");
Components.utils.import("resource://gre/modules/Task.jsm");

var tbSyncAccountManager = {

    selectedAccount: null,

    onload: function () {
        //scan accounts, update list and select first entry (because no id is passed to updateAccountList)
        //the onSelect event of the List will load the selected account
        this.updateAccountsList();
        let observerService = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
        observerService.addObserver(tbSyncAccountManager.updateAccountSyncStateObserver, "tbsync.changedSyncstate", false);
        observerService.addObserver(tbSyncAccountManager.updateAccountNameObserver, "tbsync.changedAccountName", false);
    },

    onunload: function () {
        let observerService = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
        observerService.removeObserver(tbSyncAccountManager.updateAccountSyncStateObserver, "tbsync.changedSyncstate");
        observerService.removeObserver(tbSyncAccountManager.updateAccountNameObserver, "tbsync.changedAccountName");
        tbSync.prefWindowObj = null;
    },

    addAccount: function () {
        //EAS hardcoded, will by made dynamic as soon as different providers are usable
        window.openDialog("chrome://tbsync/content/provider/eas/newaccount.xul", "easnewaccount", "centerscreen,modal,resizable=no");
    },

    deleteAccount: function () {
        let accountsList = document.getElementById("tbSyncAccountManager.accounts");
        if (accountsList.selectedItem !== null && !isNaN(accountsList.selectedItem.value)) {
            let nextAccount =  -1;
            if (accountsList.selectedIndex > 0) {
                //first try to select the item after this one, otherwise take the one before
                if (accountsList.selectedIndex + 1 < accountsList.getRowCount()) nextAccount = accountsList.getItemAtIndex(accountsList.selectedIndex + 1).value;
                else nextAccount = accountsList.getItemAtIndex(accountsList.selectedIndex - 1).value;
            }

            if (confirm(tbSync.getLocalizedMessage("prompt.DeleteAccount").replace("##accountName##", accountsList.selectedItem.getAttribute("label")))) {
                //disconnect (removes ab, triggers changelog cleanup)
                tbSync[tbSync.db.getAccountSetting(accountsList.selectedItem.value, "provider")].disconnectAccount(accountsList.selectedItem.value);
                //delete account from db
                tbSync.db.removeAccount(accountsList.selectedItem.value);

                this.updateAccountsList(nextAccount);
            }
        }
    },

    /* * *
    * Observer to catch synstate changes and to update account icons
    */
    updateAccountSyncStateObserver: {
        observe: function (aSubject, aTopic, aData) {
            //limit execution to a couple of states, not all
            let state = tbSync.currentProzess.state;

            //react on true syncstate changes send by setSyncState()
            if (aData == "" && (state == "syncing" || state == "accountdone")) tbSyncAccountManager.updateAccountStatus(tbSync.currentProzess.account);

            //react on any manual notification
            if (aData != "") tbSyncAccountManager.updateAccountStatus(aData);
        }
    },

    getStatusImage: function (account) {
        let src = "";

        switch (tbSync.db.getAccountSetting(account, "status")) {
            case "OK":
                src = "tick16.png";
                break;

            case "notconnected":
                src = "discon.png";
                break;

            case "notsyncronized":
            case "nolightning":
                src = "warning16.png";
                break;

            case "syncing":
                src = "sync16.png";
                break;

            default:
                src = "error16.png";
        }

        return "chrome://tbsync/skin/" + src;
    },

    updateAccountStatus: function (id) {
        let listItem = document.getElementById("tbSyncAccountManager.accounts." + id);
        let statusimage = this.getStatusImage(id);
        if (listItem.childNodes[1].firstChild.src != statusimage) {
            listItem.childNodes[1].firstChild.src = statusimage;
        }
    },

    updateAccountNameObserver: {
        observe: function (aSubject, aTopic, aData) {
            let pos = aData.indexOf(":");
            let id = aData.substring(0, pos);
            let name = aData.substring(pos+1);
            tbSyncAccountManager.updateAccountName (id, name);
        }
    },

    updateAccountName: function (id, name) {
        let listItem = document.getElementById("tbSyncAccountManager.accounts." + id);
        if (listItem.firstChild.getAttribute("label") != name) listItem.firstChild.setAttribute("label", name);
    },

    updateAccountsList: function (accountToSelect = -1) {
        let accountsList = document.getElementById("tbSyncAccountManager.accounts");
        let accounts = tbSync.db.getAccounts();

        if (accounts.IDs.length > null) {

            //get current accounts in list and remove entries of accounts no longer there
            let listedAccounts = [];
            for (let i=accountsList.getRowCount()-1; i>=0; i--) {
                listedAccounts.push(accountsList.getItemAtIndex (i).value);
                if (accounts.IDs.indexOf(accountsList.getItemAtIndex(i).value) == -1) {
                    accountsList.removeItemAt(i);
                }
            }

            //accounts array is without order, extract keys (ids) and loop over keys
            for (let i = 0; i < accounts.IDs.length; i++) {

                if (listedAccounts.indexOf(accounts.IDs[i]) == -1) {
                    //add all missing accounts (always to the end of the list)
                    let newListItem = document.createElement("richlistitem");
                    newListItem.setAttribute("id", "tbSyncAccountManager.accounts." + accounts.IDs[i]);
                    newListItem.setAttribute("value", accounts.IDs[i]);
                    newListItem.setAttribute("label", accounts.data[accounts.IDs[i]].accountname);

                    //add account name
                    let itemLabelCell = document.createElement("listcell");
                    itemLabelCell.setAttribute("class", "label");
                    itemLabelCell.setAttribute("flex", "1");
                    itemLabelCell.setAttribute("label", accounts.data[accounts.IDs[i]].accountname);
                    newListItem.appendChild(itemLabelCell);

                    //add account status
                    let itemStatusCell = document.createElement("listcell");
                    itemStatusCell.setAttribute("class", "img");
                    itemStatusCell.setAttribute("width", "30");
                    itemStatusCell.setAttribute("height", "30");
                    let itemStatus = document.createElement("image");
                    itemStatus.setAttribute("src", this.getStatusImage(accounts.IDs[i]));
                    itemStatus.setAttribute("style", "margin:2px;");
                    itemStatusCell.appendChild(itemStatus);

                    newListItem.appendChild(itemStatusCell);
                    accountsList.appendChild(newListItem);
                } else {
                    //update existing entries in list
                    this.updateAccountName(accounts.IDs[i], accounts.data[accounts.IDs[i]].accountname);
                    this.updateAccountStatus(accounts.IDs[i]);
                }
            }

            //find selected item
            for (let i=0; i<accountsList.getRowCount(); i++) {
                if (accountToSelect == accountsList.getItemAtIndex(i).value || accountToSelect == -1) {
                    accountsList.selectedIndex = i;
                    accountsList.ensureIndexIsVisible(i);
                    break;
                }
            }

        } else {
            //No defined accounts, empty accounts list and load dummy
            for (let i=accountsList.getRowCount()-1; i>=0; i--) {
                accountsList.removeItemAt(i);
            }

            const LOAD_FLAGS_NONE = Components.interfaces.nsIWebNavigation.LOAD_FLAGS_NONE;
            document.getElementById("tbSyncAccountManager.contentFrame").webNavigation.loadURI("chrome://tbsync/content/noaccounts.xul", LOAD_FLAGS_NONE, null, null, null);
        }
    },

    //load the pref page for the currently selected account (triggered by onSelect)
    loadSelectedAccount: function () {
        let accountsList = document.getElementById("tbSyncAccountManager.accounts");
        if (accountsList.selectedItem !== null && !isNaN(accountsList.selectedItem.value)) {
            //get id of selected account from value of selectedItem
            this.selectedAccount = accountsList.selectedItem.value;
            const LOAD_FLAGS_NONE = Components.interfaces.nsIWebNavigation.LOAD_FLAGS_NONE;
            document.getElementById("tbSyncAccountManager.contentFrame").webNavigation.loadURI("chrome://tbsync/content/provider/"+tbSync.db.getAccountSetting(this.selectedAccount, "provider")+"/accountSettings.xul?id=" + this.selectedAccount, LOAD_FLAGS_NONE, null, null, null);
        }
    },

    openFileTab: function (file) {
        return this.openTBtab(tbSync.getAbsolutePath(file));
    },

    openTBtab: function (url) {
        var tabmail = null;
        var mail3PaneWindow =
            Components.classes["@mozilla.org/appshell/window-mediator;1"]
            .getService(Components.interfaces.nsIWindowMediator)
            .getMostRecentWindow("mail:3pane");
        if (mail3PaneWindow) {
            tabmail = mail3PaneWindow.document.getElementById("tabmail");
            mail3PaneWindow.focus();
            tabmail.openTab("contentTab", {
                contentPage: url
            });
        }
        return (tabmail !== null);
    }

};
<|endoftext|>


<commit_before>$(document).ready(function() {
    let posts = [
        {
            "id": "d92jfi",
            "image": "http://localhost:3000/uploads/c568ab0c7e90c3fc122936fef0d4d489",
            "title": "Das Schloss zu Biebrich",
            "author": "loehnertz",
            "liked": ["tester1", "tester2", "etawawd"]
        },
        {
            "id": "2ecji9",
            "image": "https://lh3.googleusercontent.com/p/AF1QipMbAwY9MBHgd_zAzO97Dd4R0fYrVicNIpaswOow=s1600-w1200",
            "title": "Das Kurhaus",
            "author": "loehnertz",
            "liked": ["tester1", "tester2"]
        },
        {
            "id": "28wda7z",
            "image": "https://lh3.googleusercontent.com/p/AF1QipMbAwY9MBHgd_zAzO97Dd4R0fYrVicNIpaswOow=s1600-w1200",
            "title": "Der Neroberg",
            "author": "loehnertz",
            "liked": ["tester1", "tester2", "etawawd"]
        },
    ];

    const HeartIconSource = 'https://i.imgur.com/MXgr4Xl.png';

    let imageContainer = $('#image-container');
});
<commit_msg>Erstelle den Loop zur Generierung der Posts (samt 'console.log()'<commit_after>$(document).ready(function() {
    let posts = [
        {
            "id": "d92jfi",
            "image": "http://localhost:3000/uploads/c568ab0c7e90c3fc122936fef0d4d489",
            "title": "Das Schloss zu Biebrich",
            "author": "loehnertz",
            "liked": ["tester1", "tester2", "etawawd"]
        },
        {
            "id": "2ecji9",
            "image": "https://lh3.googleusercontent.com/p/AF1QipMbAwY9MBHgd_zAzO97Dd4R0fYrVicNIpaswOow=s1600-w1200",
            "title": "Das Kurhaus",
            "author": "loehnertz",
            "liked": ["tester1", "tester2"]
        },
        {
            "id": "28wda7z",
            "image": "https://lh3.googleusercontent.com/p/AF1QipMbAwY9MBHgd_zAzO97Dd4R0fYrVicNIpaswOow=s1600-w1200",
            "title": "Der Neroberg",
            "author": "loehnertz",
            "liked": ["tester1", "tester2", "etawawd"]
        },
    ];

    const HeartIconSource = 'https://i.imgur.com/MXgr4Xl.png';

    let imageContainer = $('#image-container');

    posts.forEach(function (post) {
        console.log(post);
    });
});
<|endoftext|>


<commit_before>import {
    UPDATE_TAG_SUGGESTIONS,
    UPDATE_EXERCISE_SUGGESTIONS
} from 'app/ActionTypes';

const SuggestionsReducer = (state = createDefaultState(), action) => {
    switch (action.type) {
        case UPDATE_EXERCISE_SUGGESTIONS:
            return Object.assign({}, state, {
                exerciseModel: generateAutocompleteExerciseModel(action.workoutData, action.historyData)
            });
        case UPDATE_TAG_SUGGESTIONS:
            return Object.assign({}, state, {
                tagsModel: generateAutocompleteTagsModel(action.workoutData, action.historyData)
            });
        default:
            return state;
    }
};

const createDefaultState = () => ({
    exerciseModel: {
        'belt squat': {suggestion: 'Belt Squat', seed: 5},
        'deficit deadlift': {suggestion: 'Deficit Deadlift', seed: 5},
        'close grip bench': {suggestion: 'Close Grip Bench', seed:5},
        'slingshot bench': {suggestion: 'Slingshot Bench', seed:5},
        'front squat': {suggestion: 'Front Squat', seed: 5},
        'SSB Squat': {suggestion: 'SSB Squat', seed: 5}
    },
    tagsModel: {}
});

const generateAutocompleteExerciseModel = (workoutData, historyData) => {
    // declare vars
    let dictionary = createDefaultState().exerciseModel;
    let model = createDefaultState().exerciseModel;
    let historySets = dictToArray(historyData);
    let workoutSets = workoutData;
    let sets = workoutSets.concat(historySets);

    // ignore nulls and empty strings
    sets = sets.filter((set) => set.exercise !== null && set.exercise !== '');

    // generate dictionary with counts
    sets.map((set) => {
        let lowercaseExercise = set.exercise.toLowerCase();
        if (dictionary[lowercaseExercise] === undefined) {
            dictionary[lowercaseExercise] = { suggestion: set.exercise, seed: 1 };
        } else {
            dictionary[lowercaseExercise] = { suggestion: set.exercise, seed: dictionary[lowercaseExercise].seed + 1};
        }
    });

    // ignore anything less than 2 count
    for (var property in dictionary) {
        if (dictionary.hasOwnProperty(property) && dictionary[property].seed > 1) {
            model[property] = dictionary[property];
        }
    }

    // return
    return model;
};

const generateAutocompleteTagsModel = (workoutData, historyData) => {
    // declare vars
    let model = createDefaultState().tagsModel;
    let workoutSets = workoutData;
    let historySets = dictToArray(historyData);
    let sets = workoutSets.concat(historySets);

    // ignore undefined / nulls / empties
    sets = sets.filter((set) => set.tags !== undefined && set.tags !== null && set.tags.length > 0);

    // generate dictionary with counts
    sets.map((set) => {
        set.tags.map((tag) => {
            let lowercaseTag = tag.toLowerCase();
            if (model[lowercaseTag] === undefined) {
                model[lowercaseTag] = { suggestion: tag, seed: 1 };
            } else {
                model[lowercaseTag] = { suggestion: tag, seed: model[lowercaseTag].seed + 1};
            }
        });
    });

    // return
    return model;
};

// TODO: consider moving this to a utility class as logic is duplicated from Set Selectors
const dictToArray = (dictionary) => {
    var array = [];
    for (var property in dictionary) {
        if (dictionary.hasOwnProperty(property)) {
            array.push(dictionary[property]);
        }
    }
    return array;
};

export default SuggestionsReducer;<commit_msg>updated exercise suggestions and seedings<commit_after>import {
    UPDATE_TAG_SUGGESTIONS,
    UPDATE_EXERCISE_SUGGESTIONS
} from 'app/ActionTypes';

const SuggestionsReducer = (state = createDefaultState(), action) => {
    switch (action.type) {
        case UPDATE_EXERCISE_SUGGESTIONS:
            return Object.assign({}, state, {
                exerciseModel: generateAutocompleteExerciseModel(action.workoutData, action.historyData)
            });
        case UPDATE_TAG_SUGGESTIONS:
            return Object.assign({}, state, {
                tagsModel: generateAutocompleteTagsModel(action.workoutData, action.historyData)
            });
        default:
            return state;
    }
};

const createDefaultState = () => ({
    exerciseModel: {
        'belt squat': {suggestion: 'Belt Squat', seed: 5},
        'deficit deadlift': {suggestion: 'Deficit Deadlift', seed: 5},
        'close grip bench': {suggestion: 'Close Grip Bench', seed:5},
        'slingshot bench': {suggestion: 'Slingshot Bench', seed:5},
        'front squat': {suggestion: 'Front Squat', seed: 5},
        'SSB Squat': {suggestion: 'SSB Squat', seed: 5}
    },
    tagsModel: {}
});

const generateAutocompleteExerciseModel = (workoutData, historyData) => {
    // declare vars
    let dictionary = createDefaultState().exerciseModel;
    let model = createDefaultState().exerciseModel;
    let historySets = dictToArray(historyData);
    let workoutSets = workoutData;
    let sets = workoutSets.concat(historySets);

    // ignore nulls and empty strings
    sets = sets.filter((set) => set.exercise !== null && set.exercise !== '');

    // generate dictionary with counts
    sets.map((set) => {
        let lowercaseExercise = set.exercise.toLowerCase();
        if (dictionary[lowercaseExercise] === undefined) {
            dictionary[lowercaseExercise] = { suggestion: set.exercise, seed: 1 };
        } else {
            dictionary[lowercaseExercise] = { suggestion: set.exercise, seed: dictionary[lowercaseExercise].seed + 1};
        }
    });

    // ignore anything less than 2 count
    for (var property in dictionary) {
        if (dictionary.hasOwnProperty(property) && dictionary[property].seed > 1) {
            model[property] = dictionary[property];
        }
    }

    // return
    return model;
};

const generateAutocompleteTagsModel = (workoutData, historyData) => {
    // declare vars
    let model = createDefaultState().tagsModel;
    let workoutSets = workoutData;
    let historySets = dictToArray(historyData);
    let sets = workoutSets.concat(historySets);

    // ignore undefined / nulls / empties
    sets = sets.filter((set) => set.tags !== undefined && set.tags !== null && set.tags.length > 0);

    // generate dictionary with counts
    sets.map((set) => {
        set.tags.map((tag) => {
            let lowercaseTag = tag.toLowerCase();
            if (model[lowercaseTag] === undefined) {
                model[lowercaseTag] = { suggestion: tag, seed: 1 };
            } else {
                model[lowercaseTag] = { suggestion: tag, seed: model[lowercaseTag].seed + 1};
            }
        });
    });

    // return
    return model;
};

// TODO: consider moving this to a utility class as logic is duplicated from Set Selectors
const dictToArray = (dictionary) => {
    var array = [];
    for (var property in dictionary) {
        if (dictionary.hasOwnProperty(property)) {
            array.push(dictionary[property]);
        }
    }
    return array;
};

export default SuggestionsReducer;
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2015 Google Inc. All Rights Reserved.
 *
 * 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
 */

CLASS({
  package: 'foam.u2.md',
  name: 'ActionButton',
  extends: 'foam.u2.View',

  requires: [
    'foam.u2.Icon',
    'foam.ui.Color',
    'foam.ui.md.HaloView',
  ],
  imports: [
    'dynamic',
    'window'
  ],

  constants: {
    TYPE_CLASSES: {
      label: 'label-only',
      icon: 'icon-only',
      floating: 'floating-action-button'
    }
  },

  properties: [
    [ 'nodeName', 'ACTION-BUTTON' ],
    'action',
    {
      name: 'type',
      choices: ['label', 'icon', 'floating'],
      defaultValueFn: function() {
        return this.action.ligature || this.action.iconUrl ? 'icon' : 'label';
      }
    },
    {
      name: 'halo',
      lazyFactory: function() {
        return this.HaloView.create({
          className: 'halo',
          color$: this.color_$,
          recentering: false,
          pressedAlpha: 0.2,
          startAlpha: 0.2,
          finishAlpha: 0
        }, this.Y);
      }
    },
    {
      name: 'icon',
      lazyFactory: function() {
        return this.Icon.create({
          url$: this.action.iconUrl$,
          ligature$: this.action.ligature$,
          color$: this.color_$
        }, this.Y);
      }
    },
    {
      model_: 'foam.ui.ColorProperty',
      name: 'color',
      defaultValueFn: function() {
        return this.type === 'label' ? '#02A8F3' : 'currentColor';
      }
    },
    {
      type: 'Float',
      name: 'alpha',
      defaultValue: 1
    },
    {
      model_: 'foam.ui.ColorProperty',
      name: 'color_',
      dynamicValue: function() {
        if ( ! (this.action && this.data &&
            this.action.isEnabled.call(this.data)) )
          return this.setColor('rgba(0,0,0,0.65)');
        else
          return this.setColor(this.color);
      }
    },
  ],

  methods: [
    function initE() {
      var self = this;
      this.cls(this.myCls())
          .style({
            color: this.color_$,
            opacity: this.alpha$,
          })
          .cls(this.dynamic(function(data, action) {
            return action &&
                action.isAvailable.call(data, action) ?
                    self.myCls('available') : '';
          }, this.data$, this.action$))
          .cls(this.myCls(this.TYPE_CLASSES[this.type]))
          .cls('noselect')
          .on('click', this.onClick)
          // TODO(markdittmer): We need a better story for adapting CViews into
          // u2.
          .add(this.halo.toView_());

      if (this.type === 'label') {
        this.start('span').cls(this.myCls('label'))
            .add(this.dynamic(function(action) {
              return action ? action.label : '';
            }, this.action$))
            .end();
      } else {
        this.start().cls(this.myCls('icon-container'))
            .start().cls(this.myCls('icon'))
                .add(this.icon)
                .end()
            .end();
      }
    },
    function setColor(c) {
      if ( ! this.Color.isInstance(c) ) {
        this.alpha = 1;
        return c;
      }
      this.alpha = c.alpha;
      c.alpha = 1;
      return c;
    }
  ],

  listeners: [
    function onClick(e) {
      e.preventDefault();
      e.stopPropagation();
      this.action.maybeCall(this.X, this.data);
    }
  ],

  templates: [
    function CSS() {/*
      ^ {
        align-items: baseline;
        border-radius: 2px;
        color: #02A8F3;
        cursor: pointer;
        display: none;
        justify-content: center;
        margin: 8px;
        overflow: hidden;
        padding: 8px;
        position: relative;
      }

      ^available {
        display: inline-flex;
      }

      ^icon-only {
        border-radius: 50%;
        flex-shrink: 0;
        transform: unset;
        transition-delay: 249ms, 0ms, 0ms, 0ms;
        transition: transform 250ms ease, width 249ms ease, margin 249ms ease, padding 249ms ease;
        width: 40px;
      }

      ^ .halo {
        border-radius: inherit;
        left: 0;
        position: absolute;
        top: 0;
        z-index: 2;
      }

      ^label-only ^label {
        color: inherit;
        text-transform: uppercase;
      }

      ^icon-container {
        height: 24px;
        position: relative;
        width: 24px;
      }
      ^icon {
        position: absolute;
        left: 0px;
      }

      ^floating-action-button {
        background-color: #e51c23;
        border-radius: 50%;
        bottom: 10px;
        box-shadow: 3px 3px 3px rgba(0, 0, 0, 0.33);
        flex-shrink: 0;
        height: 44px;
        margin: 0;
        opacity: 1;
        padding: 10px;
        position: absolute;
        right: 20px;
        width: 44px;
        z-index: 10;
      }
    */}
  ]
});
<commit_msg>U2 ActionButton: Fix isAvailable binding<commit_after>/**
 * @license
 * Copyright 2015 Google Inc. All Rights Reserved.
 *
 * 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
 */

CLASS({
  package: 'foam.u2.md',
  name: 'ActionButton',
  extends: 'foam.u2.View',

  requires: [
    'foam.u2.Icon',
    'foam.ui.Color',
    'foam.ui.md.HaloView',
  ],
  imports: [
    'dynamic',
    'window'
  ],

  constants: {
    TYPE_CLASSES: {
      label: 'label-only',
      icon: 'icon-only',
      floating: 'floating-action-button'
    }
  },

  properties: [
    [ 'nodeName', 'ACTION-BUTTON' ],
    'action',
    {
      name: 'type',
      choices: ['label', 'icon', 'floating'],
      defaultValueFn: function() {
        return this.action.ligature || this.action.iconUrl ? 'icon' : 'label';
      }
    },
    {
      name: 'halo',
      lazyFactory: function() {
        return this.HaloView.create({
          className: 'halo',
          color$: this.color_$,
          recentering: false,
          pressedAlpha: 0.2,
          startAlpha: 0.2,
          finishAlpha: 0
        }, this.Y);
      }
    },
    {
      name: 'icon',
      lazyFactory: function() {
        return this.Icon.create({
          url$: this.action.iconUrl$,
          ligature$: this.action.ligature$,
          color$: this.color_$
        }, this.Y);
      }
    },
    {
      model_: 'foam.ui.ColorProperty',
      name: 'color',
      defaultValueFn: function() {
        return this.type === 'label' ? '#02A8F3' : 'currentColor';
      }
    },
    {
      type: 'Float',
      name: 'alpha',
      defaultValue: 1
    },
    {
      model_: 'foam.ui.ColorProperty',
      name: 'color_',
      dynamicValue: function() {
        if ( ! (this.action && this.data &&
            this.action.isEnabled.call(this.data)) )
          return this.setColor('rgba(0,0,0,0.65)');
        else
          return this.setColor(this.color);
      }
    },
    {
      name: 'available_',
    },
  ],

  methods: [
    function initE() {
      var self = this;

      this.on('unload', this.X.dynamicFn(
          this.action.isAvailable.bind(this.data, this.action),
          function() {
            self.available_ = self.action.isAvailable.call(self.data, self.action);
          }
      ));

      this.cls(this.myCls())
          .style({
            color: this.color_$,
            opacity: this.alpha$,
          })
          .enableCls(this.myCls('available'), this.available_$)
          .cls(this.myCls(this.TYPE_CLASSES[this.type]))
          .cls('noselect')
          .on('click', this.onClick)
          // TODO(markdittmer): We need a better story for adapting CViews into
          // u2.
          .add(this.halo.toView_());

      if (this.type === 'label') {
        this.start('span').cls(this.myCls('label'))
            .add(this.dynamic(function(action) {
              return action ? action.label : '';
            }, this.action$))
            .end();
      } else {
        this.start().cls(this.myCls('icon-container'))
            .start().cls(this.myCls('icon'))
                .add(this.icon)
                .end()
            .end();
      }
    },
    function setColor(c) {
      if ( ! this.Color.isInstance(c) ) {
        this.alpha = 1;
        return c;
      }
      this.alpha = c.alpha;
      c.alpha = 1;
      return c;
    }
  ],

  listeners: [
    function onClick(e) {
      e.preventDefault();
      e.stopPropagation();
      this.action.maybeCall(this.X, this.data);
    }
  ],

  templates: [
    function CSS() {/*
      ^ {
        align-items: baseline;
        border-radius: 2px;
        color: #02A8F3;
        cursor: pointer;
        display: none;
        justify-content: center;
        margin: 8px;
        overflow: hidden;
        padding: 8px;
        position: relative;
      }

      ^available {
        display: inline-flex;
      }

      ^icon-only {
        border-radius: 50%;
        flex-shrink: 0;
        transform: unset;
        transition-delay: 249ms, 0ms, 0ms, 0ms;
        transition: transform 250ms ease, width 249ms ease, margin 249ms ease, padding 249ms ease;
        width: 40px;
      }

      ^ .halo {
        border-radius: inherit;
        left: 0;
        position: absolute;
        top: 0;
        z-index: 2;
      }

      ^label-only ^label {
        color: inherit;
        text-transform: uppercase;
      }

      ^icon-container {
        height: 24px;
        position: relative;
        width: 24px;
      }
      ^icon {
        position: absolute;
        left: 0px;
      }

      ^floating-action-button {
        background-color: #e51c23;
        border-radius: 50%;
        bottom: 10px;
        box-shadow: 3px 3px 3px rgba(0, 0, 0, 0.33);
        flex-shrink: 0;
        height: 44px;
        margin: 0;
        opacity: 1;
        padding: 10px;
        position: absolute;
        right: 20px;
        width: 44px;
        z-index: 10;
      }
    */}
  ]
});
<|endoftext|>


<commit_before>var https = require('https'),
querystring = require('querystring'),
appId, appSecret, appRedirect,
eventHandlers = {},
pollOngoing = {};

/**
 * @static EVENTS GitHub Api event
 * @see https://developer.github.com/v3/activity/events/types/
 */
exports.EVENTS = {
   COMMIT_COMMENT: "CommitCommentEvent",
   CREATE: "CreateEvent",
   DELETE: "DeleteEvent",
   DEPLOY: "DeploymentEvent",
   DEPLOY_STATUS: "DeploymentStatusEvent",
   DOWNLOAD: "DownloadEvent",
   FOLLOW: "FollowEvent",
   FORK: "ForkEvent",
   FORK_APPLY: "ForkApplyEvent",
   GIST: "GistEvent",
   GOLLUM: "GollumEvent",
   ISSUE_COMMENT: "IssueCommentEvent",
   ISSUES: "IssuesEvent",
   MEMBER: "MemberEvent",
   PAGE_BUILD: "PageBuildEvent",
   PUBLIC: "PublicEvent",
   PULL_REQUEST: "PullRequestEvent",
   PULL_REQUEST_REVIEWED: "PullRequestReviewCommentEvent",
   PUSH: "PushEvent",
   RELEASE: "ReleaseEvent",
   STATUS: "StatusEvent",
   TEAM_ADD: "TeamAddEvent",
   WATCH: "WatchEvent"
}

/**
 * @method gitHubApiRequest create https request for github api
 * @param accessToken user's access token get by oauth
 * @param method GET or POST
 * @param path root to call on GH API
 * @param params optional
 * @param headers optional
 * @param done(payload)
 * @see https://developer.github.com/v3/
 */
exports.gitHubApiRequest = function(accessToken, method, path, params, headers, done) {
    var dataObject = "", options = {
      headers: {"User-Agent": "GRebase", "Authorization": "token " + accessToken, "Content-Length": params ? JSON.stringify(params).length : 0},
      hostname: 'api.github.com',
      port: 443,
      path: path,
      method: method
    };

    if (headers) {
        for (var i in headers) {
            if (headers.hasOwnProperty(i)) {
                options.headers[i] = headers[i];
            }
        }
    }

    var r = https.request(options, function(res) {
        res.on('data', function (chunk) {
            dataObject += chunk.toString();
        });

        res.on('end', function() {
            try {
                dataObject = dataObject !== "" ? JSON.parse(dataObject) : null;
            } catch(e) {
                console.error(true, [method, path, params]);
                console.error(true, [dataObject]);
                console.error(true, [e]);
            }

            done(null, dataObject, res);
        });
    });

    r.on('error', function(error) {
        console.error(true, [error]);
        done(error, null, null);
    });

    if (params) {
        r.write(JSON.stringify(params));
    }

    r.end();
}

/**
 * @method getAllBranch return a list of repo's branches
 * @param accessToken user's access token get by oauth
 * @param owner repo's owner
 * @param repo repository
 * @param done(branches_list)
 * @see https://developer.github.com/v3/repos/#list-branches
 */
exports.getAllBranch = function(accessToken, owner, repo, done) {
    exports.gitHubApiRequest(accessToken, "GET", "/repos/" + owner + "/" + repo + "/branches", null, null, done);
}

/**
 * @method getBranch return a branch objet
 * @param accessToken user's access token get by oauth
 * @param owner repo's owner
 * @param repo repository
 * @param branch branch to get
 * @param done(branch_object)
 * @see https://developer.github.com/v3/repos/#get-branch
 */
exports.getBranch = function(accessToken, owner, repo, branch, done) {
    exports.gitHubApiRequest(accessToken, "GET", "/repos/" + owner + "/" + repo + "/branches/" + branch, null, null, done);
}

/**
 * @method getCommit return a specific commit object
 * @param accessToken user's access token get by oauth
 * @param owner repo's owner
 * @param repo repository
 * @param sha commit's sha1
 * @param done(commit_object)
 * @see https://developer.github.com/v3/repos/commits/#get-a-single-commit
 */
exports.getCommit = function(accessToken, owner, repo, sha, done) {
    exports.gitHubApiRequest(accessToken, "GET", "/repos/" + owner + "/" + repo + "/commits/" + sha, null, null, done);
}

/**
 * @method getUser return the user authenticated info objet
 * @param userToken user's access token get by oauth
 * @param done(user_authenticated_info_object)
 * @see https://developer.github.com/v3/users/#get-the-authenticated-user
 */
exports.getUser = function(userToken, done) {
    exports.gitHubApiRequest(userToken, "GET", "/user", null, null, done);
}

/**
 * @method getRepos return the user authenticated info objet
 * @param userToken user's access token get by oauth
 * @param type can be all, owner, public, private, member
 * @param done(user_authenticated_repos_object)
 * @see https://developer.github.com/v3/repos/#list-your-repositories
 */
exports.getRepos = function(userToken, type, done) {
    exports.gitHubApiRequest(userToken, "GET", "/user/repos?sort=created&type=" + type, null, null, done);
}

/**
 * @method doesIssueExist check if issue already exist on repo
 * @param accessToken user's access token get by oauth
 * @param owner repo's owner
 * @param repo repository
 * @param title issue's title
 * @param done(issue_object)
 * @see https://developer.github.com/v3/issues/#list-issues-for-a-repository
 */
exports.doesIssueExist = function(accessToken, owner, repo, title, done) {
    var issueFound = null;
    exports.gitHubApiRequest(accessToken, "GET", "/repos/" + owner + "/" + repo + "/issues", null, null, function(error, data, res) {
        if (!error && data && data.length) {
            data.forEach(function(issue, index) {
                if (issue.title === title) {
                    issueFound = issue;
                }
            });
            done(error, issueFound);
        } else {
            done(error, null);
        }
    });
}

/**
 * @method createIssueOnRepo create an issue on repo if not exist
 * @param accessToken user's access token get by oauth
 * @param owner repo's owner
 * @param repo repository
 * @param title issue's title
 * @param body issue's body
 * @see https://developer.github.com/v3/issues/#create-an-issue
 */
exports.createIssueOnRepo = function(accessToken, owner, repo, title, body) {
    exports.doesIssueExist(accessToken, owner, repo, title, function(error, issue) {
        if (!error && !issue) {
            exports.gitHubApiRequest(accessToken, "POST", "/repos/" + owner + "/" + repo + "/issues", {title: title, body: body}, null, function() {});
        }
    });
}

/**
 * @method closeIssueOnRepo close issue on repo if issue exist
 * @param accessToken user's access token get by oauth
 * @param owner repo's owner
 * @param repo repository
 * @param title issue's title
 * @see https://developer.github.com/v3/issues/#edit-an-issue
 */
exports.closeIssueOnRepo = function(accessToken, owner, repo, title) {
    exports.doesIssueExist(accessToken, owner, repo, title, function(error, issue) {
        if (!error && issue) {
            exports.gitHubApiRequest(accessToken, "PATCH", "/repos/" + owner + "/" + repo + "/issues/" + issue.number, {state: "closed"}, null, function() {});
        }
    });
}

/**
 * @private loopPollForRepoEvent recursive poll to listen repo event
 * @param accessToken user's access token get by oauth
 * @param owner repo's owner
 * @param repo repository
 * @see https://developer.github.com/v3/activity/events/#list-repository-events
 */
var loopPollForRepoEvent = function(accessToken, owner, repo) {
    var etag = null;
    var lastEventId = null;

    var pollRequest = function() {
        exports.gitHubApiRequest(accessToken, "GET", "/repos/" + owner + "/" + repo + "/events", null, etag, function(error, events, response) {
            if (!error) {
                var h = response.headers;
                var time =  parseInt(h["x-poll-interval"], 10);
                var ntag = h.etag;

                if (h.status === "200 OK") {
                    var newEventId = events[0].id;
                    if (etag) {
                        while (events[0].id !== lastEventId) {
                            if (eventHandlers[repo][events[0].type]) {
                                eventHandlers[repo][events[0].type].forEach(function(callback, index) {
                                    callback(events[0], events[0].type);
                                });
                            }
                            events.shift()
                        }
                    }
                    lastEventId = newEventId;
                }

                if (ntag) {
                    etag = {"If-None-Match": ntag};
                }

                setTimeout(pollRequest, time * 1000);
            }
        });
    }

    pollRequest();
}

/**
 * @method addEventOnRepo listen for a specific GitHub Api event on a repo
 * @param accessToken user's access token get by oauth
 * @param owner repo's owner
 * @param repo repository
 * @param eventName GitHub event (githubapi.EVENTS)
 * @param handler(object_event)
 * @see https://developer.github.com/v3/activity/events/#list-repository-events
 */
exports.addEventOnRepo = function(accessToken, owner, repo, eventName, handler) {
    if (!eventHandlers[repo]) {
        eventHandlers[repo] = {};
    }
    if (!eventHandlers[repo][eventName]) {
        eventHandlers[repo][eventName] = [];
    }

    eventHandlers[repo][eventName].push(handler);

    if (!pollOngoing[repo]) {
        pollOngoing[repo] = true;
        loopPollForRepoEvent(accessToken, owner, repo);
    }
}

/**
 * @private sendResponseForOAuth
 * @param req
 * @param res
 * @param done(github_access_token)
 * FIXME see to merge this function with exports.gitHubApiRequest
 */
var sendResponseForOAuth = function(req, res, done) {
    var access_token, dataObject, options = {
        hostname: "github.com",
        port: 443,
        path: "/login/oauth/access_token",
        method: "POST"
    };

    var gitResponse = https.request(options, function(resG) {
        resG.on("data", function (chunk) {
            dataObject = querystring.parse(chunk.toString());
            if (dataObject.access_token) {
                access_token = dataObject.access_token;
                done(req, res, access_token);
            }
        });
    });

    gitResponse.on("error", function(error) {
        console.error(true, ["sendResponseForOAuth error", error]);
        res.write(error);
        res.send();
    });

    gitResponse.write("client_id=" + appId + "&client_secret=" + appSecret + "&code=" + req.query.code);
    gitResponse.end();
}

/**
 * @method oauth get oauth token from GitHubAPI
 * @param req
 * @param res
 * @param done(github_access_token)
 * @see https://developer.github.com/v3/oauth/
 */
exports.oauth = function(done) {
    return function(req, res) {
        if (!appId || !appRedirect || !appSecret) {
            console.error("githubapi: (oauth) miss app infos, call init function(app_id, app_secret, app_redirect) before");
            res.send();
        } else if (!req.query.code) {
            res.redirect("https://github.com/login/oauth/authorize?redirect_uri=" + appRedirect + req.path + "&scope=repo&client_id=" + appId + "&state=" + Date.now());
        } else if (req.query.code) {
            sendResponseForOAuth(req, res, done);
        }
    }
}

/**
 * @method init init githubapi module with github app infos
 * @param app_id
 * @param app_secret
 * @param app_redirect
 * @see https://github.com/settings/applications
 */
exports.init = function(app_id, app_secret, app_redirect) {
    if (arguments.length !== 3) {
        console.error("githubapi: (init) missing arguments");
    } else {
        appId = app_id;
        appSecret = app_secret;
        appRedirect = app_redirect;
    }
}
<commit_msg>Update githubapi.js<commit_after>var https = require('https'),
querystring = require('querystring'),
appId, appSecret, appRedirect,
eventHandlers = {},
pollOngoing = {};

/**
 * @static EVENTS GitHub Api event
 * @see https://developer.github.com/v3/activity/events/types/
 */
exports.EVENTS = {
   COMMIT_COMMENT: "CommitCommentEvent",
   CREATE: "CreateEvent",
   DELETE: "DeleteEvent",
   DEPLOY: "DeploymentEvent",
   DEPLOY_STATUS: "DeploymentStatusEvent",
   DOWNLOAD: "DownloadEvent",
   FOLLOW: "FollowEvent",
   FORK: "ForkEvent",
   FORK_APPLY: "ForkApplyEvent",
   GIST: "GistEvent",
   GOLLUM: "GollumEvent",
   ISSUE_COMMENT: "IssueCommentEvent",
   ISSUES: "IssuesEvent",
   MEMBER: "MemberEvent",
   PAGE_BUILD: "PageBuildEvent",
   PUBLIC: "PublicEvent",
   PULL_REQUEST: "PullRequestEvent",
   PULL_REQUEST_REVIEWED: "PullRequestReviewCommentEvent",
   PUSH: "PushEvent",
   RELEASE: "ReleaseEvent",
   STATUS: "StatusEvent",
   TEAM_ADD: "TeamAddEvent",
   WATCH: "WatchEvent"
}

/**
 * @method gitHubApiRequest create https request for github api
 * @param accessToken user's access token get by oauth
 * @param method GET or POST
 * @param path root to call on GH API
 * @param params optional
 * @param headers optional
 * @param done(payload)
 * @see https://developer.github.com/v3/
 */
exports.gitHubApiRequest = function(accessToken, method, path, params, headers, done) {
    var dataObject = "", options = {
      headers: {"User-Agent": "GRebase", "Authorization": "token " + accessToken, "Content-Length": params ? JSON.stringify(params).length : 0},
      hostname: 'api.github.com',
      port: 443,
      path: path,
      method: method
    };

    if (headers) {
        for (var i in headers) {
            if (headers.hasOwnProperty(i)) {
                options.headers[i] = headers[i];
            }
        }
    }

    var r = https.request(options, function(res) {
        res.on('data', function (chunk) {
            dataObject += chunk.toString();
        });

        res.on('end', function() {
            try {
                dataObject = dataObject !== "" ? JSON.parse(dataObject) : null;
            } catch(e) {
                console.error(true, [method, path, params]);
                console.error(true, [dataObject]);
                console.error(true, [e]);
            }

            done(null, dataObject, res);
        });
    });

    r.on('error', function(error) {
        console.error(true, [error]);
        done(error, null, null);
    });

    if (params) {
        r.write(JSON.stringify(params));
    }

    r.end();
}

/**
 * @method getAllBranch return a list of repo's branches
 * @param accessToken user's access token get by oauth
 * @param owner repo's owner
 * @param repo repository
 * @param done(branches_list)
 * @see https://developer.github.com/v3/repos/#list-branches
 */
exports.getAllBranch = function(accessToken, owner, repo, done) {
    exports.gitHubApiRequest(accessToken, "GET", "/repos/" + owner + "/" + repo + "/branches", null, null, done);
}

/**
 * @method getBranch return a branch objet
 * @param accessToken user's access token get by oauth
 * @param owner repo's owner
 * @param repo repository
 * @param branch branch to get
 * @param done(branch_object)
 * @see https://developer.github.com/v3/repos/#get-branch
 */
exports.getBranch = function(accessToken, owner, repo, branch, done) {
    exports.gitHubApiRequest(accessToken, "GET", "/repos/" + owner + "/" + repo + "/branches/" + branch, null, null, done);
}

/**
 * @method getCommit return a specific commit object
 * @param accessToken user's access token get by oauth
 * @param owner repo's owner
 * @param repo repository
 * @param sha commit's sha1
 * @param done(commit_object)
 * @see https://developer.github.com/v3/repos/commits/#get-a-single-commit
 */
exports.getCommit = function(accessToken, owner, repo, sha, done) {
    exports.gitHubApiRequest(accessToken, "GET", "/repos/" + owner + "/" + repo + "/commits/" + sha, null, null, done);
}

/**
 * @method getUser return the user authenticated info objet
 * @param userToken user's access token get by oauth
 * @param done(user_authenticated_info_object)
 * @see https://developer.github.com/v3/users/#get-the-authenticated-user
 */
exports.getUser = function(userToken, done) {
    exports.gitHubApiRequest(userToken, "GET", "/user", null, null, done);
}

/**
 * @method getRepos return the user authenticated info objet
 * @param userToken user's access token get by oauth
 * @param type can be all, owner, public, private, member
 * @param done(user_authenticated_repos_object)
 * @see https://developer.github.com/v3/repos/#list-your-repositories
 */
exports.getRepos = function(userToken, type, done) {
    exports.gitHubApiRequest(userToken, "GET", "/user/repos?sort=created&type=" + type, null, null, done);
}

/**
 * @method doesIssueExist check if issue already exist on repo
 * @param accessToken user's access token get by oauth
 * @param owner repo's owner
 * @param repo repository
 * @param title issue's title
 * @param done(issue_object)
 * @see https://developer.github.com/v3/issues/#list-issues-for-a-repository
 */
exports.doesIssueExist = function(accessToken, owner, repo, title, done) {
    var issueFound = null;
    exports.gitHubApiRequest(accessToken, "GET", "/repos/" + owner + "/" + repo + "/issues", null, null, function(error, data, res) {
        if (!error && data && data.length) {
            data.forEach(function(issue, index) {
                if (issue.title === title) {
                    issueFound = issue;
                }
            });
            done(error, issueFound);
        } else {
            done(error, null);
        }
    });
}

/**
 * @method createIssueOnRepo create an issue on repo if not exist
 * @param accessToken user's access token get by oauth
 * @param owner repo's owner
 * @param repo repository
 * @param title issue's title
 * @param body issue's body
 * @see https://developer.github.com/v3/issues/#create-an-issue
 */
exports.createIssueOnRepo = function(accessToken, owner, repo, title, body) {
    exports.doesIssueExist(accessToken, owner, repo, title, function(error, issue) {
        if (!error && !issue) {
            exports.gitHubApiRequest(accessToken, "POST", "/repos/" + owner + "/" + repo + "/issues", {title: title, body: body}, null, function() {});
        }
    });
}

/**
 * @method closeIssueOnRepo close issue on repo if issue exist
 * @param accessToken user's access token get by oauth
 * @param owner repo's owner
 * @param repo repository
 * @param title issue's title
 * @see https://developer.github.com/v3/issues/#edit-an-issue
 */
exports.closeIssueOnRepo = function(accessToken, owner, repo, title) {
    exports.doesIssueExist(accessToken, owner, repo, title, function(error, issue) {
        if (!error && issue) {
            exports.gitHubApiRequest(accessToken, "PATCH", "/repos/" + owner + "/" + repo + "/issues/" + issue.number, {state: "closed"}, null, function() {});
        }
    });
}

/**
 * @private loopPollForRepoEvent recursive poll to listen repo event
 * @param accessToken user's access token get by oauth
 * @param owner repo's owner
 * @param repo repository
 * @see https://developer.github.com/v3/activity/events/#list-repository-events
 */
var loopPollForRepoEvent = function(accessToken, owner, repo) {
    var etag = null;
    var lastEventId = null;

    var pollRequest = function() {
        exports.gitHubApiRequest(accessToken, "GET", "/repos/" + owner + "/" + repo + "/events", null, etag, function(error, events, response) {
            if (!error) {
                var h = response.headers;
                var time =  parseInt(h["x-poll-interval"], 10);
                var ntag = h.etag;

                if (h.status === "200 OK") {
                    var newEventId = events[0].id;
                    if (etag) {
                        while (events[0].id !== lastEventId) {
                            if (eventHandlers[repo][events[0].type]) {
                                eventHandlers[repo][events[0].type].forEach(function(callback, index) {
                                    callback(events[0], events[0].type);
                                });
                            }
                            events.shift()
                        }
                    }
                    lastEventId = newEventId;
                }

                if (ntag) {
                    etag = {"If-None-Match": ntag};
                }

                setTimeout(pollRequest, time * 1000);
            }
        });
    }

    pollRequest();
}

/**
 * @method addEventOnRepo listen for a specific GitHub Api event on a repo
 * @param accessToken user's access token get by oauth
 * @param owner repo's owner
 * @param repo repository
 * @param eventName GitHub event (githubapi.EVENTS)
 * @param handler(object_event)
 * @see https://developer.github.com/v3/activity/events/#list-repository-events
 */
exports.addEventOnRepo = function(accessToken, owner, repo, eventName, handler) {
    if (!eventHandlers[repo]) {
        eventHandlers[repo] = {};
    }
    if (!eventHandlers[repo][eventName]) {
        eventHandlers[repo][eventName] = [];
    }

    eventHandlers[repo][eventName].push(handler);

    if (!pollOngoing[repo]) {
        pollOngoing[repo] = true;
        loopPollForRepoEvent(accessToken, owner, repo);
    }
}

/**
 * @private sendResponseForOAuth
 * @param req
 * @param res
 * @param done(github_access_token)
 * FIXME see to merge this function with exports.gitHubApiRequest
 */
var sendResponseForOAuth = function(req, res, done) {
    var access_token, dataObject, options = {
        hostname: "github.com",
        port: 443,
        path: "/login/oauth/access_token",
        method: "POST"
    };

    var gitResponse = https.request(options, function(resG) {
        resG.on("data", function (chunk) {
            dataObject = querystring.parse(chunk.toString());
            if (dataObject.access_token) {
                access_token = dataObject.access_token;
                done(req, res, access_token);
            }
        });
    });

    gitResponse.on("error", function(error) {
        console.error(true, ["sendResponseForOAuth error", error]);
        res.write(error);
        res.send();
    });

    gitResponse.write("client_id=" + appId + "&client_secret=" + appSecret + "&code=" + req.query.code);
    gitResponse.end();
}

/**
 * @method oauth get oauth token from GitHubAPI
 * @param req
 * @param res
 * @param done(github_access_token)
 * @see https://developer.github.com/v3/oauth/
 */
exports.oauth = function(done, scope) {
    return function(req, res) {
        if (!appId || !appRedirect || !appSecret) {
            console.error("githubapi: (oauth) miss app infos, call init function(app_id, app_secret, app_redirect) before");
            res.send();
        } else if (!req.query.code) {
            res.redirect("https://github.com/login/oauth/authorize?redirect_uri=" + appRedirect + req.path + "&scope=" + scope + "&client_id=" + appId + "&state=" + Date.now());
        } else if (req.query.code) {
            sendResponseForOAuth(req, res, done);
        }
    }
}

/**
 * @method init init githubapi module with github app infos
 * @param app_id
 * @param app_secret
 * @param app_redirect
 * @see https://github.com/settings/applications
 */
exports.init = function(app_id, app_secret, app_redirect) {
    if (arguments.length !== 3) {
        console.error("githubapi: (init) missing arguments");
    } else {
        appId = app_id;
        appSecret = app_secret;
        appRedirect = app_redirect;
    }
}
<|endoftext|>