<commit_before>/* Milesian Year Signature Display
	Character set is UTF-8
	This package displays annual figures, in relation with YearSignatureDisplay.html
Required (directly)
	MilesianYearSignature
	Seasons
Contents
	Functions called by the MilesianYearSignature.html
*/
/* Version M2020-12-29	New signature routines
	M2020-02-01 : comput epact on 1 1m, use year range constraint for milesian epact
	M2020-01-12 : strict mode
	M2019-08-23: add seasons' computation
	M2019-07-27: update dependencies
	M2019-05-12:
		Display day of week as a Date-formatted string, instead of a select field
		Display Roman date with an explicit month indication
	M2019-01-13: Suppress "Milesian" line, since Milesian figures are like Gregorian,
		and rework Easter date in milesian
	M2018-10-26: Enhance comments
	M2017-01-09: Display Gold number 1 to 19, not 0 to 18.
*/
/* Copyright Miletus 2017-2020 - Louis A. de Fouquières
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
1. The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
2. Changes with respect to any former version shall be documented.

The software is provided "as is", without warranty of any kind,
express of implied, including but not limited to the warranties of
merchantability, fitness for a particular purpose and noninfringement.
In no event shall the authors of copyright holders be liable for any
claim, damages or other liability, whether in an action of contract,
tort or otherwise, arising from, out of or in connection with the software
or the use or other dealings in the software.
Inquiries: www.calendriermilesien.org
*/
"use strict";
function romanDateFrom21March (offset) {
	let f = new Intl.DateTimeFormat(undefined,{month:"short", day:"numeric"});
	return (offset <= 10)
		? f.format(new Date (1800, 2, (offset + 21)))
		: f.format(new Date (1800, 3, (offset - 10)));
}
function milesianDateFrom30_3m (offset) {
	return	(offset <= -30 ? "<1 3m" :
		(offset <= 0 ? (30+offset) + " 3m" :
		(offset <= 31 ? (offset) + " 4m" :
		(offset <= 61 ? (offset - 31) + " 5m" :
		(offset <= 92 ? (offset - 61) + " 6m" :
		(offset <= 122 ? (offset - 92) + " 7m" :
		(offset <= 153 ? (offset - 122) + " 8m" :
		(offset <= 183 ? (offset -153) + " 9m" :
		(offset <= 214 ? (offset - 183) + " 10m" :
		(offset <= 244 ? (offset - 214) + " 11m" :
		(offset <= 274 ? (offset - 244) + " 12m" : ">30 12m" ))))))))))) ;
}
function displayDOW (Day) { // Yield the string of the day of the week of rank Day
	return new Intl.DateTimeFormat(undefined, {weekday: "long"}).format (new Date (1970, 0, 4+Day))
}
/* function displayYeartype (type) {
	var yearTypes = ["cave (et commune)", "longue (et commune)", "bissextile (et cave)"]
	return yearTypes [type];
}*/
function computeSignature(year) {
	var outBounds = (year < -5000 || year > 9000);
	var signature = julianSignature (year), m_signature = milesianSignature (year);
	// All figures the specified year
	// Set gold number
	document.yearglobal.gold.value = signature.goldNumber;
	// Julian figures
	document.details.j_type.value = signature.isLeap ? "bissextile" : "commune";
	document.details.j_day.value = displayDOW (signature.doomsday);
	document.details.j_epact.value = signature.epact;
	document.details.j_residue.value = signature.easterResidue;
	document.details.j_daynumber.value = signature.easterOffset;
	document.details.j_romandate.value = romanDateFrom21March(signature.easterOffset);
	document.details.j_milesiandate.value = milesianDateFrom30_3m(
		signature.easterOffset -2 +Math.floor(year/100) -Math.floor(year/400));
	// Gregorian and Milesian figures
	signature = gregorianSignature (year);
	document.details.g_type.value = signature.isLeap ? "bissextile" : "commune";
	document.details.m_type.value = m_signature.isLeap ? "abondante" : "cave" ;
	document.details.g_day.value = displayDOW (signature.doomsday);
	document.details.g_epact.value = signature.epact;
	document.details.m_epact.value = m_signature.epact
	document.details.g_residue.value = signature.easterResidue;
	document.details.g_daynumber.value = signature.easterOffset;
	document.details.g_romandate.value = romanDateFrom21March(signature.easterOffset);
	document.details.g_milesiandate.value = milesianDateFrom30_3m(signature.easterOffset);
	// Seasons
	let seasonDisplay = new ExtDateTimeFormat (undefined, {year: "numeric", month: "short", day: "numeric", hour: "numeric", minute: "numeric"},milesian);
	try {
		document.seasons.winter1.value = seasonDisplay.format (Seasons.tropicEvent(year,0));
		document.seasons.spring.value = seasonDisplay.format (Seasons.tropicEvent(year,1));
		document.seasons.summer.value = seasonDisplay.format (Seasons.tropicEvent(year,2));
		document.seasons.autumn.value = seasonDisplay.format (Seasons.tropicEvent(year,3));
		document.seasons.winter2.value = seasonDisplay.format (Seasons.tropicEvent(year,4));
	}
	catch (e) {
		document.seasons.winter1.value =
		document.seasons.spring.value =
		document.seasons.summer.value =
		document.seasons.autumn.value =
		document.seasons.winter2.value = "-- -- -- -- --";
	}
}
function setYear(year) {
	year = Math.round(year);	// Force to integer value
	if (isNaN (year)) alert ("non Integer: " + '"' + document.control.year.value + '"')
	else {
		document.control.year.value = +year;
		computeSignature (+year);
		}
}
function setYearOffset(shift) {
	shift = Math.round(shift);	// Force to integer value
	let year = Math.round(document.control.year.value) + Math.round(shift);
	if (isNaN (year)) alert ("non Integer: " + '"' + document.control.shift.value + '" "' + document.control.year.value + '"')
	else if (year < -271820 || year > 275760) alert ("Year out of range")
	else {
		document.control.year.value = year;
		computeSignature (year);
		}
}
function setYearToNow(){ // Self explanatory
    let targetDate = new ExtDate(milesian); // Now in Milesian.
	setYear(targetDate.year());
}
<commit_msg>Season dates in time zone<commit_after>/* Milesian Year Signature Display
	Character set is UTF-8
	This package displays annual figures, in relation with YearSignatureDisplay.html
Required (directly)
	MilesianYearSignature
	Seasons
Contents
	Functions called by the MilesianYearSignature.html
*/
/* Version M2021-01-14 Tailor to language and time zone
	M2020-12-29	New signature routines
	M2020-02-01 : comput epact on 1 1m, use year range constraint for milesian epact
	M2020-01-12 : strict mode
	M2019-08-23: add seasons' computation
	M2019-07-27: update dependencies
	M2019-05-12:
		Display day of week as a Date-formatted string, instead of a select field
		Display Roman date with an explicit month indication
	M2019-01-13: Suppress "Milesian" line, since Milesian figures are like Gregorian,
		and rework Easter date in milesian
	M2018-10-26: Enhance comments
	M2017-01-09: Display Gold number 1 to 19, not 0 to 18.
*/
/* Copyright Miletus 2017-2020 - Louis A. de Fouquières
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
1. The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
2. Changes with respect to any former version shall be documented.

The software is provided "as is", without warranty of any kind,
express of implied, including but not limited to the warranties of
merchantability, fitness for a particular purpose and noninfringement.
In no event shall the authors of copyright holders be liable for any
claim, damages or other liability, whether in an action of contract,
tort or otherwise, arising from, out of or in connection with the software
or the use or other dealings in the software.
Inquiries: www.calendriermilesien.org
*/
"use strict";
function romanDateFrom21March (offset) {
	let f = new Intl.DateTimeFormat(undefined,{month:"short", day:"numeric"});
	return (offset <= 10)
		? f.format(new Date (1800, 2, (offset + 21)))
		: f.format(new Date (1800, 3, (offset - 10)));
}
function milesianDateFrom30_3m (offset) {
	return	(offset <= -30 ? "<1 3m" :
		(offset <= 0 ? (30+offset) + " 3m" :
		(offset <= 31 ? (offset) + " 4m" :
		(offset <= 61 ? (offset - 31) + " 5m" :
		(offset <= 92 ? (offset - 61) + " 6m" :
		(offset <= 122 ? (offset - 92) + " 7m" :
		(offset <= 153 ? (offset - 122) + " 8m" :
		(offset <= 183 ? (offset -153) + " 9m" :
		(offset <= 214 ? (offset - 183) + " 10m" :
		(offset <= 244 ? (offset - 214) + " 11m" :
		(offset <= 274 ? (offset - 244) + " 12m" : ">30 12m" ))))))))))) ;
}
function displayDOW (Day, lang) { // Yield the string of the day of the week of rank Day
	if (lang == "") lang = undefined;
	return new Intl.DateTimeFormat(lang, {weekday: "long"}).format (new Date (1970, 0, 4+Day))
}
/* function displayYeartype (type) {
	var yearTypes = ["cave (et commune)", "longue (et commune)", "bissextile (et cave)"]
	return yearTypes [type];
}*/
function computeSignature(year, lang, timeZone) {
	if (lang == "") lang = undefined;
	if (timeZone == "") timeZone = undefined;
	// Begin with common and Julian calendar figures
	var signature = julianSignature (year), m_signature = milesianSignature (year);
	// All figures the specified year
	// Set gold number
	document.yearglobal.gold.value = signature.goldNumber;
	// Julian figures
	document.details.j_type.value = signature.isLeap ? "bissextile" : "commune";
	document.details.j_day.value = displayDOW (signature.doomsday);
	document.details.j_epact.value = signature.epact;
	document.details.j_residue.value = signature.easterResidue;
	document.details.j_daynumber.value = signature.easterOffset;
	document.details.j_romandate.value = romanDateFrom21March(signature.easterOffset);
	document.details.j_milesiandate.value = milesianDateFrom30_3m(
		signature.easterOffset -2 +Math.floor(year/100) -Math.floor(year/400));
	// Gregorian and Milesian figures
	signature = gregorianSignature (year);
	document.details.g_type.value = signature.isLeap ? "bissextile" : "commune";
	document.details.m_type.value = m_signature.isLeap ? "abondante" : "cave" ;
	document.details.g_day.value = displayDOW (signature.doomsday);
	document.details.g_epact.value = signature.epact;
	document.details.m_epact.value = m_signature.epact
	document.details.g_residue.value = signature.easterResidue;
	document.details.g_daynumber.value = signature.easterOffset;
	document.details.g_romandate.value = romanDateFrom21March(signature.easterOffset);
	document.details.g_milesiandate.value = milesianDateFrom30_3m(signature.easterOffset);
	// Seasons
	let seasonDisplay = new ExtDateTimeFormat (lang, {
		timeZone: timeZone,
		year: "numeric", month: "short", day: "numeric", hour: "numeric", minute: "numeric"},milesian);
	try {
		document.seasons.winter1.value = seasonDisplay.format (Seasons.tropicEvent(year,0));
		document.seasons.spring.value = seasonDisplay.format (Seasons.tropicEvent(year,1));
		document.seasons.summer.value = seasonDisplay.format (Seasons.tropicEvent(year,2));
		document.seasons.autumn.value = seasonDisplay.format (Seasons.tropicEvent(year,3));
		document.seasons.winter2.value = seasonDisplay.format (Seasons.tropicEvent(year,4));
	}
	catch (e) {		// seasons coulf not be computed, main reason is: year out of computational range
		document.seasons.winter1.value =
		document.seasons.spring.value =
		document.seasons.summer.value =
		document.seasons.autumn.value =
		document.seasons.winter2.value = "-- -- -- -- --";
	}
}
function setYear(year) {
	year = Math.round(year);	// Force to integer value
	if (isNaN (year)) alert ("non Integer: " + '"' + document.control.year.value + '"')
	else {
		document.control.year.value = +year;
		computeSignature (+year);
		}
}
function setYearOffset(shift) {
	shift = Math.round(shift);	// Force to integer value
	let year = Math.round(document.control.year.value) + Math.round(shift);
	if (isNaN (year)) alert ("non Integer: " + '"' + document.control.shift.value + '" "' + document.control.year.value + '"')
	else if (year < -271820 || year > 275760) alert ("Year out of range")
	else {
		document.control.year.value = year;
		computeSignature (year);
		}
}
function setYearToNow(){ // Self explanatory
    let targetDate = new ExtDate(milesian); // Now in Milesian.
	setYear(targetDate.year());
}
<|endoftext|>


<commit_before>function createElement(type, props, ...children) {
  return {
    type,
    props: {
      ...props,
      children: children.map(child =>
        typeof child === "object"
          ? child
          : createTextElement(child)
      ),
    },
  }
}

function createTextElement(text) {
  return {
    type: "TEXT_ELEMENT",
    props: {
      nodeValue: text,
      children: [],
    },
  }
}

function createDom(fiber) {
  const dom =
    fiber.type == "TEXT_ELEMENT"
      ? document.createTextNode("")
      : document.createElement(fiber.type)

  updateDom(dom, {}, fiber.props)

  return dom
}

const isEvent = key => key.startsWith("on")
const isProperty = key =>
  key !== "children" && !isEvent(key)
const isNew = (prev, next) => key =>
  prev[key] !== next[key]
const isGone = (prev, next) => key => !(key in next)
function updateDom(dom, prevProps, nextProps) {
  //Remove old or changed event listeners
  Object.keys(prevProps)
    .filter(isEvent)
    .filter(
      key =>
        !(key in nextProps) ||
        isNew(prevProps, nextProps)(key)
    )
    .forEach(name => {
      const eventType = name
        .toLowerCase()
        .substring(2)
      dom.removeEventListener(
        eventType,
        prevProps[name]
      )
    })

  // Remove old properties
  Object.keys(prevProps)
    .filter(isProperty)
    .filter(isGone(prevProps, nextProps))
    .forEach(name => {
      dom[name] = ""
    })

  // Set new or changed properties
  Object.keys(nextProps)
    .filter(isProperty)
    .filter(isNew(prevProps, nextProps))
    .forEach(name => {
      dom[name] = nextProps[name]
    })

  // Add event listeners
  Object.keys(nextProps)
    .filter(isEvent)
    .filter(isNew(prevProps, nextProps))
    .forEach(name => {
      const eventType = name
        .toLowerCase()
        .substring(2)
      dom.addEventListener(
        eventType,
        nextProps[name]
      )
    })
}

function commitRoot() {
  deletions.forEach(commitWork)
  commitWork(wipRoot.child)
  currentRoot = wipRoot
  wipRoot = null
}

function commitWork(fiber) {
  if (!fiber) {
    return
  }

  let domParentFiber = fiber.parent
  while (!domParentFiber.dom) {
    domParentFiber = domParentFiber.parent
  }
  const domParent = domParentFiber.dom

  if (
    fiber.effectTag === "PLACEMENT" &&
    fiber.dom != null
  ) {
    domParent.appendChild(fiber.dom)
  } else if (
    fiber.effectTag === "UPDATE" &&
    fiber.dom != null
  ) {
    updateDom(
      fiber.dom,
      fiber.alternate.props,
      fiber.props
    )
  } else if (fiber.effectTag === "DELETION") {
    domParent.removeChild(fiber.dom)
  }

  commitWork(fiber.child)
  commitWork(fiber.sibling)
}

function render(element, container) {
  wipRoot = {
    dom: container,
    props: {
      children: [element],
    },
    alternate: currentRoot,
  }
  deletions = []
  nextUnitOfWork = wipRoot
}

let nextUnitOfWork = null
let currentRoot = null
let wipRoot = null
let deletions = null

function workLoop(deadline) {
  let shouldYield = false
  while (nextUnitOfWork && !shouldYield) {
    nextUnitOfWork = performUnitOfWork(
      nextUnitOfWork
    )
    shouldYield = deadline.timeRemaining() < 1
  }

  if (!nextUnitOfWork && wipRoot) {
    commitRoot()
  }

  requestIdleCallback(workLoop)
}

requestIdleCallback(workLoop)

function performUnitOfWork(fiber) {
  const isFunctionComponent =
    fiber.type instanceof Function
  if (isFunctionComponent) {
    updateFunctionComponent(fiber)
  } else {
    updateHostComponent(fiber)
  }
  if (fiber.child) {
    return fiber.child
  }
  let nextFiber = fiber
  while (nextFiber) {
    if (nextFiber.sibling) {
      return nextFiber.sibling
    }
    nextFiber = nextFiber.parent
  }
}

function updateFunctionComponent(fiber) {
  const children = [fiber.type(fiber.props)]
  reconcileChildren(fiber, children)
}

function updateHostComponent(fiber) {
  if (!fiber.dom) {
    fiber.dom = createDom(fiber)
  }
  reconcileChildren(fiber, fiber.props.children)
}

function reconcileChildren(wipFiber, elements) {
  let index = 0
  let oldFiber =
    wipFiber.alternate && wipFiber.alternate.child
  let prevSibling = null

  while (
    index < elements.length ||
    oldFiber != null
  ) {
    const element = elements[index]
    let newFiber = null

    const sameType =
      oldFiber &&
      element &&
      element.type == oldFiber.type

    if (sameType) {
      newFiber = {
        type: oldFiber.type,
        props: element.props,
        dom: oldFiber.dom,
        parent: wipFiber,
        alternate: oldFiber,
        effectTag: "UPDATE",
      }
    }
    if (element && !sameType) {
      newFiber = {
        type: element.type,
        props: element.props,
        dom: null,
        parent: wipFiber,
        alternate: null,
        effectTag: "PLACEMENT",
      }
    }
    if (oldFiber && !sameType) {
      oldFiber.effectTag = "DELETION"
      deletions.push(oldFiber)
    }

    if (oldFiber) {
      oldFiber = oldFiber.sibling
    }

    if (index === 0) {
      wipFiber.child = newFiber
    } else if (element) {
      prevSibling.sibling = newFiber
    }

    prevSibling = newFiber
    index++
  }
}

const Didact = {
  createElement,
  render,
}

/** @jsx Didact.createElement */
function App({ props }) {
  return
Hi {props.name}

}
const element = <App name="foo" />
const container = document.getElementById("root")
Didact.render(element, container)
<commit_msg>Find child to remove<commit_after>function createElement(type, props, ...children) {
  return {
    type,
    props: {
      ...props,
      children: children.map(child =>
        typeof child === "object"
          ? child
          : createTextElement(child)
      ),
    },
  }
}

function createTextElement(text) {
  return {
    type: "TEXT_ELEMENT",
    props: {
      nodeValue: text,
      children: [],
    },
  }
}

function createDom(fiber) {
  const dom =
    fiber.type == "TEXT_ELEMENT"
      ? document.createTextNode("")
      : document.createElement(fiber.type)

  updateDom(dom, {}, fiber.props)

  return dom
}

const isEvent = key => key.startsWith("on")
const isProperty = key =>
  key !== "children" && !isEvent(key)
const isNew = (prev, next) => key =>
  prev[key] !== next[key]
const isGone = (prev, next) => key => !(key in next)
function updateDom(dom, prevProps, nextProps) {
  //Remove old or changed event listeners
  Object.keys(prevProps)
    .filter(isEvent)
    .filter(
      key =>
        !(key in nextProps) ||
        isNew(prevProps, nextProps)(key)
    )
    .forEach(name => {
      const eventType = name
        .toLowerCase()
        .substring(2)
      dom.removeEventListener(
        eventType,
        prevProps[name]
      )
    })

  // Remove old properties
  Object.keys(prevProps)
    .filter(isProperty)
    .filter(isGone(prevProps, nextProps))
    .forEach(name => {
      dom[name] = ""
    })

  // Set new or changed properties
  Object.keys(nextProps)
    .filter(isProperty)
    .filter(isNew(prevProps, nextProps))
    .forEach(name => {
      dom[name] = nextProps[name]
    })

  // Add event listeners
  Object.keys(nextProps)
    .filter(isEvent)
    .filter(isNew(prevProps, nextProps))
    .forEach(name => {
      const eventType = name
        .toLowerCase()
        .substring(2)
      dom.addEventListener(
        eventType,
        nextProps[name]
      )
    })
}

function commitRoot() {
  deletions.forEach(commitWork)
  commitWork(wipRoot.child)
  currentRoot = wipRoot
  wipRoot = null
}

function commitWork(fiber) {
  if (!fiber) {
    return
  }

  let domParentFiber = fiber.parent
  while (!domParentFiber.dom) {
    domParentFiber = domParentFiber.parent
  }
  const domParent = domParentFiber.dom

  if (
    fiber.effectTag === "PLACEMENT" &&
    fiber.dom != null
  ) {
    domParent.appendChild(fiber.dom)
  } else if (
    fiber.effectTag === "UPDATE" &&
    fiber.dom != null
  ) {
    updateDom(
      fiber.dom,
      fiber.alternate.props,
      fiber.props
    )
  } else if (fiber.effectTag === "DELETION") {
    commitDeletion(fiber, domParent)
  }

  commitWork(fiber.child)
  commitWork(fiber.sibling)
}

function commitDeletion(fiber, domParent) {
  if (fiber.dom) {
    domParent.removeChild(fiber.dom)
  } else {
    commitDeletion(fiber.child, domParent)
  }
}

function render(element, container) {
  wipRoot = {
    dom: container,
    props: {
      children: [element],
    },
    alternate: currentRoot,
  }
  deletions = []
  nextUnitOfWork = wipRoot
}

let nextUnitOfWork = null
let currentRoot = null
let wipRoot = null
let deletions = null

function workLoop(deadline) {
  let shouldYield = false
  while (nextUnitOfWork && !shouldYield) {
    nextUnitOfWork = performUnitOfWork(
      nextUnitOfWork
    )
    shouldYield = deadline.timeRemaining() < 1
  }

  if (!nextUnitOfWork && wipRoot) {
    commitRoot()
  }

  requestIdleCallback(workLoop)
}

requestIdleCallback(workLoop)

function performUnitOfWork(fiber) {
  const isFunctionComponent =
    fiber.type instanceof Function
  if (isFunctionComponent) {
    updateFunctionComponent(fiber)
  } else {
    updateHostComponent(fiber)
  }
  if (fiber.child) {
    return fiber.child
  }
  let nextFiber = fiber
  while (nextFiber) {
    if (nextFiber.sibling) {
      return nextFiber.sibling
    }
    nextFiber = nextFiber.parent
  }
}

function updateFunctionComponent(fiber) {
  const children = [fiber.type(fiber.props)]
  reconcileChildren(fiber, children)
}

function updateHostComponent(fiber) {
  if (!fiber.dom) {
    fiber.dom = createDom(fiber)
  }
  reconcileChildren(fiber, fiber.props.children)
}

function reconcileChildren(wipFiber, elements) {
  let index = 0
  let oldFiber =
    wipFiber.alternate && wipFiber.alternate.child
  let prevSibling = null

  while (
    index < elements.length ||
    oldFiber != null
  ) {
    const element = elements[index]
    let newFiber = null

    const sameType =
      oldFiber &&
      element &&
      element.type == oldFiber.type

    if (sameType) {
      newFiber = {
        type: oldFiber.type,
        props: element.props,
        dom: oldFiber.dom,
        parent: wipFiber,
        alternate: oldFiber,
        effectTag: "UPDATE",
      }
    }
    if (element && !sameType) {
      newFiber = {
        type: element.type,
        props: element.props,
        dom: null,
        parent: wipFiber,
        alternate: null,
        effectTag: "PLACEMENT",
      }
    }
    if (oldFiber && !sameType) {
      oldFiber.effectTag = "DELETION"
      deletions.push(oldFiber)
    }

    if (oldFiber) {
      oldFiber = oldFiber.sibling
    }

    if (index === 0) {
      wipFiber.child = newFiber
    } else if (element) {
      prevSibling.sibling = newFiber
    }

    prevSibling = newFiber
    index++
  }
}

const Didact = {
  createElement,
  render,
}

/** @jsx Didact.createElement */
function App({ props }) {
  return
Hi {props.name}

}
const element = <App name="foo" />
const container = document.getElementById("root")
Didact.render(element, container)
<|endoftext|>


<commit_before>var last_feeds = [];

var _active_feed_id = false;
var _active_feed_offset = false;
var _update_timeout = false;

function catchup_article(article_id, callback) {
	try {
		var query = "?op=rpc&subop=catchupSelected" +
			"&cmode=0&ids=" + article_id;

		new Ajax.Request("backend.php",	{
			parameters: query,
			onComplete: function(transport) {
				if (callback) callback(transport);
			} });

	} catch (e) {
		exception_error("catchup_article", e);
	}
}

function set_selected_feed(feed_id) {
	try {
		var feeds = $("feeds-content").getElementsByTagName("LI");

		for (var i = 0; i < feeds.length; i++) {
			if (feeds[i].id == "F-" + feed_id)
				feeds[i].className = "selected";
			else
				feeds[i].className = "";
		}

		_active_feed_id = feed_id;

	} catch (e) {
		exception_error("mark_selected_feed", e);
	}
}

function zoom(article_id) {
	try {
		var elem = $('A-' + article_id);

		if (elem) {
			var divs = elem.getElementsByTagName('DIV');

			for (var i = 0; i < divs.length; i++) {
				if (divs[i].className == 'excerpt')
					Element.hide(divs[i]);

				if (divs[i].className == 'content')
					Element.show(divs[i]);
			}
		}

		catchup_article(article_id,
			function() { update(); });

	} catch (e) {
		exception_error("zoom", e);
	}
}

function load_more() {
	try {
		viewfeed(_active_feed_id, _active_feed_offset + 10);
	} catch (e) {
		exception_error("load_more", e);
	}
}

function update() {
	try {
		console.log('updating feeds...');

		window.clearTimeout(_update_timeout);

		new Ajax.Request("backend.php",	{
			parameters: "?op=rpc&subop=digest-init",
			onComplete: function(transport) {
				parse_feeds(transport);
				set_selected_feed(_active_feed_id);
				} });

		_update_timeout = window.setTimeout('update()', 5*1000);
	} catch (e) {
		exception_error("update", e);
	}
}

function remove_headline_entry(article_id) {
	try {
		var elem = $('A-' + article_id);

		if (elem) {
			elem.parentNode.removeChild(elem);
		}

	} catch (e) {
		exception_error("remove_headline_entry", e);
	}
}

function view(article_id, dismiss_only) {
	try {
		remove_headline_entry(article_id);

		catchup_article(article_id,
			function() { update(); });

		return dismiss_only != true;
	} catch (e) {
		exception_error("view", e);
	}
}

function viewfeed(feed_id, offset) {
	try {

		if (!feed_id) feed_id = _active_feed_id;

		if (!offset) {
			offset = 0;
		} else {
			offset = _active_feed_offset + offset;
		}

		var query = "backend.php?op=rpc&subop=digest-update&feed_id=" + feed_id +
				"&offset=" + offset;

		new Ajax.Request("backend.php",	{
			parameters: query,
			onComplete: function(transport) {
				parse_headlines(transport, offset == 0);
				set_selected_feed(feed_id);
				_active_feed_offset = offset;
			} });

	} catch (e) {
		exception_error("view", e);
	}
}

function find_article(articles, article_id) {
	try {
		for (var i = 0; i < articles.length; i++) {
			if (articles[i].id == article_id)
				return articles[i];
		}

		return false;

	} catch (e) {
		exception_error("find_article", e);
	}
}

function find_feed(feeds, feed_id) {
	try {
		for (var i = 0; i < feeds.length; i++) {
			if (feeds[i].id == feed_id)
				return feeds[i];
		}

		return false;

	} catch (e) {
		exception_error("find_feed", e);
	}
}

function get_feed_icon(feed) {
	try {
		if (feed.has_icon)
			return 'icons/' + feed.id + '.ico';

		if (feed.id == -1)
			return 'images/mark_set.png';

		if (feed.id == -2)
			return 'images/pub_set.png';

		if (feed.id == -3)
			return 'images/fresh.png';

		if (feed.id == -4)
			return 'images/tag.png';

		if (feed.id < -10)
			return 'images/label.png';

		return 'images/blank_icon.gif';

	} catch (e) {
		exception_error("get_feed_icon", e);
	}
}

function add_feed_entry(feed) {
	try {
		var icon_part = "";

		icon_part = "";

		var tmp_html = "
" +
			icon_part +
			"" + feed.title +
			"
" + feed.unread + "
" +
			"
";

		$("feeds-content").innerHTML += tmp_html;

	} catch (e) {
		exception_error("add_feed_entry", e);
	}
}

function add_headline_entry(article, feed) {
	try {

		var icon_part = "";

		icon_part = "";

		var tmp_html = "
" +
			icon_part +
			"
" +
			"" +
			"" +
			"" +
			"
" +
			"" +
				article.title + "" +
			"
" +
			"
" +
				article.excerpt + "
" +
			"
" +
				article.content + "
" +
			"
" +
				feed.title + " " + " @ " +
				new Date(article.updated * 1000) + "
" +
			"

";

		$("headlines-content").innerHTML += tmp_html;

	} catch (e) {
		exception_error("add_headline_entry", e);
	}
}

function parse_feeds(transport) {
	try {

		var feeds = transport.responseXML.getElementsByTagName('feeds')[0];

		if (feeds) {
			feeds = eval("(" + feeds.firstChild.nodeValue + ")");

			last_feeds = feeds;

			$('feeds-content').innerHTML = "";

			for (var i = 0; i < feeds.length; i++) {
				add_feed_entry(feeds[i]);
			}
		}

	} catch (e) {
		exception_error("parse_feeds", e);
	}
}

function parse_headlines(transport, replace) {
	try {
		var headlines = transport.responseXML.getElementsByTagName('headlines')[0];

		if (headlines) {
			headlines = eval("(" + headlines.firstChild.nodeValue + ")");

			if (replace) $('headlines-content').innerHTML = '';

			var pr = $('MORE-PROMPT');

			if (pr) pr.parentNode.removeChild(pr);

			for (var i = 0; i < headlines.length; i++) {

				if (!$('A-' + headlines[i].id)) {
					add_headline_entry(headlines[i],
							find_feed(last_feeds, headlines[i].feed_id));
				}
			}

			if (pr) {
				$('headlines-content').appendChild(pr);
			} else {
				$('headlines-content').innerHTML += "
" +
					"
" +
				  	__("More articles...") + "

";
			}

			new Effect.Appear('headlines-content');
		}

	} catch (e) {
		exception_error("parse_headlines", e);
	}
}

/*function digest_update(transport, feed_id, offset) {
	try {
		var feeds = transport.responseXML.getElementsByTagName('feeds')[0];
		var headlines = transport.responseXML.getElementsByTagName('headlines')[0];

		if (feeds) {
			feeds = eval("(" + feeds.firstChild.nodeValue + ")");

			last_feeds = feeds;

			$('feeds-content').innerHTML = "";

			for (var i = 0; i < feeds.length; i++) {
				add_feed_entry(feeds[i]);
			}
		} else {
			feeds = last_feeds;
		}

		if (headlines) {
			headlines = eval("(" + headlines.firstChild.nodeValue + ")");

			if (_active_feed_id != feed_id || !offset)
				$('headlines-content').innerHTML = "";

			var pr = $('MORE-PROMPT');

			if (pr) {
				pr.id = '';
				Element.hide(pr);
			}

			for (var i = 0; i < headlines.length; i++) {
				var elem = $('A-' + headlines[i].id);

				if (elem && Element.visible(elem)) {
					if (!headlines[i].unread)
						remove_headline_entry(headlines[i].id);

				} else {
					add_headline_entry(headlines[i], find_feed(feeds, headlines[i].feed_id));
				}
			}

			$('headlines-content').innerHTML += "
" +
				"
" +
			  	__("More articles...") + "

";

			new Effect.Appear('headlines-content');
		}

		if (feed_id != undefined) {
			_active_feed_id = feed_id;
		}

		if (offset != undefined) _active_feed_offset = offset;

		mark_selected_feed(_active_feed_id);

	} catch (e) {
		exception_error("digest_update", e);
	}
} */

function init() {
	try {

		new Ajax.Request("backend.php",	{
			parameters: "backend.php?op=rpc&subop=digest-init",
			onComplete: function(transport) {
				parse_feeds(transport);
				window.setTimeout('viewfeed(-4)', 100);
				_update_timeout = window.setTimeout('update()', 5*1000);
				} });

	} catch (e) {
		exception_error("digest_init", e);
	}
}

function tMark_afh_off(effect) {
	try {
		var elem = effect.effects[0].element;

		console.log("tMark_afh_off : " + elem.id);

		if (elem) {
			elem.src = elem.src.replace("mark_set", "mark_unset");
			elem.alt = __("Star article");
			Element.show(elem);
		}

	} catch (e) {
		exception_error("tMark_afh_off", e);
	}
}

function tPub_afh_off(effect) {
	try {
		var elem = effect.effects[0].element;

		console.log("tPub_afh_off : " + elem.id);

		if (elem) {
			elem.src = elem.src.replace("pub_set", "pub_unset");
			elem.alt = __("Publish article");
			Element.show(elem);
		}

	} catch (e) {
		exception_error("tPub_afh_off", e);
	}
}

function toggleMark(mark_img, id) {

	try {

		var query = "?op=rpc&id=" + id + "&subop=mark";

		query = query + "&afid=" + _active_feed_id;
		query = query + "&omode=c";

		if (!mark_img) return;

		if (mark_img.src.match("mark_unset")) {
			mark_img.src = mark_img.src.replace("mark_unset", "mark_set");
			mark_img.alt = __("Unstar article");
			query = query + "&mark=1";
		} else {
			mark_img.alt = __("Please wait...");
			query = query + "&mark=0";

			mark_img.src = mark_img.src.replace("mark_set", "mark_unset");
			mark_img.alt = __("Star article");
		}

		new Ajax.Request("backend.php", {
			parameters: query,
			onComplete: function(transport) {
				//
			} });

	} catch (e) {
		exception_error("toggleMark", e);
	}
}

function togglePub(mark_img, id, note) {

	try {

		var query = "?op=rpc&id=" + id + "&subop=publ";

		query = query + "&afid=" + _active_feed_id;

		if (note != undefined) {
			query = query + "&note=" + param_escape(note);
		} else {
			query = query + "&note=undefined";
		}

		query = query + "&omode=c";

		if (!mark_img) return;

		if (mark_img.src.match("pub_unset") || note != undefined) {
			mark_img.src = mark_img.src.replace("pub_unset", "pub_set");
			mark_img.alt = __("Unpublish article");
			query = query + "&pub=1";

		} else {
			mark_img.alt = __("Please wait...");
			query = query + "&pub=0";

			mark_img.src = mark_img.src.replace("pub_set", "pub_unset");
			mark_img.alt = __("Publish article");
		}

		new Ajax.Request("backend.php", {
			parameters: query,
			onComplete: function(transport) {
				//
			} });

	} catch (e) {
		exception_error("togglePub", e);
	}
}

<commit_msg>sort feeds list by unread; support fatal error messages and login redirects<commit_after>var last_feeds = [];

var _active_feed_id = false;
var _active_feed_offset = false;
var _update_timeout = false;

function catchup_article(article_id, callback) {
	try {
		var query = "?op=rpc&subop=catchupSelected" +
			"&cmode=0&ids=" + article_id;

		new Ajax.Request("backend.php",	{
			parameters: query,
			onComplete: function(transport) {
				if (callback) callback(transport);
			} });

	} catch (e) {
		exception_error("catchup_article", e);
	}
}

function set_selected_feed(feed_id) {
	try {
		var feeds = $("feeds-content").getElementsByTagName("LI");

		for (var i = 0; i < feeds.length; i++) {
			if (feeds[i].id == "F-" + feed_id)
				feeds[i].className = "selected";
			else
				feeds[i].className = "";
		}

		_active_feed_id = feed_id;

	} catch (e) {
		exception_error("mark_selected_feed", e);
	}
}

function zoom(article_id) {
	try {
		var elem = $('A-' + article_id);

		if (elem) {
			var divs = elem.getElementsByTagName('DIV');

			for (var i = 0; i < divs.length; i++) {
				if (divs[i].className == 'excerpt')
					Element.hide(divs[i]);

				if (divs[i].className == 'content')
					Element.show(divs[i]);
			}
		}

		catchup_article(article_id,
			function() { update(); });

	} catch (e) {
		exception_error("zoom", e);
	}
}

function load_more() {
	try {
		viewfeed(_active_feed_id, _active_feed_offset + 10);
	} catch (e) {
		exception_error("load_more", e);
	}
}

function update() {
	try {
		console.log('updating feeds...');

		window.clearTimeout(_update_timeout);

		new Ajax.Request("backend.php",	{
			parameters: "?op=rpc&subop=digest-init",
			onComplete: function(transport) {
				fatal_error_check(transport);
				parse_feeds(transport);
				set_selected_feed(_active_feed_id);
				} });

		_update_timeout = window.setTimeout('update()', 5*1000);
	} catch (e) {
		exception_error("update", e);
	}
}

function remove_headline_entry(article_id) {
	try {
		var elem = $('A-' + article_id);

		if (elem) {
			elem.parentNode.removeChild(elem);
		}

	} catch (e) {
		exception_error("remove_headline_entry", e);
	}
}

function view(article_id, dismiss_only) {
	try {
		remove_headline_entry(article_id);

		catchup_article(article_id,
			function() { update(); });

		return dismiss_only != true;
	} catch (e) {
		exception_error("view", e);
	}
}

function viewfeed(feed_id, offset) {
	try {

		if (!feed_id) feed_id = _active_feed_id;

		if (!offset) {
			offset = 0;
		} else {
			offset = _active_feed_offset + offset;
		}

		var query = "backend.php?op=rpc&subop=digest-update&feed_id=" + feed_id +
				"&offset=" + offset;

		new Ajax.Request("backend.php",	{
			parameters: query,
			onComplete: function(transport) {
				fatal_error_check(transport);
				parse_headlines(transport, offset == 0);
				set_selected_feed(feed_id);
				_active_feed_offset = offset;
			} });

	} catch (e) {
		exception_error("view", e);
	}
}

function find_article(articles, article_id) {
	try {
		for (var i = 0; i < articles.length; i++) {
			if (articles[i].id == article_id)
				return articles[i];
		}

		return false;

	} catch (e) {
		exception_error("find_article", e);
	}
}

function find_feed(feeds, feed_id) {
	try {
		for (var i = 0; i < feeds.length; i++) {
			if (feeds[i].id == feed_id)
				return feeds[i];
		}

		return false;

	} catch (e) {
		exception_error("find_feed", e);
	}
}

function get_feed_icon(feed) {
	try {
		if (feed.has_icon)
			return 'icons/' + feed.id + '.ico';

		if (feed.id == -1)
			return 'images/mark_set.png';

		if (feed.id == -2)
			return 'images/pub_set.png';

		if (feed.id == -3)
			return 'images/fresh.png';

		if (feed.id == -4)
			return 'images/tag.png';

		if (feed.id < -10)
			return 'images/label.png';

		return 'images/blank_icon.gif';

	} catch (e) {
		exception_error("get_feed_icon", e);
	}
}

function add_feed_entry(feed) {
	try {
		var icon_part = "";

		icon_part = "";

		var tmp_html = "
" +
			icon_part +
			"" + feed.title +
			"
" + feed.unread + "
" +
			"
";

		$("feeds-content").innerHTML += tmp_html;

	} catch (e) {
		exception_error("add_feed_entry", e);
	}
}

function add_headline_entry(article, feed) {
	try {

		var icon_part = "";

		icon_part = "";

		var tmp_html = "
" +
			icon_part +
			"
" +
			"" +
			"" +
			"" +
			"
" +
			"" +
				article.title + "" +
			"
" +
			"
" +
				article.excerpt + "
" +
			"
" +
				article.content + "
" +
			"
" +
				feed.title + " " + " @ " +
				new Date(article.updated * 1000) + "
" +
			"

";

		$("headlines-content").innerHTML += tmp_html;

	} catch (e) {
		exception_error("add_headline_entry", e);
	}
}

function parse_feeds(transport) {
	try {

		var feeds = transport.responseXML.getElementsByTagName('feeds')[0];

		if (feeds) {
			feeds = eval("(" + feeds.firstChild.nodeValue + ")");

			feeds.sort( function (a,b)
				{
					if (b.unread != a.unread)
						return (b.unread - a.unread)
					else
						if (a.title > b.title)
							return 1;
						else if (a.title < b.title)
							return -1;
						else
							return 0;
				});

			last_feeds = feeds;

			$('feeds-content').innerHTML = "";

			for (var i = 0; i < feeds.length; i++) {
				add_feed_entry(feeds[i]);
			}
		}

	} catch (e) {
		exception_error("parse_feeds", e);
	}
}

function parse_headlines(transport, replace) {
	try {
		var headlines = transport.responseXML.getElementsByTagName('headlines')[0];

		if (headlines) {
			headlines = eval("(" + headlines.firstChild.nodeValue + ")");

			if (replace) $('headlines-content').innerHTML = '';

			var pr = $('MORE-PROMPT');

			if (pr) pr.parentNode.removeChild(pr);

			for (var i = 0; i < headlines.length; i++) {

				if (!$('A-' + headlines[i].id)) {
					add_headline_entry(headlines[i],
							find_feed(last_feeds, headlines[i].feed_id));
				}
			}

			if (pr) {
				$('headlines-content').appendChild(pr);
			} else {
				$('headlines-content').innerHTML += "
" +
					"
" +
				  	__("More articles...") + "

";
			}

			new Effect.Appear('headlines-content');
		}

	} catch (e) {
		exception_error("parse_headlines", e);
	}
}

/*function digest_update(transport, feed_id, offset) {
	try {
		var feeds = transport.responseXML.getElementsByTagName('feeds')[0];
		var headlines = transport.responseXML.getElementsByTagName('headlines')[0];

		if (feeds) {
			feeds = eval("(" + feeds.firstChild.nodeValue + ")");

			last_feeds = feeds;

			$('feeds-content').innerHTML = "";

			for (var i = 0; i < feeds.length; i++) {
				add_feed_entry(feeds[i]);
			}
		} else {
			feeds = last_feeds;
		}

		if (headlines) {
			headlines = eval("(" + headlines.firstChild.nodeValue + ")");

			if (_active_feed_id != feed_id || !offset)
				$('headlines-content').innerHTML = "";

			var pr = $('MORE-PROMPT');

			if (pr) {
				pr.id = '';
				Element.hide(pr);
			}

			for (var i = 0; i < headlines.length; i++) {
				var elem = $('A-' + headlines[i].id);

				if (elem && Element.visible(elem)) {
					if (!headlines[i].unread)
						remove_headline_entry(headlines[i].id);

				} else {
					add_headline_entry(headlines[i], find_feed(feeds, headlines[i].feed_id));
				}
			}

			$('headlines-content').innerHTML += "
" +
				"
" +
			  	__("More articles...") + "

";

			new Effect.Appear('headlines-content');
		}

		if (feed_id != undefined) {
			_active_feed_id = feed_id;
		}

		if (offset != undefined) _active_feed_offset = offset;

		mark_selected_feed(_active_feed_id);

	} catch (e) {
		exception_error("digest_update", e);
	}
} */

function init() {
	try {

		new Ajax.Request("backend.php",	{
			parameters: "backend.php?op=rpc&subop=digest-init",
			onComplete: function(transport) {
				parse_feeds(transport);
				window.setTimeout('viewfeed(-4)', 100);
				_update_timeout = window.setTimeout('update()', 5*1000);
				} });

	} catch (e) {
		exception_error("digest_init", e);
	}
}

function tMark_afh_off(effect) {
	try {
		var elem = effect.effects[0].element;

		console.log("tMark_afh_off : " + elem.id);

		if (elem) {
			elem.src = elem.src.replace("mark_set", "mark_unset");
			elem.alt = __("Star article");
			Element.show(elem);
		}

	} catch (e) {
		exception_error("tMark_afh_off", e);
	}
}

function tPub_afh_off(effect) {
	try {
		var elem = effect.effects[0].element;

		console.log("tPub_afh_off : " + elem.id);

		if (elem) {
			elem.src = elem.src.replace("pub_set", "pub_unset");
			elem.alt = __("Publish article");
			Element.show(elem);
		}

	} catch (e) {
		exception_error("tPub_afh_off", e);
	}
}

function toggleMark(mark_img, id) {

	try {

		var query = "?op=rpc&id=" + id + "&subop=mark";

		query = query + "&afid=" + _active_feed_id;
		query = query + "&omode=c";

		if (!mark_img) return;

		if (mark_img.src.match("mark_unset")) {
			mark_img.src = mark_img.src.replace("mark_unset", "mark_set");
			mark_img.alt = __("Unstar article");
			query = query + "&mark=1";
		} else {
			mark_img.alt = __("Please wait...");
			query = query + "&mark=0";

			mark_img.src = mark_img.src.replace("mark_set", "mark_unset");
			mark_img.alt = __("Star article");
		}

		new Ajax.Request("backend.php", {
			parameters: query,
			onComplete: function(transport) {
				//
			} });

	} catch (e) {
		exception_error("toggleMark", e);
	}
}

function togglePub(mark_img, id, note) {

	try {

		var query = "?op=rpc&id=" + id + "&subop=publ";

		query = query + "&afid=" + _active_feed_id;

		if (note != undefined) {
			query = query + "&note=" + param_escape(note);
		} else {
			query = query + "&note=undefined";
		}

		query = query + "&omode=c";

		if (!mark_img) return;

		if (mark_img.src.match("pub_unset") || note != undefined) {
			mark_img.src = mark_img.src.replace("pub_unset", "pub_set");
			mark_img.alt = __("Unpublish article");
			query = query + "&pub=1";

		} else {
			mark_img.alt = __("Please wait...");
			query = query + "&pub=0";

			mark_img.src = mark_img.src.replace("pub_set", "pub_unset");
			mark_img.alt = __("Publish article");
		}

		new Ajax.Request("backend.php", {
			parameters: query,
			onComplete: function(transport) {
				//
			} });

	} catch (e) {
		exception_error("togglePub", e);
	}
}

function fatal_error(code, msg) {
	try {

		if (code == 6) {
			window.location.href = "digest.php";
		} else if (code == 5) {
			window.location.href = "update.php";
		} else {

			if (msg == "") msg = "Unknown error";

			console.error("Fatal error: " + code + "\n" +
				msg);

		}

	} catch (e) {
		exception_error("fatalError", e);
	}
}

function fatal_error_check(transport) {
	try {
		if (transport.responseXML) {
			var error = transport.responseXML.getElementsByTagName("error")[0];

			if (error) {
				var code = error.getAttribute("error-code");
				var msg = error.getAttribute("error-msg");
				if (code != 0) {
					fatal_error(code, msg);
					return false;
				}
			}
		}
	} catch (e) {
		exception_error("fatal_error_check", e);
	}
	return true;
}

<|endoftext|>


<commit_before>/*!
 * dimsum.js v0.1
 * https://github.com/ninjascribble/dimsum
 * MIT licensed
 *
 * Copyright (C) 2012 Scott Grogan, http://ninjascript.com
 */
;(function(global) {

var classic = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",

cicero_1_10_32 = "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?",

cicero_1_10_33 = "At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.",

defaults = {
    'format': 'text',
    'flavor': 'latin',
    'sentences_per_paragraph': [3, 5],
    'words_per_sentence': [10, 31],
    'commas_per_sentence': [0, 4]
},

config = {},

punct = [',','.',';',':','?','!'],

punct_reg = new RegExp('[' + punct.join('') + ']*','g'),

flavors = {
    'latin': dedupe( normify([classic, cicero_1_10_32, cicero_1_10_33]).split(' ') )
},

dimsum = global.dimsum = exports = function(num_paragraphs, options) {
    return dimsum.generate(num_paragraphs, options);
};

// For client-side compatibility
if (typeof module !== 'undefined') module.exports = dimsum;

/**
 * The standard Lorem Ipsum passage.
 */
dimsum.classic = function() {
    return classic;
};

/**
 * Section 1.10.32 of Cicero's "de Finibus Bonorum et Malorum".
 */
dimsum.cicero32 = function() {
    return cicero_1_10_32;
};

/**
 * Section 1.10.33 of Cicero's "de Finibus Bonorum et Malorum".
 */
dimsum.cicero33 = function() {
    return cicero_1_10_33;
};

/**
 * Restore default configuration.
 */
dimsum.initialize = function() {
    return this.configure(defaults);
};

/**
 * Override the current configuration.
 *
 * @param options
 *      An object containing new config values.
 */
dimsum.configure = function(options) {
    config = shallow_copy(config, options);
    return this;
};

/**
 * @return A list of flavors that are currently available.
 */
dimsum.flavors = function() {
    return Object.keys(flavors);
};

/**
 * Creates a flavor out of the ingredients.
 *
 * @return An array containing the words used in this flavor.
 */
dimsum.flavor = function(name, ingredients) {

    if (arguments.length == 0) {
        return;
    }
    else if (arguments.length == 1) {

        if (name.match(/\s/)) {
            return dedupe( normify([name]).split(' ') );
        }
        else {
            return flavors[name];
        }
    }
    else {
        flavors[name] = (typeof ingredients == 'Array') ? ingredients : dedupe( normify([ingredients]).split(' ') );
        return flavors[name];
    }
};

/**
 * Create a random chunk of lipsum. Returns a string containing
 * the number of paragraphs specified.
 *
 * @param num_paragraphs
 *      How many paragraphs to generate.
 *
 * @param options
 *      An object containing new config values. The new options
 *      will only apply to this one execution.
 */
dimsum.generate = function(num_paragraphs, options) {

    var config_1 = config,
        sentences = [],
        paragraphs = [],
        result = '',
        num_paragraphs = num_paragraphs || 1;

    // Temporarily overwrite the configuration
    this.configure(options);

    // Add some paragraphs
    while (paragraphs.length < num_paragraphs) {
        paragraphs.push(this.paragraph());
    }

    // Make it pretty
    switch(config.format) {
        case 'text':
            result = paragraphs.join("\r\n\r\n");
            break;
        case 'html':
            result = '
' + paragraphs.join('

') + '
';
            break;
    }

    // Restore the original configuration
    config = config_1;

    return result;
};

/**
 * Create a single sentence of random lipsum.
 */
dimsum.sentence = function() {

    var word = '',
        words = [],
        num_words = range(config.words_per_sentence[0], config.words_per_sentence[1]),
        num_commas = range(config.commas_per_sentence[0], config.commas_per_sentence[1]),
        flavor = flavors[config.flavor];

    // Get some words
    while (words.length < num_words) {
        word = flavor[ range(0, flavor.length -1) ];
        words.push(word);
    }

    // Add some commas
    for (var i = 0; i < num_commas; i++) {
        word = range(4, words.length - 3);
        if (!words[word]) {
            break;
        }
        else if (words[word].match(',')) {
            i--;
        }
        else {
            words[word] += ',';
        }
    }

    // Capitalize the first word
    words = words.join(' ');
    words = words.replace(/^[a-z]/i, words[0].toUpperCase());

    // Punctuate and return
    return words + '.';
};

/**
 * Create a single paragraph of random lipsum.
 */
dimsum.paragraph = function() {

    var sentences = [],
        num_sentences = range(config.sentences_per_paragraph[0], config.sentences_per_paragraph[1]);

    while (sentences.length < num_sentences) {
        sentences.push(this.sentence());
    }
    return sentences.join(' ');
};

dimsum.initialize();

/** Utils **/
function normify(strings) {
    return strings.join(' ')
            .toLowerCase()
            .replace(punct_reg, '');
};

function dedupe(array) {

    var obj = {},
        result = [];

    for (var i = 0; i < array.length; i++) {
        obj[array[i]] = null;
    }
    for (key in obj) {
        result.push(key);
    }
    return result;
};

function range(min, max) {
    return min + Math.random() * (max - min) << 0;
};

function shallow_copy() {

    var i, key, result = {},
        args = Array.prototype.slice.call(arguments);

    for (i = 0; i < args.length; i++) {
        for (key in args[i]) {
            result[key] = args[i][key];
        }
    }
    return result;
};

/* Debug */
// dimsum.normify = normify;
// dimsum.dedupe = dedupe;
// dimsum.range = range;
// dimsum.shallow_copy = shallow_copy;

}(this));<commit_msg>Adding quotes, mdash and new lines to punctuation filter<commit_after>/*!
 * dimsum.js v0.1
 * https://github.com/ninjascribble/dimsum
 * MIT licensed
 *
 * Copyright (C) 2012 Scott Grogan, http://ninjascript.com
 */
;(function(global) {

var classic = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",

cicero_1_10_32 = "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?",

cicero_1_10_33 = "At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.",

defaults = {
    'format': 'text',
    'flavor': 'latin',
    'sentences_per_paragraph': [3, 5],
    'words_per_sentence': [10, 31],
    'commas_per_sentence': [0, 4]
},

config = {},

punct = [',','.',';',':','?','!','"','—','\r','\n'],

punct_reg = new RegExp('[' + punct.join('') + ']*','g'),

flavors = {
    'latin': dedupe( normify([classic, cicero_1_10_32, cicero_1_10_33]).split(' ') )
},

dimsum = global.dimsum = exports = function(num_paragraphs, options) {
    return dimsum.generate(num_paragraphs, options);
};

// For client-side compatibility
if (typeof module !== 'undefined') module.exports = dimsum;

/**
 * The standard Lorem Ipsum passage.
 */
dimsum.classic = function() {
    return classic;
};

/**
 * Section 1.10.32 of Cicero's "de Finibus Bonorum et Malorum".
 */
dimsum.cicero32 = function() {
    return cicero_1_10_32;
};

/**
 * Section 1.10.33 of Cicero's "de Finibus Bonorum et Malorum".
 */
dimsum.cicero33 = function() {
    return cicero_1_10_33;
};

/**
 * Restore default configuration.
 */
dimsum.initialize = function() {
    return this.configure(defaults);
};

/**
 * Override the current configuration.
 *
 * @param options
 *      An object containing new config values.
 */
dimsum.configure = function(options) {
    config = shallow_copy(config, options);
    return this;
};

/**
 * @return A list of flavors that are currently available.
 */
dimsum.flavors = function() {
    return Object.keys(flavors);
};

/**
 * Creates a flavor out of the ingredients.
 *
 * @return An array containing the words used in this flavor.
 */
dimsum.flavor = function(name, ingredients) {

    if (arguments.length == 0) {
        return;
    }
    else if (arguments.length == 1) {

        if (name.match(/\s/)) {
            return dedupe( normify([name]).split(' ') );
        }
        else {
            return flavors[name];
        }
    }
    else {
        flavors[name] = (typeof ingredients == 'Array') ? ingredients : dedupe( normify([ingredients]).split(' ') );
        return flavors[name];
    }
};

/**
 * Create a random chunk of lipsum. Returns a string containing
 * the number of paragraphs specified.
 *
 * @param num_paragraphs
 *      How many paragraphs to generate.
 *
 * @param options
 *      An object containing new config values. The new options
 *      will only apply to this one execution.
 */
dimsum.generate = function(num_paragraphs, options) {

    var config_1 = config,
        sentences = [],
        paragraphs = [],
        result = '',
        num_paragraphs = num_paragraphs || 1;

    // Temporarily overwrite the configuration
    this.configure(options);

    // Add some paragraphs
    while (paragraphs.length < num_paragraphs) {
        paragraphs.push(this.paragraph());
    }

    // Make it pretty
    switch(config.format) {
        case 'text':
            result = paragraphs.join("\r\n\r\n");
            break;
        case 'html':
            result = '
' + paragraphs.join('

') + '
';
            break;
    }

    // Restore the original configuration
    config = config_1;

    return result;
};

/**
 * Create a single sentence of random lipsum.
 */
dimsum.sentence = function() {

    var word = '',
        words = [],
        num_words = range(config.words_per_sentence[0], config.words_per_sentence[1]),
        num_commas = range(config.commas_per_sentence[0], config.commas_per_sentence[1]),
        flavor = flavors[config.flavor];

    // Get some words
    while (words.length < num_words) {
        word = flavor[ range(0, flavor.length -1) ];
        words.push(word);
    }

    // Add some commas
    for (var i = 0; i < num_commas; i++) {
        word = range(4, words.length - 3);
        if (!words[word]) {
            break;
        }
        else if (words[word].match(',')) {
            i--;
        }
        else {
            words[word] += ',';
        }
    }

    // Capitalize the first word
    words = words.join(' ');
    words = words.replace(/^[a-z]/i, words[0].toUpperCase());

    // Punctuate and return
    return words + '.';
};

/**
 * Create a single paragraph of random lipsum.
 */
dimsum.paragraph = function() {

    var sentences = [],
        num_sentences = range(config.sentences_per_paragraph[0], config.sentences_per_paragraph[1]);

    while (sentences.length < num_sentences) {
        sentences.push(this.sentence());
    }
    return sentences.join(' ');
};

dimsum.initialize();

/** Utils **/
function normify(strings) {
    return strings.join(' ')
            .toLowerCase()
            .replace(punct_reg, function(match) {
                if (match.match(/\r|\n/)) {
                    return ' ';
                }
                else {
                    return '';
                }
            });
};

function dedupe(array) {

    var obj = {},
        result = [];

    for (var i = 0; i < array.length; i++) {
        obj[array[i]] = null;
    }
    for (key in obj) {
        result.push(key);
    }
    return result;
};

function range(min, max) {
    return min + Math.random() * (max - min) << 0;
};

function shallow_copy() {

    var i, key, result = {},
        args = Array.prototype.slice.call(arguments);

    for (i = 0; i < args.length; i++) {
        for (key in args[i]) {
            result[key] = args[i][key];
        }
    }
    return result;
};

/* Debug */
// dimsum.normify = normify;
// dimsum.dedupe = dedupe;
// dimsum.range = range;
// dimsum.shallow_copy = shallow_copy;

}(this));<|endoftext|>


<commit_before>"use strict";

var React = require('react');
var ReactDOM = require('react-dom');

var animateScroll = require('./animate-scroll');
var scrollSpy = require('./scroll-spy');
var defaultScroller = require('./scroller');

var Helpers = {

  Scroll: function (Component, customScroller) {

    var scroller = customScroller || defaultScroller;

    return React.createClass({

      propTypes: {
        to: React.PropTypes.string.isRequired,
        offset: React.PropTypes.number,
        delay: React.PropTypes.number,
        isDynamic: React.PropTypes.bool,
        onClick: React.PropTypes.func,
        duration: React.PropTypes.oneOfType([React.PropTypes.number, React.PropTypes.func])
      },

      getDefaultProps: function() {
        return {offset: 0};
      },

      scrollTo : function(to, props) {
          scroller.scrollTo(to, props);
      },

      handleClick: function(event) {

        /*
         * give the posibility to override onClick
         */

        if(this.props.onClick) {
          this.props.onClick(event);
        }

        /*
         * dont bubble the navigation
         */

        if (event.stopPropagation) event.stopPropagation();
        if (event.preventDefault) event.preventDefault();

        /*
         * do the magic!
         */

        this.scrollTo(this.props.to, this.props);

      },

      spyHandler: function(y) {
        var element = scroller.get(this.props.to);
        if (!element) return;
        var cords = element.getBoundingClientRect();
        var topBound = cords.top + y;
        var bottomBound = topBound + cords.height;
        var offsetY = y - this.props.offset;
        var to = this.props.to;
        var isInside = (offsetY >= topBound && offsetY <= bottomBound);
        var isOutside = (offsetY < topBound || offsetY > bottomBound);
        var activeLink = scroller.getActiveLink();

        if (isOutside && activeLink === to) {
          scroller.setActiveLink(void 0);
          this.setState({ active : false });

        } else if (isInside && activeLink != to) {
          scroller.setActiveLink(to);
          this.setState({ active : true });

          if(this.props.onSetActive) {
            this.props.onSetActive(to);
          }

          scrollSpy.updateStates();
        }
      },

      componentDidMount: function() {

        scrollSpy.mount();

        if(this.props.spy) {
          var to = this.props.to;
          var element = null;
          var elemTopBound = 0;
          var elemBottomBound = 0;

          scrollSpy.addStateHandler((function() {
            if(scroller.getActiveLink() != to) {
                this.setState({ active : false });
            }
          }).bind(this));

          scrollSpy.addSpyHandler((function(y) {

            if(!element || this.props.isDynamic) {
                element = scroller.get(to);
                if(!element){ return;}

                var cords = element.getBoundingClientRect();
                elemTopBound = (cords.top + y);
                elemBottomBound = elemTopBound + cords.height;
            }

            var offsetY = y - this.props.offset;
            var isInside = (offsetY >= elemTopBound && offsetY <= elemBottomBound);
            var isOutside = (offsetY < elemTopBound || offsetY > elemBottomBound);
            var activeLink = scroller.getActiveLink();

            if (isOutside && activeLink === to) {
              scroller.setActiveLink(void 0);
              this.setState({ active : false });

            } else if (isInside && activeLink != to) {
              scroller.setActiveLink(to);
              this.setState({ active : true });

              if(this.props.onSetActive) {
                this.props.onSetActive(to);
              }

              scrollSpy.updateStates();

            }
          }).bind(this));
        }
      },
      componentWillUnmount: function() {
        scrollSpy.unmount();
      },
      render: function() {
        var className = "";
        if(this.state && this.state.active) {
          className = ((this.props.className || "") + " " + (this.props.activeClass || "active")).trim();
        } else {
          className = this.props.className
        }

        var props = {};
        for(var prop in this.props) {
          props[prop] = this.props[prop];
        }

        props.className = className;
        props.onClick = this.handleClick;

        return React.createElement(Component, props);
      }
    });
  },

  Element: function(Component) {
    return React.createClass({
      propTypes: {
        name: React.PropTypes.string.isRequired
      },
      componentDidMount: function() {
        var domNode = ReactDOM.findDOMNode(this);
        defaultScroller.register(this.props.name, domNode);
      },
      componentWillUnmount: function() {
        defaultScroller.unregister(this.props.name);
      },
      render: function() {
        return React.createElement(Component, this.props);
      }
    });
  }
};

module.exports = Helpers;
<commit_msg>Don't pass all props / new 15.2 warning fix<commit_after>"use strict";

var React = require('react');
var ReactDOM = require('react-dom');

var animateScroll = require('./animate-scroll');
var scrollSpy = require('./scroll-spy');
var defaultScroller = require('./scroller');

var Helpers = {

  Scroll: function (Component, customScroller) {

    var scroller = customScroller || defaultScroller;

    return React.createClass({

      propTypes: {
        to: React.PropTypes.string.isRequired,
        offset: React.PropTypes.number,
        delay: React.PropTypes.number,
        isDynamic: React.PropTypes.bool,
        onClick: React.PropTypes.func,
        duration: React.PropTypes.oneOfType([React.PropTypes.number, React.PropTypes.func])
      },

      getDefaultProps: function() {
        return {offset: 0};
      },

      scrollTo : function(to, props) {
          scroller.scrollTo(to, props);
      },

      handleClick: function(event) {

        /*
         * give the posibility to override onClick
         */

        if(this.props.onClick) {
          this.props.onClick(event);
        }

        /*
         * dont bubble the navigation
         */

        if (event.stopPropagation) event.stopPropagation();
        if (event.preventDefault) event.preventDefault();

        /*
         * do the magic!
         */

        this.scrollTo(this.props.to, this.props);

      },

      spyHandler: function(y) {
        var element = scroller.get(this.props.to);
        if (!element) return;
        var cords = element.getBoundingClientRect();
        var topBound = cords.top + y;
        var bottomBound = topBound + cords.height;
        var offsetY = y - this.props.offset;
        var to = this.props.to;
        var isInside = (offsetY >= topBound && offsetY <= bottomBound);
        var isOutside = (offsetY < topBound || offsetY > bottomBound);
        var activeLink = scroller.getActiveLink();

        if (isOutside && activeLink === to) {
          scroller.setActiveLink(void 0);
          this.setState({ active : false });

        } else if (isInside && activeLink != to) {
          scroller.setActiveLink(to);
          this.setState({ active : true });

          if(this.props.onSetActive) {
            this.props.onSetActive(to);
          }

          scrollSpy.updateStates();
        }
      },

      componentDidMount: function() {

        scrollSpy.mount();

        if(this.props.spy) {
          var to = this.props.to;
          var element = null;
          var elemTopBound = 0;
          var elemBottomBound = 0;

          scrollSpy.addStateHandler((function() {
            if(scroller.getActiveLink() != to) {
                this.setState({ active : false });
            }
          }).bind(this));

          scrollSpy.addSpyHandler((function(y) {

            if(!element || this.props.isDynamic) {
                element = scroller.get(to);
                if(!element){ return;}

                var cords = element.getBoundingClientRect();
                elemTopBound = (cords.top + y);
                elemBottomBound = elemTopBound + cords.height;
            }

            var offsetY = y - this.props.offset;
            var isInside = (offsetY >= elemTopBound && offsetY <= elemBottomBound);
            var isOutside = (offsetY < elemTopBound || offsetY > elemBottomBound);
            var activeLink = scroller.getActiveLink();

            if (isOutside && activeLink === to) {
              scroller.setActiveLink(void 0);
              this.setState({ active : false });

            } else if (isInside && activeLink != to) {
              scroller.setActiveLink(to);
              this.setState({ active : true });

              if(this.props.onSetActive) {
                this.props.onSetActive(to);
              }

              scrollSpy.updateStates();

            }
          }).bind(this));
        }
      },
      componentWillUnmount: function() {
        scrollSpy.unmount();
      },
      render: function() {
        var className = "";
        if(this.state && this.state.active) {
          className = ((this.props.className || "") + " " + (this.props.activeClass || "active")).trim();
        } else {
          className = this.props.className
        }

        var props = {};
        for(var prop in this.props) {
          props[prop] = this.props[prop];
        }

        props.className = className;
        props.onClick = this.handleClick;

        return React.createElement(Component,
          {
            className: className,
            children: this.props.children,
            onClick: this.handleClick
          }
        );
      }
    });
  },

  Element: function(Component) {
    return React.createClass({
      propTypes: {
        name: React.PropTypes.string.isRequired
      },
      componentDidMount: function() {
        var domNode = ReactDOM.findDOMNode(this);
        defaultScroller.register(this.props.name, domNode);
      },
      componentWillUnmount: function() {
        defaultScroller.unregister(this.props.name);
      },
      render: function() {
        return React.createElement(Component,
          {
            className: this.props.className,
            children: this.props.children
          }
        );
      }
    });
  }
};

module.exports = Helpers;
<|endoftext|>


<commit_before>"use strict";

var React = require('react');
var ReactDOM = require('react-dom');

var animateScroll = require('./animate-scroll');
var scrollSpy = require('./scroll-spy');
var defaultScroller = require('./scroller');
var assign = require('object-assign');

var protoTypes = {
  to: React.PropTypes.string.isRequired,
  containerId: React.PropTypes.string,
  activeClass:React.PropTypes.string,
  spy: React.PropTypes.bool,
  smooth: React.PropTypes.bool,
  offset: React.PropTypes.number,
  delay: React.PropTypes.number,
  isDynamic: React.PropTypes.bool,
  onClick: React.PropTypes.func,
  duration: React.PropTypes.oneOfType([React.PropTypes.number, React.PropTypes.func]),
  absolute: React.PropTypes.bool,
  onSetActive: React.PropTypes.func
};

var Helpers = {

  Scroll: function (Component, customScroller) {

    var scroller = customScroller || defaultScroller;

    return React.createClass({

      propTypes: protoTypes,

      getDefaultProps: function() {
        return {offset: 0};
      },

      scrollTo : function(to, props) {
          scroller.scrollTo(to, props);
      },

      handleClick: function(event) {

        /*
         * give the posibility to override onClick
         */

        if(this.props.onClick) {
          this.props.onClick(event);
        }

        /*
         * dont bubble the navigation
         */

        if (event.stopPropagation) event.stopPropagation();
        if (event.preventDefault) event.preventDefault();

        /*
         * do the magic!
         */
        this.scrollTo(this.props.to, this.props);

      },

      spyHandler: function(y) {
        var element = scroller.get(this.props.to);
        if (!element) return;
        var cords = element.getBoundingClientRect();
        var topBound = cords.top + y;
        var bottomBound = topBound + cords.height;
        var offsetY = y - this.props.offset;
        var to = this.props.to;
        var isInside = (offsetY >= topBound && offsetY <= bottomBound);
        var isOutside = (offsetY < topBound || offsetY > bottomBound);
        var activeLink = scroller.getActiveLink();

        if (isOutside && activeLink === to) {
          scroller.setActiveLink(void 0);
          this.setState({ active : false });

        } else if (isInside && activeLink != to) {
          scroller.setActiveLink(to);
          this.setState({ active : true });

          if(this.props.onSetActive) {
            this.props.onSetActive(to);
          }

          scrollSpy.updateStates();
        }
      },

      componentDidMount: function() {

        var containerId = this.props.containerId;

        var scrollSpyContainer = containerId ? document.getElementById(containerId) : document;

        if(!scrollSpy.isMounted(scrollSpyContainer)) {
          scrollSpy.mount(scrollSpyContainer);
        }

        if(this.props.spy) {
          var to = this.props.to;
          var element = null;
          var elemTopBound = 0;
          var elemBottomBound = 0;

          scrollSpy.addStateHandler((function() {
            if(scroller.getActiveLink() != to) {
                this.setState({ active : false });
            }
          }).bind(this));

          var spyHandler = function(y) {
            if(!element || this.props.isDynamic) {
                element = scroller.get(to);
                if(!element){ return;}

                var cords = element.getBoundingClientRect();
                elemTopBound = (cords.top + y);
                elemBottomBound = elemTopBound + cords.height;
            }

            var offsetY = y - this.props.offset;
            var isInside = (offsetY >= Math.floor(elemTopBound) && offsetY <= Math.floor(elemBottomBound));
            var isOutside = (offsetY < Math.floor(elemTopBound) || offsetY > Math.floor(elemBottomBound));
            var activeLink = scroller.getActiveLink();

            if (isOutside && activeLink === to) {
              scroller.setActiveLink(void 0);
              this.setState({ active : false });

            } else if (isInside && activeLink != to) {
              scroller.setActiveLink(to);
              this.setState({ active : true });

              if(this.props.onSetActive) {
                this.props.onSetActive(to);
              }

              scrollSpy.updateStates();

            }
          }.bind(this);

          scrollSpy.addSpyHandler(spyHandler, scrollSpyContainer);
        }
      },
      componentWillUnmount: function() {
        scrollSpy.unmount();
      },
      render: function() {

        var className = "";
        if(this.state && this.state.active) {
          className = ((this.props.className || "") + " " + (this.props.activeClass || "active")).trim();
        } else {
          className = this.props.className;
        }

        var props = assign({}, this.props);

        for(var prop in protoTypes) {
          if(props.hasOwnProperty(prop)) {
            delete props[prop];
          }
        }

        props.className = className;
        props.onClick = this.handleClick;

        return React.createElement(Component, props);
      }
    });
  },

  Element: function(Component) {
    return React.createClass({
      propTypes: {
        name: React.PropTypes.string.isRequired
      },
      componentDidMount: function() {
        var domNode = ReactDOM.findDOMNode(this);
        defaultScroller.register(this.props.name, domNode);
      },
      componentWillUnmount: function() {
        defaultScroller.unregister(this.props.name);
      },
      render: function() {
        return React.createElement(Component, this.props);
      }
    });
  }
};

module.exports = Helpers;
<commit_msg>Helpers.js now takes the position of the scroll container into account, instead of defaulting to the top of the browswer window. (#134)<commit_after>"use strict";

var React = require('react');
var ReactDOM = require('react-dom');

var animateScroll = require('./animate-scroll');
var scrollSpy = require('./scroll-spy');
var defaultScroller = require('./scroller');
var assign = require('object-assign');

var protoTypes = {
  to: React.PropTypes.string.isRequired,
  containerId: React.PropTypes.string,
  activeClass:React.PropTypes.string,
  spy: React.PropTypes.bool,
  smooth: React.PropTypes.bool,
  offset: React.PropTypes.number,
  delay: React.PropTypes.number,
  isDynamic: React.PropTypes.bool,
  onClick: React.PropTypes.func,
  duration: React.PropTypes.oneOfType([React.PropTypes.number, React.PropTypes.func]),
  absolute: React.PropTypes.bool,
  onSetActive: React.PropTypes.func
};

var Helpers = {

  Scroll: function (Component, customScroller) {

    var scroller = customScroller || defaultScroller;

    return React.createClass({

      propTypes: protoTypes,

      getDefaultProps: function() {
        return {offset: 0};
      },

      scrollTo : function(to, props) {
          scroller.scrollTo(to, props);
      },

      handleClick: function(event) {

        /*
         * give the posibility to override onClick
         */

        if(this.props.onClick) {
          this.props.onClick(event);
        }

        /*
         * dont bubble the navigation
         */

        if (event.stopPropagation) event.stopPropagation();
        if (event.preventDefault) event.preventDefault();

        /*
         * do the magic!
         */
        this.scrollTo(this.props.to, this.props);

      },

      spyHandler: function(y) {
        var element = scroller.get(this.props.to);
        if (!element) return;
        var cords = element.getBoundingClientRect();
        var topBound = cords.top + y;
        var bottomBound = topBound + cords.height;
        var offsetY = y - this.props.offset;
        var to = this.props.to;
        var isInside = (offsetY >= topBound && offsetY <= bottomBound);
        var isOutside = (offsetY < topBound || offsetY > bottomBound);
        var activeLink = scroller.getActiveLink();

        if (isOutside && activeLink === to) {
          scroller.setActiveLink(void 0);
          this.setState({ active : false });

        } else if (isInside && activeLink != to) {
          scroller.setActiveLink(to);
          this.setState({ active : true });

          if(this.props.onSetActive) {
            this.props.onSetActive(to);
          }

          scrollSpy.updateStates();
        }
      },

      componentDidMount: function() {

        var containerId = this.props.containerId;

        var scrollSpyContainer = containerId ? document.getElementById(containerId) : document;

        if(!scrollSpy.isMounted(scrollSpyContainer)) {
          scrollSpy.mount(scrollSpyContainer);
        }

        if(this.props.spy) {
          var to = this.props.to;
          var element = null;
          var elemTopBound = 0;
          var elemBottomBound = 0;

          scrollSpy.addStateHandler((function() {
            if(scroller.getActiveLink() != to) {
                this.setState({ active : false });
            }
          }).bind(this));

          var spyHandler = function(y) {

            var containerCords = scrollSpyContainer.getBoundingClientRect();
            var containerTop = containerCords.top;

            if(!element || this.props.isDynamic) {
                element = scroller.get(to);
                if(!element){ return;}

                var cords = element.getBoundingClientRect();
                elemTopBound = (cords.top - containerTop + y);
                elemBottomBound = elemTopBound + cords.height;
            }

            var offsetY = y - this.props.offset;
            var isInside = (offsetY >= Math.floor(elemTopBound) && offsetY <= Math.floor(elemBottomBound));
            var isOutside = (offsetY < Math.floor(elemTopBound) || offsetY > Math.floor(elemBottomBound));
            var activeLink = scroller.getActiveLink();

            if (isOutside && activeLink === to) {
              scroller.setActiveLink(void 0);
              this.setState({ active : false });

            } else if (isInside && activeLink != to) {
              scroller.setActiveLink(to);
              this.setState({ active : true });

              if(this.props.onSetActive) {
                this.props.onSetActive(to);
              }

              scrollSpy.updateStates();

            }
          }.bind(this);

          scrollSpy.addSpyHandler(spyHandler, scrollSpyContainer);
        }
      },
      componentWillUnmount: function() {
        scrollSpy.unmount();
      },
      render: function() {

        var className = "";
        if(this.state && this.state.active) {
          className = ((this.props.className || "") + " " + (this.props.activeClass || "active")).trim();
        } else {
          className = this.props.className;
        }

        var props = assign({}, this.props);

        for(var prop in protoTypes) {
          if(props.hasOwnProperty(prop)) {
            delete props[prop];
          }
        }

        props.className = className;
        props.onClick = this.handleClick;

        return React.createElement(Component, props);
      }
    });
  },

  Element: function(Component) {
    return React.createClass({
      propTypes: {
        name: React.PropTypes.string.isRequired
      },
      componentDidMount: function() {
        var domNode = ReactDOM.findDOMNode(this);
        defaultScroller.register(this.props.name, domNode);
      },
      componentWillUnmount: function() {
        defaultScroller.unregister(this.props.name);
      },
      render: function() {
        return React.createElement(Component, this.props);
      }
    });
  }
};

module.exports = Helpers;
<|endoftext|>