<commit_before>/*global State, Config*/

State.Menu = function (game) {
	"use strict";
	this.game = game;
};
State.Menu.prototype = {
	create: function () {
		"use strict";
		var background, buttonPlay, buttonCredits, buttonHowToPlay;
		background = this.game.add.sprite(Config.menu.x, Config.menu.y, 'menu-background');
		buttonPlay = this.game.add.button(Config.menu.buttonPlay.x, Config.menu.buttonPlay.y, 'button-play', this.clickPlay, this, 1, 0, 2, 1);
		buttonPlay.anchor.setTo(Config.menu.buttonPlay.anchor.x, Config.menu.buttonPlay.anchor.y);
		buttonHowToPlay = this.game.add.button(Config.menu.buttonHowToPlay.x, Config.menu.buttonHowToPlay.y, 'button-how-to-play', this.clickHowToPlay, this, 0, 1, 2, 0);
		buttonHowToPlay.anchor.setTo(Config.menu.buttonHowToPlay.anchor.x, Config.menu.buttonHowToPlay.anchor.y);
		buttonCredits = this.game.add.button(Config.menu.buttonCredits.x, Config.menu.buttonCredits.y, 'button-credits', this.clickCredits, this, 2, 1, 0, 0);
		buttonCredits.anchor.setTo(Config.menu.buttonCredits.anchor.x, Config.menu.buttonCredits.anchor.y);
	},
	update: function () {
		"use strict";
		Config.global.screen.resize(this.game);
	},
	clickPlay: function () {
		"use strict";
		this.game.state.start('Story');
	},
	clickHowToPlay: function () {
		"use strict";
		this.game.state.start('HowToPlay');
	},
	clickCredits: function () {
		"use strict";
		this.game.state.start('Credits');
	}
};<commit_msg>Adicao da musica de fundo a tela de menu<commit_after>/*global State, Config*/

State.Menu = function (game) {
	"use strict";
	this.game = game;
};
State.Menu.prototype = {
	create: function () {
		"use strict";
		var background, buttonPlay, buttonCredits, buttonHowToPlay;
		background = this.game.add.sprite(Config.menu.x, Config.menu.y, 'menu-background');
		buttonPlay = this.game.add.button(Config.menu.buttonPlay.x, Config.menu.buttonPlay.y, 'button-play', this.clickPlay, this, 1, 0, 2, 1);
		buttonPlay.anchor.setTo(Config.menu.buttonPlay.anchor.x, Config.menu.buttonPlay.anchor.y);
		buttonHowToPlay = this.game.add.button(Config.menu.buttonHowToPlay.x, Config.menu.buttonHowToPlay.y, 'button-how-to-play', this.clickHowToPlay, this, 0, 1, 2, 0);
		buttonHowToPlay.anchor.setTo(Config.menu.buttonHowToPlay.anchor.x, Config.menu.buttonHowToPlay.anchor.y);
		buttonCredits = this.game.add.button(Config.menu.buttonCredits.x, Config.menu.buttonCredits.y, 'button-credits', this.clickCredits, this, 2, 1, 0, 0);
		buttonCredits.anchor.setTo(Config.menu.buttonCredits.anchor.x, Config.menu.buttonCredits.anchor.y);

		this.backgroundSound = game.add.audio('music');
		this.backgroundSound.play('',0,0.8,true);
	},
	update: function () {
		"use strict";
		Config.global.screen.resize(this.game);
	},
	clickPlay: function () {
		"use strict";
		this.backgroundSound.stop();
		this.game.state.start('Story');
	},
	clickHowToPlay: function () {
		"use strict";
		this.game.state.start('HowToPlay');
	},
	clickCredits: function () {
		"use strict";
		this.game.state.start('Credits');
	}
};<|endoftext|>


<commit_before>// IBIS application

// This is an unfinished work in progress

// References:
// arrow marker: https://stackoverflow.com/questions/12680166/how-to-use-an-arrow-marker-on-an-svg-line-element
// arrowhead derived from: https://stackoverflow.com/questions/11808860/how-to-place-arrow-head-triangles-on-svg-lines
// marker-end: http://tutorials.jenkov.com/svg/marker-element.html
// line to edge of circle: https://stackoverflow.com/questions/13165913/draw-an-arrow-between-two-circles#13234898

/* global CompendiumIcons */

// You need to have run the snippet which defines the CompendiumIcons global with the IBIS icons first
// This next section does that for you if needed with the local storage journal, but not with the memory journal
if (!window.CompendiumIcons) {
    const iconLoaderResource = {
        name: "Compendium Icons Loader",
        id: "28746681f0477c2d66e09e3c4fc3c73ede3dcb3d5f972aaa3d281e09d8d01270"
    }

    const iconLoader = Twirlip7.getCurrentJournal().getItem(iconLoaderResource.id)
    if (iconLoader) {
        /* eslint no-eval: 0 */
        /* jslint evil: true */
        eval(iconLoader)
    }
}

const diagram = []

// tiny stack for connecting items
let firstDraggedItem = null
let secondDraggedItem = null

let draggedItem = null
let dragStart = {x: 0, y: 0}
let objectStart = {x: 0, y: 0}

let mouseTrackingPosition = {x: 0, y: 0}

function onmousedown(element, event) {
    firstDraggedItem = secondDraggedItem
    secondDraggedItem = element
    draggedItem = element
    dragStart = { x: event.clientX, y: event.clientY }
    objectStart = { x: element.x, y: element.y }
}

function onmousemove(event) {
    if (draggedItem) {
        const dx = event.clientX - dragStart.x
        const dy = event.clientY - dragStart.y
        const newX = objectStart.x + dx
        const newY = objectStart.y + dy
        draggedItem.x = newX
        draggedItem.y = newY
    } else {
        mouseTrackingPosition = {x: event.clientX, y: event.clientY }
    }
}

function onmouseup() {
    draggedItem = null
}

function onkeydown(event) {
    console.log("onkeydown", event)
}

function newX() {
    return (20 + (diagram.length * 37)) % 600
}

function newY() {
    return (50 + (diagram.length * 23)) % 300
}

function addElement(type) {
    const name = prompt(type + " name")
    if (!name) return
    diagram.unshift({ type: type, name: name, x: newX(), y: newY() } )
}

function addLink() {
    if (!firstDraggedItem) return
    if (!secondDraggedItem) return
    firstDraggedItem.parent = secondDraggedItem
}

// Need to add undo

function deleteLink() {
    if (!secondDraggedItem) return
    secondDraggedItem.parent = undefined
}

function deleteElement() {
    const elementToDelete = secondDraggedItem
    if (!elementToDelete) return
    const index = diagram.indexOf(elementToDelete)
    if (index > -1) {
        diagram.splice(index, 1)
    }
    for (let element of diagram) {
        if (element.parent === elementToDelete) element.parent = null
    }
}

function viewLink(element) {
    const parent = element.parent
    if (!parent) return

    const xA = parent.x
    const yA = parent.y
    const xB = element.x
    const yB = element.y
    const radius = 24

    const d = Math.sqrt((xB - xA) * (xB - xA) + (yB - yA) * (yB - yA))
    const d2 = d - radius

    const ratio = d2 / d

    const dx = (xB - xA) * ratio
    const dy = (yB - yA) * ratio

    const x = xA + dx
    const y = yA + dy

    return m("line", {
        x1: x,
        y1: y,
        x2: element.x - dx,
        y2: element.y - dy,
        "marker-end": "url(#arrowhead)",
        stroke: "black",
        "stroke-width": 1
    })
}

function viewElement(element) {
    return [
        m("image", {
            "xlink:href": CompendiumIcons[element.type + "_png"],
            x: element.x - 16,
            y: element.y - 16,
            width: 32,
            height: 32,
            alt: "question",
            onmousedown: (event) => onmousedown(element, event)
        }),
        m("text", {x: element.x, y: element.y + 34, "text-anchor": "middle"}, element.name)
    ]
}

function viewArrowhead() {
    return m("marker", {
        id: "arrowhead",
        orient: "auto",
        markerWidth: 8,
        markerHeight: 16,
        refX: 2,
        refY: 4,
    }, m("path", { d: "M0,0 V8 L8,4 Z", fill: "black" }))
}

Twirlip7.show(() => {
    return [
        m("button.ma1", { onclick: addElement.bind(null, "issue") }, "Add question"),
        m("button.ma1", { onclick: addElement.bind(null, "position") }, "Add position"),
        m("button.ma1", { onclick: addElement.bind(null, "plus") }, "Add plus"),
        m("button.ma1", { onclick: addElement.bind(null, "minus") }, "Add minus"),
        m("button.ma1", { onclick: addLink }, "Link last two"),
        m("button.ma1", { onclick: deleteLink }, "Delete link"),
        m("button.ma1", { onclick: deleteElement }, "Delete element"),
        m("br"),
        // on keydown does not seem to work here
        m("svg.diagram.ba", { width: 600, height: 300, onmousemove: onmousemove, onmouseup: onmouseup, onkeydown: onkeydown },
            viewArrowhead(),
            diagram.map((element) => {
                return viewLink(element)
            }),
            diagram.map((element) => {
                return viewElement(element)
            })
        )
    ]
}, ".bg-blue.br4")
<commit_msg>improve ibis application so new item at last click<commit_after>// IBIS application

// This is an unfinished work in progress

// References:
// arrow marker: https://stackoverflow.com/questions/12680166/how-to-use-an-arrow-marker-on-an-svg-line-element
// arrowhead derived from: https://stackoverflow.com/questions/11808860/how-to-place-arrow-head-triangles-on-svg-lines
// marker-end: http://tutorials.jenkov.com/svg/marker-element.html
// line to edge of circle: https://stackoverflow.com/questions/13165913/draw-an-arrow-between-two-circles#13234898

/* global CompendiumIcons */

// You need to have run the snippet which defines the CompendiumIcons global with the IBIS icons first
// This next section does that for you if needed
if (!window.CompendiumIcons) {
    const iconLoaderResource = {
        name: "Compendium Icons Loader",
        id: "28746681f0477c2d66e09e3c4fc3c73ede3dcb3d5f972aaa3d281e09d8d01270"
    }

    const iconLoader = Twirlip7.getCurrentJournal().getItem(iconLoaderResource.id)
    if (iconLoader) {
        /* eslint no-eval: 0 */
        /* jslint evil: true */
        eval(iconLoader)
    }
}

const diagram = []

// tiny stack for connecting items
let firstDraggedItem = null
let secondDraggedItem = null

let draggedItem = null
let dragStart = {x: 0, y: 0}
let objectStart = {x: 0, y: 0}

let mouseTrackingPosition = {x: 0, y: 0}
let lastClickPosition = null

function onmousedownBackground(event) {
    if (draggedItem) return
    console.log("onmousedownBackground")
    const rect = event.target.getBoundingClientRect();
    lastClickPosition = { x: event.clientX - rect.left, y: event.clientY - rect.top }
}

function onmousedown(element, event) {
    console.log("onmousedown")
    lastClickPosition = null
    firstDraggedItem = secondDraggedItem
    secondDraggedItem = element
    draggedItem = element
    dragStart = { x: event.clientX, y: event.clientY }
    objectStart = { x: element.x, y: element.y }
}

function onmousemove(event) {
    console.log("mouse move")
    if (draggedItem) {
        const dx = event.clientX - dragStart.x
        const dy = event.clientY - dragStart.y
        const newX = objectStart.x + dx
        const newY = objectStart.y + dy
        draggedItem.x = newX
        draggedItem.y = newY
    } else {
        mouseTrackingPosition = {x: event.clientX, y: event.clientY }
    }
}

function onmouseup() {
    console.log("mouse up")
    draggedItem = null
}

function onkeydown(event) {
    console.log("onkeydown", event)
}

function newX() {
    return (20 + (diagram.length * 37)) % 600
}

function newY() {
    return (50 + (diagram.length * 23)) % 300
}

function addElement(type) {
    const name = prompt(type + " name")
    if (!name) return
    const x = lastClickPosition ? lastClickPosition.x : newX()
    const y = lastClickPosition ? lastClickPosition.y : newY()
    diagram.unshift({ type: type, name: name, x: x, y: y })
    if (lastClickPosition) {
        lastClickPosition.x += 37;
        lastClickPosition.y += 23;
    }
}

function addLink() {
    if (!firstDraggedItem) return
    if (!secondDraggedItem) return
    firstDraggedItem.parent = secondDraggedItem
}

// Need to add undo

function deleteLink() {
    if (!secondDraggedItem) return
    secondDraggedItem.parent = undefined
}

function deleteElement() {
    if (!secondDraggedItem) return
    const index = diagram.indexOf(secondDraggedItem)
    if (index > -1) {
        diagram.splice(index, 1)
    }
}

function viewLink(element) {
    const parent = element.parent
    if (!parent) return

    const xA = parent.x
    const yA = parent.y
    const xB = element.x
    const yB = element.y
    const radius = 24

    const d = Math.sqrt((xB - xA) * (xB - xA) + (yB - yA) * (yB - yA))
    const d2 = d - radius

    const ratio = d2 / d

    const dx = (xB - xA) * ratio
    const dy = (yB - yA) * ratio

    const x = xA + dx
    const y = yA + dy

    return m("line", {
        x1: x,
        y1: y,
        x2: element.x - dx,
        y2: element.y - dy,
        "marker-end": "url(#arrowhead)",
        stroke: "black",
        "stroke-width": 1
    })
}

function viewElement(element) {
    return [
        m("image", {
            "xlink:href": CompendiumIcons[element.type + "_png"],
            x: element.x - 16,
            y: element.y - 16,
            width: 32,
            height: 32,
            alt: "question",
            onmousedown: (event) => onmousedown(element, event)
        }),
        m("text", {x: element.x, y: element.y + 34, "text-anchor": "middle"}, element.name)
    ]
}

function viewArrowhead() {
    return m("marker", {
        id: "arrowhead",
        orient: "auto",
        markerWidth: 8,
        markerHeight: 16,
        refX: 2,
        refY: 4,
    }, m("path", { d: "M0,0 V8 L8,4 Z", fill: "black" }))
}

Twirlip7.show(() => {
    return [
        m("button.ma1", { onclick: addElement.bind(null, "issue") }, "Add question"),
        m("button.ma1", { onclick: addElement.bind(null, "position") }, "Add position"),
        m("button.ma1", { onclick: addElement.bind(null, "plus") }, "Add plus"),
        m("button.ma1", { onclick: addElement.bind(null, "minus") }, "Add minus"),
        m("button.ma1", { onclick: addLink }, "Link last two"),
        m("button.ma1", { onclick: deleteLink }, "Delete link"),
        m("button.ma1", { onclick: deleteElement }, "Delete element"),
        m("br"),
        // on keydown does not seem to work here
        m("svg.diagram.ba", { width: 600, height: 300, onmousedown: onmousedownBackground, onmousemove: onmousemove, onmouseup: onmouseup, onkeydown: onkeydown },
            viewArrowhead(),
            diagram.map((element) => {
                return viewLink(element)
            }),
            diagram.map((element) => {
                return viewElement(element)
            })
        )
    ]
}, ".bg-blue.br4")
<|endoftext|>


<commit_before>/* File: print.js
 *
 * Copyright (c) 2014
 * Centre National d’Enseignement à Distance (Cned), Boulevard Nicephore Niepce, 86360 CHASSENEUIL-DU-POITOU, France
 * (direction-innovation@cned.fr)
 *
 * GNU Affero General Public License (AGPL) version 3.0 or later version
 *
 * This file is part of a program which is free software: you can
 * redistribute it and/or modify it under the terms of the
 * GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License along with this program.
 * If not, see <http://www.gnu.org/licenses/>.
 *
 */

/*jshint loopfunc:true*/
/*global $:false, blocks */

'use strict';

angular.module('cnedApp').controller('PrintCtrl', function($scope, $rootScope, $http, $window, $location, configuration, dropbox, removeHtmlTags) {

	$scope.data = [];
	// $scope.blocks = [];
	$scope.blocksAlternative = [];
	$scope.plans = [];
	$scope.showApercu = 'hidden';
	$scope.showPlan = 'visible';
	$scope.counterElements = 0;
	$scope.styleParagraphe = '';
	/* activer le loader */
	$scope.loader = false;
	var numTitre = 0;
	$scope.showPlan = true;
	$scope.isPagePlan = false;

	/* Mette à jour dernier document affiché */
	if ($location.absUrl()) {
		localStorage.setItem('lastDocument', $location.absUrl());
		$scope.encodeURI = decodeURI($location.absUrl());
	}

	$scope.requestToSend = {};
	if (localStorage.getItem('compteId')) {
		$scope.requestToSend = {
			id: localStorage.getItem('compteId')
		};
	}

	$scope.showTitleDoc = function() {
		var docUrl = decodeURI($location.absUrl());
		docUrl = docUrl.replace('#/apercu', '');
		$rootScope.titreDoc = decodeURIComponent(/((_+)([A-Za-z0-9_%]*)(_+))/i.exec(encodeURIComponent(docUrl))[0].replace('_', '').replace('_', ''));
		console.log('titre document ==> ');
		console.log($rootScope.titreDoc);
		$('#titreDocumentApercu').show();
	};
	$scope.showTitleDoc();

	$scope.populateApercu = function() {
		console.log('in populateApercu ==> ');
		console.log(blocks);
		// Selection des profils tags pour le style
		if (blocks && blocks.children.length > 0) {
			$scope.profiltags = JSON.parse(localStorage.getItem('listTagsByProfil'));
			//Selection des tags pour le plan
			$scope.tags = JSON.parse(localStorage.getItem('listTags'));
			var blocksArray = angular.fromJson(blocks);
			console.log(blocksArray);
			var j = 0;
			$scope.blocksPlan = [];
			$scope.blocksPlan[0] = [];
			$scope.blocksPlan[0][0] = [];

			for (var i = 0; i < blocksArray.children.length; i++) {
				$scope.blocksPlan[i + 1] = [];
				j = 0;
				blocksArray.children[i].root = true;
				traverseRoot(blocksArray.children[i], i, j);
				traverseLeaf(blocksArray.children[i].children, i, j);
			}

			$scope.plans.forEach(function(entry) {
				entry.style = '
 ' + entry.libelle + '
';
			});

			var mode = parseInt($location.search().mode);
			var printPlan = parseInt($location.search().plan);
			$scope.pageTraites = [];
			if (mode === 1 || mode === 2) {
				var pageDe = parseInt($location.search().de);
				var pageA = parseInt($location.search().a);
				console.log('pageDe ===>' + pageDe);
				console.log('pageA ===>' + pageA);
				if (pageDe > 0 && pageA > 0 && pageDe <= pageA) {
					var blocksPlanTmp = $scope.blocksPlan.slice(pageDe, pageA + 1);
					console.log(blocksPlanTmp);
					$scope.blocksPlan = [];
					$scope.blocksPlan[0] = [];
					$scope.blocksPlan[0][0] = [];
					for (var j = 0; j < blocksPlanTmp.length; j++) {
						$scope.blocksPlan[j + 1] = blocksPlanTmp[j];
					}

					for (var k = pageDe; k <= pageA; k++) {
						$scope.pageTraites.push(k);
					}

				} else {
					printPlan = 1;
					$scope.isPagePlan = true;
					$scope.blocksPlan = [];
					$scope.blocksPlan[0] = [];
					$scope.blocksPlan[0][0] = [];
				}
			}

			if (printPlan === 0) {
				$scope.showPlan = false;
				$scope.plans = [];
			}

			$scope.loader = false;
		}
	};

	if (localStorage.getItem('listTagsByProfil') && localStorage.getItem('listTags')) {
		console.log('starting populate');
		$scope.populateApercu();
	}

	function getTitleIndex(titre) {
		return parseInt(titre.substring(titre.length - 1, titre.length));
	}

	function limitParagraphe(titre) {
		var taille = 0;
		var limite = 80;

		if (titre.length <= limite) {
			return titre;
		}

		for (var i = 0; i < titre.length; i++) {
			taille = taille + 1;
			if (taille >= limite) {
				break;
			}
		}
		return titre.substring(0, taille) + '...';
	}

	function applyRegleStyle(block, idx1) {
		var counterElement = $scope.counterElements;
		var debutStyle = '
';
		var finStyle = '
';
		var tagExist = false;
		var libelle = '';
		var numTitreTmp = numTitre;
		var isTitre = false;

		console.log('OKI 2');
		console.log(block.text);

		for (var profiltag in $scope.profiltags) {
			/* le cas d'un paragraphe */
			var style = $scope.profiltags[profiltag].texte;
			libelle = $scope.profiltags[profiltag].tagName;
			if (libelle.match('^Paragraphe')) {
				$scope.styleParagraphe = style.substring(style.indexOf('
'));
			}

			if (block.tag === $scope.profiltags[profiltag].tag) {
				debutStyle = style.substring(style.indexOf('
')) + 'id="' + counterElement + '" regle-style="" >';
				/* le cas d'un titre */
				if (libelle.match('^Titre')) {
					numTitre = getTitleIndex(libelle);
					numTitreTmp = numTitre;
					numTitre++;
					libelle = block.text;
					isTitre = true;
				}
				tagExist = true;
				break;
			}
		}

		// Selection du Tag si il n'existe pas sur les profilsTags
		if (!tagExist) {
			for (var i = 0; i < $scope.tags.length; i++) {
				if (block.tag === $scope.tags[i]._id) {
					libelle = $scope.tags[i].libelle;
					if (libelle.match('^Titre')) {
						numTitre = getTitleIndex(libelle);
						numTitreTmp = numTitre;
						numTitre++;
						libelle = block.text;
						isTitre = true;
					}
					break;
				}
			}
		}

		if (!isTitre) {
			libelle = removeHtmlTags(libelle) + ' : ' + limitParagraphe(removeHtmlTags(block.text)).replace(/\n/g, ' ');
		} else {
			libelle = removeHtmlTags(libelle);
		}

		if (block.tag && block.tag.length > 0) {
			$scope.plans.push({
				libelle: libelle,
				block: block.id,
				position: idx1,
				numTitre: numTitreTmp
			});
		}

		block.text = debutStyle + block.text + finStyle;

		return block;
	}

	/* Parcourir les blocks du document d'une facon recursive */

	function traverseLeaf(obj, idx1, idx2) {
		for (var key in obj) {
			if (typeof(obj[key]) === 'object') {
				if (obj[key].text && obj[key].text.length > 0) {
					$scope.counterElements += 1;
					obj[key] = applyRegleStyle(obj[key], idx1);
				}

				$scope.blocksPlan[idx1 + 1][++idx2] = obj[key];

				if (obj[key].children.length > 0) {
					traverseLeaf(obj[key].children, idx1, idx2);
				} else {
					obj[key].leaf = true;
				}
			}
		}
	}

	function traverseRoot(obj, idx1, idx2) {
		if (obj.text && obj.text.length > 0 && obj.children.length <= 0) {
			$scope.counterElements += 1;
			obj = applyRegleStyle(obj, idx1);
		}
		$scope.blocksPlan[idx1 + 1][idx2] = obj;
	}

	$scope.showTitleDoc = function() {
		var docUrl = decodeURI($location.absUrl());
		docUrl = docUrl.replace('#/print', '');
		// $rootScope.titreDoc = decodeURIComponent(/((_+)([A-Za-z0-9_%]*)(_+))/i.exec(encodeURIComponent(docUrl))[0].replace('_', '').replace('_', ''));
		var docName = decodeURI(docUrl.substring(docUrl.lastIndexOf('/') + 1, docUrl.lastIndexOf('.html')));
		$scope.docSignature = /((_)([A-Za-z0-9_%]+))/i.exec(encodeURIComponent(docName))[0].replace(/((_+)([A-Za-z0-9_%]*)(_+))/i.exec(encodeURIComponent(docName))[0], '');
	};
	$scope.showTitleDoc();

	$scope.notes = [];
	$scope.drawLine = function() {
		$('#noteBlock1 div').remove();
		if ($scope.notes.length > 0) {
			for (var i = 0; i < $scope.notes.length; i++) {
				$('#noteBlock1').line($scope.notes[i].xLink + 55, $scope.notes[i].yLink + 12, $scope.notes[i].x - 9, $scope.notes[i].y + 20, {
					color: '#747474',
					stroke: 1,
					zindex: 10
				});
			}
		}
	};

	$scope.$on('ngRepeatFinished', function() {
		$scope.restoreNotesStorage();
		window.print();
	});

	$scope.restoreNotesStorage = function() {
		console.log('pageTraites ===>');
		console.log($scope.pageTraites);
		if (!$scope.isPagePlan && localStorage.getItem('notes')) {
			var notes = JSON.parse(angular.fromJson(localStorage.getItem('notes')));
			var defY = 65;
			var defTmp = 0;
			$scope.notes = [];
			for (var i = 0; i < notes.length; i++) {
				if (notes[i].idDoc === $scope.docSignature && ($scope.pageTraites.length <= 0 || $scope.pageTraites.indexOf(notes[i].idPage) !== -1)) {
					defTmp = $('#noPlanPrint' + notes[i].idPage).offset().top + defY;
					notes[i].yLink += defTmp;
					notes[i].y += defTmp;
					notes[i].styleNote = '
 ' + notes[i].texte + '
';
					$scope.notes.push(notes[i]);
				}
			}
		} else {
			$scope.notes = [];
		}
		$scope.drawLine();
	};

});<commit_msg>Corriger le non affichage de quelques blocks dans les slides de l'apercu d'impression d'un document HTML.<commit_after>/* File: print.js
 *
 * Copyright (c) 2014
 * Centre National d’Enseignement à Distance (Cned), Boulevard Nicephore Niepce, 86360 CHASSENEUIL-DU-POITOU, France
 * (direction-innovation@cned.fr)
 *
 * GNU Affero General Public License (AGPL) version 3.0 or later version
 *
 * This file is part of a program which is free software: you can
 * redistribute it and/or modify it under the terms of the
 * GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License along with this program.
 * If not, see <http://www.gnu.org/licenses/>.
 *
 */

/*jshint loopfunc:true*/
/*global $:false, blocks */

'use strict';

angular.module('cnedApp').controller('PrintCtrl', function($scope, $rootScope, $http, $window, $location, configuration, dropbox, removeHtmlTags) {

	$scope.data = [];
	// $scope.blocks = [];
	$scope.blocksAlternative = [];
	$scope.plans = [];
	$scope.showApercu = 'hidden';
	$scope.showPlan = 'visible';
	$scope.counterElements = 0;
	$scope.styleParagraphe = '';
	/* activer le loader */
	$scope.loader = false;
	var numTitre = 0;
	$scope.showPlan = true;
	$scope.isPagePlan = false;

	/* Mette à jour dernier document affiché */
	if ($location.absUrl()) {
		localStorage.setItem('lastDocument', $location.absUrl());
		$scope.encodeURI = decodeURI($location.absUrl());
	}

	$scope.requestToSend = {};
	if (localStorage.getItem('compteId')) {
		$scope.requestToSend = {
			id: localStorage.getItem('compteId')
		};
	}

	$scope.showTitleDoc = function() {
		var docUrl = decodeURI($location.absUrl());
		docUrl = docUrl.replace('#/apercu', '');
		$rootScope.titreDoc = decodeURIComponent(/((_+)([A-Za-z0-9_%]*)(_+))/i.exec(encodeURIComponent(docUrl))[0].replace('_', '').replace('_', ''));
		console.log('titre document ==> ');
		console.log($rootScope.titreDoc);
		$('#titreDocumentApercu').show();
	};
	$scope.showTitleDoc();

	$scope.populateApercu = function() {
		console.log('in populateApercu ==> ');
		console.log(blocks);
		// Selection des profils tags pour le style
		if (blocks && blocks.children.length > 0) {
			$scope.profiltags = JSON.parse(localStorage.getItem('listTagsByProfil'));
			//Selection des tags pour le plan
			$scope.tags = JSON.parse(localStorage.getItem('listTags'));
			var blocksArray = angular.fromJson(blocks);
			console.log(blocksArray);
			$scope.blocksPlan = [];
			$scope.blocksPlan[0] = [];
			$scope.blocksPlan[0][0] = [];
			$scope.idx2 = [];

			for (var i = 0; i < blocksArray.children.length; i++) {
				$scope.blocksPlan[i + 1] = [];
				$scope.idx2[i + 1] = 0;
				blocksArray.children[i].root = true;
				traverseRoot(blocksArray.children[i], i);
				traverseLeaf(blocksArray.children[i].children, i);
			}

			$scope.plans.forEach(function(entry) {
				entry.style = '
 ' + entry.libelle + '
';
			});

			var mode = parseInt($location.search().mode);
			var printPlan = parseInt($location.search().plan);
			$scope.pageTraites = [];
			if (mode === 1 || mode === 2) {
				var pageDe = parseInt($location.search().de);
				var pageA = parseInt($location.search().a);
				console.log('pageDe ===>' + pageDe);
				console.log('pageA ===>' + pageA);
				if (pageDe > 0 && pageA > 0 && pageDe <= pageA) {
					var blocksPlanTmp = $scope.blocksPlan.slice(pageDe, pageA + 1);
					console.log(blocksPlanTmp);
					$scope.blocksPlan = [];
					$scope.blocksPlan[0] = [];
					$scope.blocksPlan[0][0] = [];
					for (var j = 0; j < blocksPlanTmp.length; j++) {
						$scope.blocksPlan[j + 1] = blocksPlanTmp[j];
					}

					for (var k = pageDe; k <= pageA; k++) {
						$scope.pageTraites.push(k);
					}

				} else {
					printPlan = 1;
					$scope.isPagePlan = true;
					$scope.blocksPlan = [];
					$scope.blocksPlan[0] = [];
					$scope.blocksPlan[0][0] = [];
				}
			}

			if (printPlan === 0) {
				$scope.showPlan = false;
				$scope.plans = [];
			}

			$scope.loader = false;
		}
	};

	if (localStorage.getItem('listTagsByProfil') && localStorage.getItem('listTags')) {
		console.log('starting populate');
		$scope.populateApercu();
	}

	function getTitleIndex(titre) {
		return parseInt(titre.substring(titre.length - 1, titre.length));
	}

	function limitParagraphe(titre) {
		var taille = 0;
		var limite = 80;

		if (titre.length <= limite) {
			return titre;
		}

		for (var i = 0; i < titre.length; i++) {
			taille = taille + 1;
			if (taille >= limite) {
				break;
			}
		}
		return titre.substring(0, taille) + '...';
	}

	function applyRegleStyle(block, idx1) {
		var counterElement = $scope.counterElements;
		var debutStyle = '
';
		var finStyle = '
';
		var tagExist = false;
		var libelle = '';
		var numTitreTmp = numTitre;
		var isTitre = false;

		console.log('OKI 2');
		console.log(block.text);

		for (var profiltag in $scope.profiltags) {
			/* le cas d'un paragraphe */
			var style = $scope.profiltags[profiltag].texte;
			libelle = $scope.profiltags[profiltag].tagName;
			if (libelle.match('^Paragraphe')) {
				$scope.styleParagraphe = style.substring(style.indexOf('
'));
			}

			if (block.tag === $scope.profiltags[profiltag].tag) {
				debutStyle = style.substring(style.indexOf('
')) + 'id="' + counterElement + '" regle-style="" >';
				/* le cas d'un titre */
				if (libelle.match('^Titre')) {
					numTitre = getTitleIndex(libelle);
					numTitreTmp = numTitre;
					numTitre++;
					libelle = block.text;
					isTitre = true;
				}
				tagExist = true;
				break;
			}
		}

		// Selection du Tag si il n'existe pas sur les profilsTags
		if (!tagExist) {
			for (var i = 0; i < $scope.tags.length; i++) {
				if (block.tag === $scope.tags[i]._id) {
					libelle = $scope.tags[i].libelle;
					if (libelle.match('^Titre')) {
						numTitre = getTitleIndex(libelle);
						numTitreTmp = numTitre;
						numTitre++;
						libelle = block.text;
						isTitre = true;
					}
					break;
				}
			}
		}

		if (!isTitre) {
			libelle = removeHtmlTags(libelle) + ' : ' + limitParagraphe(removeHtmlTags(block.text)).replace(/\n/g, ' ');
		} else {
			libelle = removeHtmlTags(libelle);
		}

		if (block.tag && block.tag.length > 0) {
			$scope.plans.push({
				libelle: libelle,
				block: block.id,
				position: idx1,
				numTitre: numTitreTmp
			});
		}

		block.text = debutStyle + block.text + finStyle;

		return block;
	}

	/* Parcourir les blocks du document d'une facon recursive */

	function traverseLeaf(obj, idx1) {
		for (var key in obj) {
			if (typeof(obj[key]) === 'object') {
				if (obj[key].text && obj[key].text.length > 0) {
					$scope.counterElements += 1;
					obj[key] = applyRegleStyle(obj[key], idx1);
				}

				$scope.idx2[idx1 + 1] = $scope.idx2[idx1 + 1] + 1;
				$scope.blocksPlan[idx1 + 1][$scope.idx2[idx1 + 1]] = obj[key];

				if (obj[key].children.length > 0) {
					traverseLeaf(obj[key].children, idx1);
				} else {
					obj[key].leaf = true;
				}
			}
		}
	}

	function traverseRoot(obj, idx1) {
		if (obj.text && obj.text.length > 0 && obj.children.length <= 0) {
			$scope.counterElements += 1;
			obj = applyRegleStyle(obj, idx1);
		}
		$scope.blocksPlan[idx1 + 1][$scope.idx2[idx1 + 1]] = obj;
	}

	$scope.showTitleDoc = function() {
		var docUrl = decodeURI($location.absUrl());
		docUrl = docUrl.replace('#/print', '');
		// $rootScope.titreDoc = decodeURIComponent(/((_+)([A-Za-z0-9_%]*)(_+))/i.exec(encodeURIComponent(docUrl))[0].replace('_', '').replace('_', ''));
		var docName = decodeURI(docUrl.substring(docUrl.lastIndexOf('/') + 1, docUrl.lastIndexOf('.html')));
		$scope.docSignature = /((_)([A-Za-z0-9_%]+))/i.exec(encodeURIComponent(docName))[0].replace(/((_+)([A-Za-z0-9_%]*)(_+))/i.exec(encodeURIComponent(docName))[0], '');
	};
	$scope.showTitleDoc();

	$scope.notes = [];
	$scope.drawLine = function() {
		$('#noteBlock1 div').remove();
		if ($scope.notes.length > 0) {
			for (var i = 0; i < $scope.notes.length; i++) {
				$('#noteBlock1').line($scope.notes[i].xLink + 55, $scope.notes[i].yLink + 12, $scope.notes[i].x - 9, $scope.notes[i].y + 20, {
					color: '#747474',
					stroke: 1,
					zindex: 10
				});
			}
		}
	};

	$scope.$on('ngRepeatFinished', function() {
		$scope.restoreNotesStorage();
		window.print();
	});

	$scope.restoreNotesStorage = function() {
		console.log('pageTraites ===>');
		console.log($scope.pageTraites);
		if (!$scope.isPagePlan && localStorage.getItem('notes')) {
			var notes = JSON.parse(angular.fromJson(localStorage.getItem('notes')));
			var defY = 65;
			var defTmp = 0;
			$scope.notes = [];
			for (var i = 0; i < notes.length; i++) {
				if (notes[i].idDoc === $scope.docSignature && ($scope.pageTraites.length <= 0 || $scope.pageTraites.indexOf(notes[i].idPage) !== -1)) {
					defTmp = $('#noPlanPrint' + notes[i].idPage).offset().top + defY;
					notes[i].yLink += defTmp;
					notes[i].y += defTmp;
					notes[i].styleNote = '
 ' + notes[i].texte + '
';
					$scope.notes.push(notes[i]);
				}
			}
		} else {
			$scope.notes = [];
		}
		$scope.drawLine();
	};

});<|endoftext|>


<commit_before>define([
    'angular'
], function(angular) {
    'use strict';

    angular.module('superdesk.profile.resources', ['superdesk.server']).
        factory('usersResource', function( $resource) {
            return $resource('scripts/superdesk/profile/static-resources/users.json');
        }).
        factory('activityResource', function( $resource) {
            return $resource('scripts/superdesk/profile/static-resources/activity.json');
        }).
        service('profileService', function(server) {
            return {
                /**
                 * Get user for given username
                 *
                 * @param {string} username
                 * @return {object} user
                 */
                getUserByUsername: function(username) {
                    return server.readItem('users', username);
                },

                /**
                 * Get user activity feed for given user
                 *
                 * @param {object} user
                 * @param {int} maxResults
                 * @param {int} page
                 * @return {object} activity
                 */
                getUserActivity: function(user, maxResults, page) {
                    var params = {
                        where: {user: user._id},
                        sort: '[("created", -1)]',
                        embedded: {user: 1},
                    };

                    if (maxResults) {
                        params['max_results'] = maxResults;
                    }

                    if (page > 1) {
                        params.page = page;
                    }

                    return server.readList('activity', params);
                }
            };
        });
});<commit_msg>Fix docs in profile/resources.<commit_after>define([
    'angular'
], function(angular) {
    'use strict';

    angular.module('superdesk.profile.resources', ['superdesk.server']).
        factory('usersResource', function( $resource) {
            return $resource('scripts/superdesk/profile/static-resources/users.json');
        }).
        factory('activityResource', function( $resource) {
            return $resource('scripts/superdesk/profile/static-resources/activity.json');
        }).
        service('profileService', function(server) {
            return {
                /**
                 * Get user for given username
                 *
                 * @param {string} username
                 * @return {object} user
                 */
                getUserByUsername: function(username) {
                    return server.readItem('users', username);
                },

                /**
                 * Get user activity feed for given user
                 *
                 * @param {object} user
                 * @param {number} maxResults
                 * @param {number} page
                 * @return {object} activity
                 */
                getUserActivity: function(user, maxResults, page) {
                    var params = {
                        where: {user: user._id},
                        sort: '[("created", -1)]',
                        embedded: {user: 1},
                    };

                    if (maxResults) {
                        params['max_results'] = maxResults;
                    }

                    if (page > 1) {
                        params.page = page;
                    }

                    return server.readList('activity', params);
                }
            };
        });
});<|endoftext|>


<commit_before>/**
 * @author sunag / http://www.sunag.com.br/
 */

THREE.NodeLib = {
	nodes: {},
	add: function( node ) {

		this.nodes[ node.name ] = node;

	},
	remove: function( node ) {

		delete this.nodes[ node.name ];

	},
	get: function( name ) {

		return this.nodes[ name ];

	},
	contains: function( name ) {

		return this.nodes[ name ] != undefined;

	}
};

//
//	Luma
//

THREE.NodeLib.add( new THREE.ConstNode( "vec3 LUMA = vec3(0.2125, 0.7154, 0.0721);" ) );

//
//	DepthColor
//

THREE.NodeLib.add( new THREE.FunctionNode( [
"float depthcolor( float mNear, float mFar ) {",

	"#ifdef USE_LOGDEPTHBUF_EXT",
		"float depth = gl_FragDepthEXT / gl_FragCoord.w;",
	"#else",
		"float depth = gl_FragCoord.z / gl_FragCoord.w;",
	"#endif",

	"return 1.0 - smoothstep( mNear, mFar, depth );",
"}"
].join( "\n" ) ) );

//
//	NormalMap
//

THREE.NodeLib.add( new THREE.FunctionNode( [
// Per-Pixel Tangent Space Normal Mapping
// http://hacksoflife.blogspot.ch/2009/11/per-pixel-tangent-space-normal-mapping.html
"vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm, vec3 map, vec2 mUv, vec2 scale ) {",
	"vec3 q0 = dFdx( eye_pos );",
	"vec3 q1 = dFdy( eye_pos );",
	"vec2 st0 = dFdx( mUv.st );",
	"vec2 st1 = dFdy( mUv.st );",
	"vec3 S = normalize( q0 * st1.t - q1 * st0.t );",
	"vec3 T = normalize( -q0 * st1.s + q1 * st0.s );",
	"vec3 N = normalize( surf_norm );",
	"vec3 mapN = map * 2.0 - 1.0;",
	"mapN.xy = scale * mapN.xy;",
	"mat3 tsn = mat3( S, T, N );",
	"return normalize( tsn * mapN );",
"}"
].join( "\n" ), null, { derivatives: true } ) );

//
//	Saturation
//

THREE.NodeLib.add( new THREE.FunctionNode( [
// Algorithm from Chapter 16 of OpenGL Shading Language
"vec3 saturation_rgb(vec3 rgb, float adjustment) {",
	"vec3 intensity = vec3(dot(rgb, LUMA));",
	"return mix(intensity, rgb, adjustment);",
"}"
].join( "\n" ) ) );

//
//	Luminance
//

THREE.NodeLib.add( new THREE.FunctionNode( [
// Algorithm from Chapter 10 of Graphics Shaders.
"float luminance_rgb(vec3 rgb) {",
	"return dot(rgb, LUMA);",
"}"
].join( "\n" ) ) );
<commit_msg>new includes<commit_after>/**
 * @author sunag / http://www.sunag.com.br/
 */

THREE.NodeLib = {
	nodes: {},
	add: function( node ) {

		this.nodes[ node.name ] = node;

	},
	remove: function( node ) {

		delete this.nodes[ node.name ];

	},
	get: function( name ) {

		return this.nodes[ name ];

	},
	contains: function( name ) {

		return this.nodes[ name ] != undefined;

	}
};

//
//	Luma
//

THREE.NodeLib.add( new THREE.ConstNode( "vec3 LUMA = vec3(0.2125, 0.7154, 0.0721);" ) );

//
//	DepthColor
//

THREE.NodeLib.add( new THREE.FunctionNode( [
"float depthcolor( float mNear, float mFar ) {",

	"#ifdef USE_LOGDEPTHBUF_EXT",
		"float depth = gl_FragDepthEXT / gl_FragCoord.w;",
	"#else",
		"float depth = gl_FragCoord.z / gl_FragCoord.w;",
	"#endif",

	"return 1.0 - smoothstep( mNear, mFar, depth );",
"}"
].join( "\n" ) ) );

//
//	NormalMap
//

THREE.NodeLib.add( new THREE.FunctionNode( [
// Per-Pixel Tangent Space Normal Mapping
// http://hacksoflife.blogspot.ch/2009/11/per-pixel-tangent-space-normal-mapping.html
"vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm, vec3 map, vec2 mUv, vec2 scale ) {",
	"vec3 q0 = dFdx( eye_pos );",
	"vec3 q1 = dFdy( eye_pos );",
	"vec2 st0 = dFdx( mUv.st );",
	"vec2 st1 = dFdy( mUv.st );",
	"vec3 S = normalize( q0 * st1.t - q1 * st0.t );",
	"vec3 T = normalize( -q0 * st1.s + q1 * st0.s );",
	"vec3 N = normalize( surf_norm );",
	"vec3 mapN = map * 2.0 - 1.0;",
	"mapN.xy = scale * mapN.xy;",
	"mat3 tsn = mat3( S, T, N );",
	"return normalize( tsn * mapN );",
"}"
].join( "\n" ), null, { derivatives: true } ) );

//
//	Noise
//

THREE.NodeLib.add( new THREE.FunctionNode( [
"float snoise(vec2 co) {",
	"return fract( sin( dot(co.xy, vec2(12.9898,78.233) ) ) * 43758.5453 );",
"}"
].join( "\n" ) ) );

//
//	Hue
//

THREE.NodeLib.add( new THREE.FunctionNode( [
"vec3 hue_rgb(vec3 rgb, float adjustment) {",
	"const mat3 RGBtoYIQ = mat3(0.299, 0.587, 0.114, 0.595716, -0.274453, -0.321263, 0.211456, -0.522591, 0.311135);",
	"const mat3 YIQtoRGB = mat3(1.0, 0.9563, 0.6210, 1.0, -0.2721, -0.6474, 1.0, -1.107, 1.7046);",
	"vec3 yiq = RGBtoYIQ * rgb;",
	"float hue = atan(yiq.z, yiq.y) + adjustment;",
	"float chroma = sqrt(yiq.z * yiq.z + yiq.y * yiq.y);",
	"return YIQtoRGB * vec3(yiq.x, chroma * cos(hue), chroma * sin(hue));",
"}"
].join( "\n" ) ) );

//
//	Saturation
//

THREE.NodeLib.add( new THREE.FunctionNode( [
// Algorithm from Chapter 16 of OpenGL Shading Language
"vec3 saturation_rgb(vec3 rgb, float adjustment) {",
	"vec3 intensity = vec3(dot(rgb, LUMA));",
	"return mix(intensity, rgb, adjustment);",
"}"
].join( "\n" ) ) );

//
//	Luminance
//

THREE.NodeLib.add( new THREE.FunctionNode( [
// Algorithm from Chapter 10 of Graphics Shaders
"float luminance_rgb(vec3 rgb) {",
	"return dot(rgb, LUMA);",
"}"
].join( "\n" ) ) );

//
//	Vibrance
//

THREE.NodeLib.add( new THREE.FunctionNode( [
// Shader by Evan Wallace adapted from @lo-th
"vec3 vibrance_rgb(vec3 rgb, float adjustment) {",
	"float average = (rgb.r + rgb.g + rgb.b) / 3.0;",
	"float mx = max(rgb.r, max(rgb.g, rgb.b));",
	"float amt = (mx - average) * (-3.0 * adjustment);",
	"return mix(rgb.rgb, vec3(mx), amt);",
"}"
].join( "\n" ) ) );
<|endoftext|>


<commit_before>App.views.User.addChild('UserProjects', _.extend({
  el: '#user_created_projects',

  activate: function(){
    this.$loader = this.$(".loading img");
    this.$loaderDiv = this.$(".loading");
    this.$results = this.$(".results");
    this.path = this.$el.data('path');
    this.filter = {};
    this.setupScroll();
  }

}, Skull.InfiniteScroll));

<commit_msg>now we load the user created projects on the selectTab event that display the users project pane<commit_after>App.views.User.addChild('UserProjects', _.extend({
  el: '#user_created_projects',

  activate: function(){
    var that = this;
    this.$loader = this.$(".loading img");
    this.$loaderDiv = this.$(".loading");
    this.$results = this.$(".results");
    this.path = this.$el.data('path');
    this.filter = {};
    this.setupScroll();
    this.parent.on('selectTab', function(){
      if(that.$el.is(':visible')){
        that.fetchPage();
      }
    });
  }

}, Skull.InfiniteScroll));

<|endoftext|>


<commit_before>define([
    'angular',
    'angular-route'
], function(angular) {
    'use strict';

    /**
     * Activity service
     *
     * Activity service is used to configure both menuProvider and $routeProvider,
     * as they have many common elements.
     *
     * Usage:
     *
     * Registering an activity:
     *
     * activityProvider.activity(id, options);
     *
     * Params:
     *
     * @param {string} id - activity id. Currently only passed to menuProvider
     * for managing relationships between menu items. If not provided, activity
     * is not listed in the menu.
     *
     * @param {object} options - options for activity. Additionally, any option that
     * needs to be passed to $routeProvider (controller, templateUrl) can be added
     * to options.
     *
     * Available options are:
     * href: (mandatory) Directly passed to menuProvider and $routeProvider for
     * defining url.
     *
     * label: (mandatory) Used for display name used in $routeProvider and
     * (if menuLabel is not provided) menuProvider.
     *
     * priority: (optional) Used for sorting menu items.
     *
     * menu: (optional) Used to determine if activity will be displayed in navigation
     * menu or not. Default is true.
     *
     * menuLabel: (optional) If menu label needs to be different than route, this
     * is used to override label for menuProvider.
     *
     * menuHref: (optional) If menu href needs to be different than route, this
     * is used to override route for menuProvider.
     *
     * parent: (optional) Directly passed to menu provider, to manage menu hierarchy.
     *
     */
    angular.module('superdesk.services.activity', ['ngRoute'])
        .provider('activity', ['menuProvider', '$routeProvider', function(menuProvider, $routeProvider) {
            return {
                $get: function() {

                },
                activity: function(id, item) {
                    if (item.menu !== false) {
                        menuProvider.menu(id, {
                            label: item.menuLabel || item.label,
                            href: item.menuHref || item.href,
                            priority: item.priority,
                            parent: item.parent
                        });
                    }
                    var route = _.omit(_.extend({}, item), ['priority', 'href', 'menuLabel', 'menuHref']);
                    $routeProvider.when(item.href, route);

                    return this;
                }
            };

        }]);

});<commit_msg>Fixed docs.<commit_after>define([
    'angular',
    'angular-route'
], function(angular) {
    'use strict';

    /**
     * Activity service
     *
     * Activity service is used to configure both menuProvider and $routeProvider,
     * as they have many common elements.
     *
     * Usage:
     *
     * Registering an activity:
     *
     * activityProvider.activity(id, options);
     *
     * Params:
     *
     * @param {string} id - activity id.
     *
     * @param {object} options - options for activity. Additionally, any option that
     * needs to be passed to $routeProvider (controller, templateUrl) can be added
     * to options.
     *
     * Available options are:
     * href: (mandatory) Directly passed to menuProvider and $routeProvider for
     * defining url.
     *
     * label: (mandatory) Used for display name used in $routeProvider and
     * (if menuLabel is not provided) menuProvider.
     *
     * priority: (optional) Used for sorting menu items.
     *
     * menu: (optional) Used to determine if activity will be displayed in navigation
     * menu or not. Default is true.
     *
     * menuLabel: (optional) If menu label needs to be different than route, this
     * is used to override label for menuProvider.
     *
     * menuHref: (optional) If menu href needs to be different than route, this
     * is used to override route for menuProvider.
     *
     * parent: (optional) Directly passed to menu provider, to manage menu hierarchy.
     *
     */
    angular.module('superdesk.services.activity', ['ngRoute'])
        .provider('activity', ['menuProvider', '$routeProvider', function(menuProvider, $routeProvider) {
            return {
                $get: function() {

                },
                activity: function(id, item) {
                    if (item.menu !== false) {
                        menuProvider.menu(id, {
                            label: item.menuLabel || item.label,
                            href: item.menuHref || item.href,
                            priority: item.priority,
                            parent: item.parent
                        });
                    }
                    var route = _.omit(_.extend({}, item), ['priority', 'href', 'menuLabel', 'menuHref']);
                    $routeProvider.when(item.href, route);

                    return this;
                }
            };

        }]);

});<|endoftext|>


<commit_before>
function renderGamePage(gameState) {
  var team1 = gameState.teams[0];
  var team2 = gameState.teams[1];
  var userdata = $("#live[data-userid]").data()
  var user_id = !!userdata ? userdata.userid : null;
  var isCluegiver = (user_id === gameState.cluegiver.id);
  var isCreator = (user_id === gameState.creator.id);

  // Universal View

  function getTimerHTML(){
    return `

00:30

`;
  };

  function getTitleHTML(){
    return `

${gameState.game.name}

Current Round: ${gameState.current_round.type}

`;
  };

  // Waiting-to-Start-Game View

  function getWaitingHTML(){
    if(gameState.game_started){ return "" }

    var allPlayers = ''

    gameState.participants.forEach(function(participant){
      allPlayers += `<li class='player-name'>${participant.display_name}</li>`
    })

    return `

Participants

          ${allPlayers}

          <form id="new_card" class="action-form" action="/cards" accept-charset="UTF-8" method="post">
            <input type="text" name="card[concept]" id="card_concept" />
            <input type="hidden" name="game_id" id="game_id" value="${gameState.game.id}" />
            <input type="submit" name="commit" value="Add Card" data-disable-with="Add Card" />
          </form>

        ${startGameFormHTML()}

    `;
  }

  function startGameFormHTML(){
    var formHTML;

    if(isCreator && gameState.ready) {
      return `
        <form id="start-game" class="action-form" action="/games/${gameState.game.name}/start" method="post">
          <input class="waves-effect waves-light btn-large teal" type="submit" value="Start Game!">
        </form>
      `
    } else if (!isCreator && gameState.ready) {
      return `

          Waiting for ${gameState.creator.display_name} to push start...

      `
    } else if(gameState.participants < 4) {
      var missingNo = 4 - gameState.participants.length;
      return `

          Waiting for ${missingNo} more player(s)...

      `
    } else if (!gameState.has_cards) {
      return `

          Waiting for all players to add 4 cards...

      `
    }
  }

  // Waiting-to-Round-Game View

  function getTeamsHTML(){
    if(!gameState.game_started || gameState.round_started){ return "" }

    var team1Players = ''
    var team2Players = ''

    team1.players.forEach(function(player) {
      team1Players += ('
' + player.display_name + '
')
    })

    team2.players.forEach(function(player) {
      team2Players += ('
' + player.display_name + '
')
    })

    return `
Teams:

${team1.name}

${team1.score} points

    ${team1Players}

${team2.name}

${team2.score} points

    ${team2Players}

    `;
  }

  function startRoundFormHTML(){
    if(!isCreator){ return "" }
    if(!gameState.game_started || gameState.round_started){ return "" }
    return `
    <form class="action-form" action="/games/${gameState.game.name}/start_round" method="post">
    <input class="waves-effect waves-light btn-large teal" type="submit" value="START ROUND">
    </form>
    `
  }

  // Cluegiver View

  function getCluegiverHTML() {
    if(!gameState.round_started || !isCluegiver){ return "" }
    return `

      ${getCardHTML()}
      ${getCluegiverButtonsHTML()}

    `;
  }

  function getCardHTML(){
    return `<h1>${gameState.card}</h1>`;
  }

  function getCluegiverButtonsHTML(){
    return `

    <form class="action-form" action="/games/${gameState.game.name}/pass" method="post">
    <input class="waves-effect waves-light btn-large red" type="submit" value="pass">
    </form>

    <form class="action-form" action="/games/${gameState.game.name}/win_card" method="post">
    <input class="waves-effect waves-light btn-large teal" type="submit" value="got it!">
    </form>

    <form class="action-form" action="/games/${gameState.game.name}/pause" method="post">
    <input class="waves-effect waves-light btn-large orange" type="submit" value="pause">
    </form>

`;
  };

  // Observer View

  function getObserverHTML() {
    if(!gameState.round_started || isCluegiver){ return "" }
    return `

${gameState.cluegiver.display_name}s Turn

    `;
  }

  // Results View

  function showResults() {
    var winningTeam = team1.score > team2.score ? team1 : team2;
    var losingTeam = gameState.teams.find(function(team) { return team != winningTeam });

    return `

${winningTeam.name} win!

${winningTeam.score}

${losingTeam.name}

${losingTeam.score}

    `
  }

  function nextTurnButton() {
    if(!isCreator || !gameState.round_started){ return "" }
    return `
    <form class="action-form" action="/games/${gameState.game.name}/next_turn" method="post">
    <input class="waves-effect waves-light btn-large green" type="submit" value="NEXT TURN">
    </form>
    `
  }

  var gameHTML;
  if(gameState.is_over){
    gameHTML = showResults()
  } else {
    gameHTML = `
      ${getTimerHTML()}
      ${getTitleHTML()}
      ${getWaitingHTML()}
      ${getTeamsHTML()}
      ${startRoundFormHTML()}
      ${getCluegiverHTML()}
      ${getObserverHTML()}
      ${nextTurnButton()}
    `
  }
  $('#live').html(gameHTML)
}
<commit_msg>fix participants count conditional<commit_after>
function renderGamePage(gameState) {
  var team1 = gameState.teams[0];
  var team2 = gameState.teams[1];
  var userdata = $("#live[data-userid]").data()
  var user_id = !!userdata ? userdata.userid : null;
  var isCluegiver = (user_id === gameState.cluegiver.id);
  var isCreator = (user_id === gameState.creator.id);

  // Universal View

  function getTimerHTML(){
    return `

00:30

`;
  };

  function getTitleHTML(){
    return `

${gameState.game.name}

Current Round: ${gameState.current_round.type}

`;
  };

  // Waiting-to-Start-Game View

  function getWaitingHTML(){
    if(gameState.game_started){ return "" }

    var allPlayers = ''

    gameState.participants.forEach(function(participant){
      allPlayers += `<li class='player-name'>${participant.display_name}</li>`
    })

    return `

Participants

          ${allPlayers}

          <form id="new_card" class="action-form" action="/cards" accept-charset="UTF-8" method="post">
            <input type="text" name="card[concept]" id="card_concept" />
            <input type="hidden" name="game_id" id="game_id" value="${gameState.game.id}" />
            <input type="submit" name="commit" value="Add Card" data-disable-with="Add Card" />
          </form>

        ${startGameFormHTML()}

    `;
  }

  function startGameFormHTML(){
    var innerHTML;
    var output = `

        ${innerHTML}

    `

    if(isCreator && gameState.ready) {
      innerHTML = `
        <form id="start-game" class="action-form" action="/games/${gameState.game.name}/start" method="post">
          <input class="waves-effect waves-light btn-large teal" type="submit" value="Start Game!">
        </form>
      `
    } else if (!isCreator && gameState.ready) {
      innerHTML = `<span>Waiting for ${gameState.creator.display_name} to push start...</span>`

    } else if(gameState.participants.length < 4) {
      var missingNo = 4 - gameState.participants.length;
      innerHTML = `<span>Waiting for ${missingNo} more player(s)...</span>`

    } else if (!gameState.has_cards) {
      innerHTML = 'Waiting for all players to add 4 cards...'
    }
    return output;
  }

  // Waiting-to-Round-Game View

  function getTeamsHTML(){
    if(!gameState.game_started || gameState.round_started){ return "" }

    var team1Players = ''
    var team2Players = ''

    team1.players.forEach(function(player) {
      team1Players += ('
' + player.display_name + '
')
    })

    team2.players.forEach(function(player) {
      team2Players += ('
' + player.display_name + '
')
    })

    return `
Teams:

${team1.name}

${team1.score} points

    ${team1Players}

${team2.name}

${team2.score} points

    ${team2Players}

    `;
  }

  function startRoundFormHTML(){
    if(!isCreator){ return "" }
    if(!gameState.game_started || gameState.round_started){ return "" }
    return `
    <form class="action-form" action="/games/${gameState.game.name}/start_round" method="post">
    <input class="waves-effect waves-light btn-large teal" type="submit" value="START ROUND">
    </form>
    `
  }

  // Cluegiver View

  function getCluegiverHTML() {
    if(!gameState.round_started || !isCluegiver){ return "" }
    return `

      ${getCardHTML()}
      ${getCluegiverButtonsHTML()}

    `;
  }

  function getCardHTML(){
    return `<h1>${gameState.card}</h1>`;
  }

  function getCluegiverButtonsHTML(){
    return `

    <form class="action-form" action="/games/${gameState.game.name}/pass" method="post">
    <input class="waves-effect waves-light btn-large red" type="submit" value="pass">
    </form>

    <form class="action-form" action="/games/${gameState.game.name}/win_card" method="post">
    <input class="waves-effect waves-light btn-large teal" type="submit" value="got it!">
    </form>

    <form class="action-form" action="/games/${gameState.game.name}/pause" method="post">
    <input class="waves-effect waves-light btn-large orange" type="submit" value="pause">
    </form>

`;
  };

  // Observer View

  function getObserverHTML() {
    if(!gameState.round_started || isCluegiver){ return "" }
    return `

${gameState.cluegiver.display_name}s Turn

    `;
  }

  // Results View

  function showResults() {
    var winningTeam = team1.score > team2.score ? team1 : team2;
    var losingTeam = gameState.teams.find(function(team) { return team != winningTeam });

    return `

${winningTeam.name} win!

${winningTeam.score}

${losingTeam.name}

${losingTeam.score}

    `
  }

  function nextTurnButton() {
    if(!isCreator || !gameState.round_started){ return "" }
    return `
    <form class="action-form" action="/games/${gameState.game.name}/next_turn" method="post">
    <input class="waves-effect waves-light btn-large green" type="submit" value="NEXT TURN">
    </form>
    `
  }

  var gameHTML;
  if(gameState.is_over){
    gameHTML = showResults()
  } else {
    gameHTML = `
      ${getTimerHTML()}
      ${getTitleHTML()}
      ${getWaitingHTML()}
      ${getTeamsHTML()}
      ${startRoundFormHTML()}
      ${getCluegiverHTML()}
      ${getObserverHTML()}
      ${nextTurnButton()}
    `
  }
  $('#live').html(gameHTML)
}
<|endoftext|>


<commit_before>/*global LockOn:true*/
var jumpScheduled = false,
    rewrites = [];

Discourse.URL = Ember.Object.createWithMixins({

  // Used for matching a topic
  TOPIC_REGEXP: /\/t\/([^\/]+)\/(\d+)\/?(\d+)?/,

  isJumpScheduled: function() {
    return jumpScheduled;
  },

  /**
    Jumps to a particular post in the stream
  **/
  jumpToPost: function(postNumber, opts) {
    var holderId = '#post-cloak-' + postNumber;

    var offset = function(){

      var $header = $('header'),
          $title = $('#topic-title'),
          windowHeight = $(window).height() - $title.height(),
          expectedOffset = $title.height() - $header.find('.contents').height() + (windowHeight / 5);

      return $header.outerHeight(true) + ((expectedOffset < 0) ? 0 : expectedOffset);
    };

    Em.run.schedule('afterRender', function() {
      if (postNumber === 1) {
        $(window).scrollTop(0);
        return;
      }

      var lockon = new LockOn(holderId, {offsetCalculator: offset});
      var holder = $(holderId);

      if(holder.length > 0 && opts && opts.skipIfOnScreen){

        // if we are on screen skip
        var elementTop = lockon.elementTop(),
            scrollTop = $(window).scrollTop(),
            windowHeight = $(window).height()-offset(),
            height = holder.height();

        if (elementTop > scrollTop &&
            (elementTop + height) < (scrollTop + windowHeight)) {
          return;
        }
      }

      lockon.lock();

    });
  },

  /**
    Browser aware replaceState. Will only be invoked if the browser supports it.

    @method replaceState
    @param {String} path The path we are replacing our history state with.
  **/
  replaceState: function(path) {
    if (window.history &&
        window.history.pushState &&
        window.history.replaceState &&
        !navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]|WebApps\/.+CFNetwork)/) &&
        (window.location.pathname !== path)) {

        // Always use replaceState in the next runloop to prevent weird routes changing
        // while URLs are loading. For example, while a topic loads it sets `currentPost`
        // which triggers a replaceState even though the topic hasn't fully loaded yet!
        Em.run.next(function() {
          var location = Discourse.URL.get('router.location');
          if (location && location.replaceURL) {
            location.replaceURL(path);
          }
        });
    }
  },

  // Scroll to the same page, different anchor
  scrollToId: function(id) {
    if (Em.isEmpty(id)) { return; }

    jumpScheduled = true;
    Em.run.schedule('afterRender', function() {
      var $elem = $(id);
      if ($elem.length === 0) {
        $elem = $("[name='" + id.replace('#', '') + "']");
      }
      if ($elem.length > 0) {
        $('html,body').scrollTop($elem.offset().top - $('header').height() - 15);
        jumpScheduled = false;
      }
    });
  },

  /**
    Our custom routeTo method is used to intelligently overwrite default routing
    behavior.

    It contains the logic necessary to route within a topic using replaceState to
    keep the history intact.

    @method routeTo
    @param {String} path The path we are routing to.
  **/
  routeTo: function(path) {

    if (Em.isEmpty(path)) { return; }

    if (Discourse.get('requiresRefresh')) {
      document.location.href = path;
      return;
    }

    // Protocol relative URLs
    if (path.indexOf('//') === 0) {
      document.location = path;
      return;
    }

    // Scroll to the same page, different anchor
    if (path.indexOf('#') === 0) {
      this.scrollToId(path);
      return;
    }

    var oldPath = window.location.pathname;
    path = path.replace(/(https?\:)?\/\/[^\/]+/, '');

    // handle prefixes
    if (path.match(/^\//)) {
      var rootURL = (Discourse.BaseUri === undefined ? "/" : Discourse.BaseUri);
      rootURL = rootURL.replace(/\/$/, '');
      path = path.replace(rootURL, '');
    }

    // Rewrite /my/* urls
    if (path.indexOf('/my/') === 0) {
      var currentUser = Discourse.User.current();
      if (currentUser) {
        path = path.replace('/my/', '/users/' + currentUser.get('username_lower') + "/");
      } else {
        document.location.href = "/404";
        return;
      }
    }

    rewrites.forEach(function(rw) {
      path = path.replace(rw.regexp, rw.replacement);
    });

    if (this.navigatedToPost(oldPath, path)) { return; }
    // Schedule a DOM cleanup event
    Em.run.scheduleOnce('afterRender', Discourse.Route, 'cleanDOM');

    // TODO: Extract into rules we can inject into the URL handler
    if (this.navigatedToHome(oldPath, path)) { return; }

    if (oldPath === path) {
      // If navigating to the same path send an app event. Views can watch it
      // and tell their controllers to refresh
      this.appEvents.trigger('url:refresh');
    }

    return this.handleURL(path);
  },

  rewrite: function(regexp, replacement) {
    rewrites.push({ regexp: regexp, replacement: replacement });
  },

  redirectTo: function(url) {
    window.location = Discourse.getURL(url);
  },

  /**
   * Determines whether a URL is internal or not
   *
   * @method isInternal
   * @param {String} url
  **/
  isInternal: function(url) {
    if (url && url.length) {
      if (url.indexOf('#') === 0) { return true; }
      if (url.indexOf('/') === 0) { return true; }
      if (url.indexOf(this.origin()) === 0) { return true; }
      if (url.replace(/^http/, 'https').indexOf(this.origin()) === 0) { return true; }
      if (url.replace(/^https/, 'http').indexOf(this.origin()) === 0) { return true; }
    }
    return false;
  },

  /**
    @private

    If the URL is in the topic form, /t/something/:topic_id/:post_number
    then we want to apply some special logic. If the post_number changes within the
    same topic, use replaceState and instruct our controller to load more posts.

    @method navigatedToPost
    @param {String} oldPath the previous path we were on
    @param {String} path the path we're navigating to
  **/
  navigatedToPost: function(oldPath, path) {
    var newMatches = this.TOPIC_REGEXP.exec(path),
        newTopicId = newMatches ? newMatches[2] : null;

    if (newTopicId) {
      var oldMatches = this.TOPIC_REGEXP.exec(oldPath),
          oldTopicId = oldMatches ? oldMatches[2] : null;

      // If the topic_id is the same
      if (oldTopicId === newTopicId) {
        Discourse.URL.replaceState(path);

        var container = Discourse.__container__,
            topicController = container.lookup('controller:topic'),
            opts = {},
            postStream = topicController.get('model.postStream');

        if (newMatches[3]) opts.nearPost = newMatches[3];
        if (path.match(/last$/)) { opts.nearPost = topicController.get('highest_post_number'); }
        var closest = opts.nearPost || 1;

        var self = this;
        postStream.refresh(opts).then(function() {
          topicController.setProperties({
            'model.currentPost': closest,
            enteredAt: new Date().getTime().toString()
          });
          var closestPost = postStream.closestPostForPostNumber(closest),
              progress = postStream.progressIndexOfPost(closestPost),
              progressController = container.lookup('controller:topic-progress');

          progressController.set('progressPosition', progress);
          self.appEvents.trigger('post:highlight', closest);
        }).then(function() {
          Discourse.URL.jumpToPost(closest, {skipIfOnScreen: true});
        });

        // Abort routing, we have replaced our state.
        return true;
      }
    }

    return false;
  },

  /**
    @private

    Handle the custom case of routing to the root path from itself.

    @param {String} oldPath the previous path we were on
    @param {String} path the path we're navigating to
  **/
  navigatedToHome: function(oldPath, path) {
    var homepage = Discourse.Utilities.defaultHomepage();

    if (window.history &&
        window.history.pushState &&
        (path === "/" || path === "/" + homepage) &&
        (oldPath === "/" || oldPath === "/" + homepage)) {
      this.appEvents.trigger('url:refresh');
      return true;
    }

    return false;
  },

  /**
    @private

    Get the origin of the current location.
    This has been extracted so it can be tested.

    @method origin
  **/
  origin: function() {
    return window.location.origin;
  },

  /**
    @private

    Get a handle on the application's router. Note that currently it uses `__container__` which is not
    advised but there is no other way to access the router.

    @property router
  **/
  router: function() {
    return Discourse.__container__.lookup('router:main');
  }.property().volatile(),

  /**
    @private

    Get a controller. Note that currently it uses `__container__` which is not
    advised but there is no other way to access the router.

    @method controllerFor
    @param {String} name the name of the controller
  **/
  controllerFor: function(name) {
    return Discourse.__container__.lookup('controller:' + name);
  },

  /**
    @private

    Be wary of looking up the router. In this case, we have links in our
    HTML, say form compiled markdown posts, that need to be routed.

    @method handleURL
    @param {String} path the url to handle
  **/
  handleURL: function(path) {
    var router = this.get('router');
    router.router.updateURL(path);

    var split = path.split('#'),
        elementId;

    if (split.length === 2) {
      path = split[0];
      elementId = split[1];
    }

    var transition = router.handleURL(path);
    transition._discourse_intercepted = true;
    transition.promise.then(function() {
      if (elementId) {

        jumpScheduled = true;
        Em.run.next('afterRender', function() {
          var offset = $('#' + elementId).offset();
          if (offset && offset.top) {
            $('html, body').scrollTop(offset.top - $('header').height() - 10);
            jumpScheduled = false;
          }
        });
      }
    });
  }

});
<commit_msg>FIX: subfolder support for page refresh when assets have changed<commit_after>/*global LockOn:true*/
var jumpScheduled = false,
    rewrites = [];

Discourse.URL = Ember.Object.createWithMixins({

  // Used for matching a topic
  TOPIC_REGEXP: /\/t\/([^\/]+)\/(\d+)\/?(\d+)?/,

  isJumpScheduled: function() {
    return jumpScheduled;
  },

  /**
    Jumps to a particular post in the stream
  **/
  jumpToPost: function(postNumber, opts) {
    var holderId = '#post-cloak-' + postNumber;

    var offset = function(){

      var $header = $('header'),
          $title = $('#topic-title'),
          windowHeight = $(window).height() - $title.height(),
          expectedOffset = $title.height() - $header.find('.contents').height() + (windowHeight / 5);

      return $header.outerHeight(true) + ((expectedOffset < 0) ? 0 : expectedOffset);
    };

    Em.run.schedule('afterRender', function() {
      if (postNumber === 1) {
        $(window).scrollTop(0);
        return;
      }

      var lockon = new LockOn(holderId, {offsetCalculator: offset});
      var holder = $(holderId);

      if(holder.length > 0 && opts && opts.skipIfOnScreen){

        // if we are on screen skip
        var elementTop = lockon.elementTop(),
            scrollTop = $(window).scrollTop(),
            windowHeight = $(window).height()-offset(),
            height = holder.height();

        if (elementTop > scrollTop &&
            (elementTop + height) < (scrollTop + windowHeight)) {
          return;
        }
      }

      lockon.lock();

    });
  },

  /**
    Browser aware replaceState. Will only be invoked if the browser supports it.

    @method replaceState
    @param {String} path The path we are replacing our history state with.
  **/
  replaceState: function(path) {
    if (window.history &&
        window.history.pushState &&
        window.history.replaceState &&
        !navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]|WebApps\/.+CFNetwork)/) &&
        (window.location.pathname !== path)) {

        // Always use replaceState in the next runloop to prevent weird routes changing
        // while URLs are loading. For example, while a topic loads it sets `currentPost`
        // which triggers a replaceState even though the topic hasn't fully loaded yet!
        Em.run.next(function() {
          var location = Discourse.URL.get('router.location');
          if (location && location.replaceURL) {
            location.replaceURL(path);
          }
        });
    }
  },

  // Scroll to the same page, different anchor
  scrollToId: function(id) {
    if (Em.isEmpty(id)) { return; }

    jumpScheduled = true;
    Em.run.schedule('afterRender', function() {
      var $elem = $(id);
      if ($elem.length === 0) {
        $elem = $("[name='" + id.replace('#', '') + "']");
      }
      if ($elem.length > 0) {
        $('html,body').scrollTop($elem.offset().top - $('header').height() - 15);
        jumpScheduled = false;
      }
    });
  },

  /**
    Our custom routeTo method is used to intelligently overwrite default routing
    behavior.

    It contains the logic necessary to route within a topic using replaceState to
    keep the history intact.

    @method routeTo
    @param {String} path The path we are routing to.
  **/
  routeTo: function(path) {

    if (Em.isEmpty(path)) { return; }

    if (Discourse.get('requiresRefresh')) {
      document.location.href = Discourse.getURL(path);
      return;
    }

    // Protocol relative URLs
    if (path.indexOf('//') === 0) {
      document.location = path;
      return;
    }

    // Scroll to the same page, different anchor
    if (path.indexOf('#') === 0) {
      this.scrollToId(path);
      return;
    }

    var oldPath = window.location.pathname;
    path = path.replace(/(https?\:)?\/\/[^\/]+/, '');

    // handle prefixes
    if (path.match(/^\//)) {
      var rootURL = (Discourse.BaseUri === undefined ? "/" : Discourse.BaseUri);
      rootURL = rootURL.replace(/\/$/, '');
      path = path.replace(rootURL, '');
    }

    // Rewrite /my/* urls
    if (path.indexOf('/my/') === 0) {
      var currentUser = Discourse.User.current();
      if (currentUser) {
        path = path.replace('/my/', '/users/' + currentUser.get('username_lower') + "/");
      } else {
        document.location.href = "/404";
        return;
      }
    }

    rewrites.forEach(function(rw) {
      path = path.replace(rw.regexp, rw.replacement);
    });

    if (this.navigatedToPost(oldPath, path)) { return; }
    // Schedule a DOM cleanup event
    Em.run.scheduleOnce('afterRender', Discourse.Route, 'cleanDOM');

    // TODO: Extract into rules we can inject into the URL handler
    if (this.navigatedToHome(oldPath, path)) { return; }

    if (oldPath === path) {
      // If navigating to the same path send an app event. Views can watch it
      // and tell their controllers to refresh
      this.appEvents.trigger('url:refresh');
    }

    return this.handleURL(path);
  },

  rewrite: function(regexp, replacement) {
    rewrites.push({ regexp: regexp, replacement: replacement });
  },

  redirectTo: function(url) {
    window.location = Discourse.getURL(url);
  },

  /**
   * Determines whether a URL is internal or not
   *
   * @method isInternal
   * @param {String} url
  **/
  isInternal: function(url) {
    if (url && url.length) {
      if (url.indexOf('#') === 0) { return true; }
      if (url.indexOf('/') === 0) { return true; }
      if (url.indexOf(this.origin()) === 0) { return true; }
      if (url.replace(/^http/, 'https').indexOf(this.origin()) === 0) { return true; }
      if (url.replace(/^https/, 'http').indexOf(this.origin()) === 0) { return true; }
    }
    return false;
  },

  /**
    @private

    If the URL is in the topic form, /t/something/:topic_id/:post_number
    then we want to apply some special logic. If the post_number changes within the
    same topic, use replaceState and instruct our controller to load more posts.

    @method navigatedToPost
    @param {String} oldPath the previous path we were on
    @param {String} path the path we're navigating to
  **/
  navigatedToPost: function(oldPath, path) {
    var newMatches = this.TOPIC_REGEXP.exec(path),
        newTopicId = newMatches ? newMatches[2] : null;

    if (newTopicId) {
      var oldMatches = this.TOPIC_REGEXP.exec(oldPath),
          oldTopicId = oldMatches ? oldMatches[2] : null;

      // If the topic_id is the same
      if (oldTopicId === newTopicId) {
        Discourse.URL.replaceState(path);

        var container = Discourse.__container__,
            topicController = container.lookup('controller:topic'),
            opts = {},
            postStream = topicController.get('model.postStream');

        if (newMatches[3]) opts.nearPost = newMatches[3];
        if (path.match(/last$/)) { opts.nearPost = topicController.get('highest_post_number'); }
        var closest = opts.nearPost || 1;

        var self = this;
        postStream.refresh(opts).then(function() {
          topicController.setProperties({
            'model.currentPost': closest,
            enteredAt: new Date().getTime().toString()
          });
          var closestPost = postStream.closestPostForPostNumber(closest),
              progress = postStream.progressIndexOfPost(closestPost),
              progressController = container.lookup('controller:topic-progress');

          progressController.set('progressPosition', progress);
          self.appEvents.trigger('post:highlight', closest);
        }).then(function() {
          Discourse.URL.jumpToPost(closest, {skipIfOnScreen: true});
        });

        // Abort routing, we have replaced our state.
        return true;
      }
    }

    return false;
  },

  /**
    @private

    Handle the custom case of routing to the root path from itself.

    @param {String} oldPath the previous path we were on
    @param {String} path the path we're navigating to
  **/
  navigatedToHome: function(oldPath, path) {
    var homepage = Discourse.Utilities.defaultHomepage();

    if (window.history &&
        window.history.pushState &&
        (path === "/" || path === "/" + homepage) &&
        (oldPath === "/" || oldPath === "/" + homepage)) {
      this.appEvents.trigger('url:refresh');
      return true;
    }

    return false;
  },

  /**
    @private

    Get the origin of the current location.
    This has been extracted so it can be tested.

    @method origin
  **/
  origin: function() {
    return window.location.origin;
  },

  /**
    @private

    Get a handle on the application's router. Note that currently it uses `__container__` which is not
    advised but there is no other way to access the router.

    @property router
  **/
  router: function() {
    return Discourse.__container__.lookup('router:main');
  }.property().volatile(),

  /**
    @private

    Get a controller. Note that currently it uses `__container__` which is not
    advised but there is no other way to access the router.

    @method controllerFor
    @param {String} name the name of the controller
  **/
  controllerFor: function(name) {
    return Discourse.__container__.lookup('controller:' + name);
  },

  /**
    @private

    Be wary of looking up the router. In this case, we have links in our
    HTML, say form compiled markdown posts, that need to be routed.

    @method handleURL
    @param {String} path the url to handle
  **/
  handleURL: function(path) {
    var router = this.get('router');
    router.router.updateURL(path);

    var split = path.split('#'),
        elementId;

    if (split.length === 2) {
      path = split[0];
      elementId = split[1];
    }

    var transition = router.handleURL(path);
    transition._discourse_intercepted = true;
    transition.promise.then(function() {
      if (elementId) {

        jumpScheduled = true;
        Em.run.next('afterRender', function() {
          var offset = $('#' + elementId).offset();
          if (offset && offset.top) {
            $('html, body').scrollTop(offset.top - $('header').height() - 10);
            jumpScheduled = false;
          }
        });
      }
    });
  }

});
<|endoftext|>


<commit_before>$(document).ready( function() {
  fixButtons();
  bindFileInput($("#icon_files"));
});

function fixButtons() {
  $(".icon-row-add").hide().unbind();
  $(".icon-row-add").last().show();
  $(".icon-row-rem").show();
  $(".icon-row-rem").first().hide();
  bindAdd();
  bindRem();
  $("#icon-table tr.icon-row:odd td").removeClass('even').addClass("odd");
  $("#icon-table tr.icon-row:even td").removeClass('odd').addClass("even");
};

function bindAdd() {
  $(".icon-row-add").click(function () {
    addNewRow();
    fixButtons();
  });
};

function addNewRow() {
  var new_row = $(".icon-row:last").clone();
  var index = new_row.data('index') + 1;
  new_row.attr('data-index', index);

  // clear all input values in the clone
  var inputs = new_row.find('input');
  inputs.val('');

  // handle the URL field specially
  // because uploads have special UI
  var urlField = inputs.first();
  new_row.find('.conf').remove();
  urlField.show();
  urlField.attr('id', 'icons_'+index+'_url');

  new_row.insertBefore($(".submit-row"));
  return index;
};

function bindRem() {
  $(".icon-row-rem").click(function () {
    var rem_row = $(this).parent().parent();
    rem_row.remove();
    fixButtons();
  });
};

function bindFileInput(fileInput) {
    var form         = $('form.icon-upload');
    var submitButton = form.find('input[type="submit"]');
    var formData     = form.data('form-data');

    fileInput.fileupload({
      fileInput:       fileInput,
      url:             form.data('url'),
      type:            'POST',
      autoUpload:       true,
      formData:         formData,
      paramName:        'file', // S3 does not like nested name fields i.e. name="user[avatar_url]"
      dataType:         'XML',  // S3 returns XML if success_action_status is set to 201
      replaceFileInput: false,

      add: function (e, data) {
        var fileType = data.files[0].type;
        if (!fileType.startsWith('image/')) {
          alert("You must upload files with an image filetype such as .png or .jpg - please retry with a valid file.");
          return;
        } else if (fileType === 'image/tiff') {
          alert("Unfortunately, .tiff files are only supported by Safari - please retry with a valid file.");
          return
        }

        formData["Content-Type"] = fileType;
        data.formData = formData;
        data.submit();
        fileInput.val('');
      },
      start: function (e) {
        submitButton.prop('disabled', true);
      },
      done: function(e, data) {
        submitButton.prop('disabled', false);

        // extract key and generate URL from response
        var key   = $(data.jqXHR.responseXML).find("Key").text();
        var url   = 'https://d1anwqy6ci9o1i.cloudfront.net/' + key;

        // create hidden field
        var iconIndex = addNewRow();
        var urlInput = $("#icons_"+iconIndex+"_url");
        var urlCell = $(urlInput.parents('td:first'));
        urlInput.hide().val(url);
        urlCell.find('.conf').remove();
        var uploaded = ' Uploaded ' + data.files[0].name;
        urlCell.append(""+uploaded+"");
        cleanUpRows();
      },
      fail: function(e, data) {
        var iconIndex = data.iconIndex;
        submitButton.prop('disabled', false);
        var response = data.response().jqXHR
        var policyExpired = response.responseText.includes("Invalid according to Policy: Policy expired.");
        var badFiletype = response.responseText.includes("Policy Condition failed") && response.responseText.includes('"$Content-Type", "image/"');
        var bugsData = {
          'response_status': response.status,
          'response_body': response.responseText,
          'response_text': response.statusText,
          'file_name': data.files[0].name,
          'file_type': data.files[0].type,
        };
        if (policyExpired) {
          alert("Your upload permissions appear to have expired. Please refresh the page and try again.");
        } else if (badFiletype) {
          alert("You must upload files with an image filetype such as .png or .jpg - please retry with a valid file.");
        } else {
          $.post('/bugs', bugsData);
          alert("Upload of " + data.files[0].name + " failed, Marri has been notified.");
        }
      },
    });
};

function cleanUpRows() {
  $(".icon-row").each(function (index) {
    var anySet = false;
    if ($(this).find('.conf').length > 0) { return true; }
    $(this).find('input').each(function() {
      if($(this).val() != '') {
        anySet = true;
        return false;
      }
    });
    if (!anySet) { $(this).remove(); }
  });
  $(".icon-row").each(function (index) {
    $(this).attr('data-index', index);
    $(this).find('input').first().attr('id', 'icons_'+index+'_url');
  });
  fixButtons();
};
<commit_msg>Fixes issue #171. Added an additional timeout error warning on icon upload<commit_after>$(document).ready( function() {
  fixButtons();
  bindFileInput($("#icon_files"));
});

function fixButtons() {
  $(".icon-row-add").hide().unbind();
  $(".icon-row-add").last().show();
  $(".icon-row-rem").show();
  $(".icon-row-rem").first().hide();
  bindAdd();
  bindRem();
  $("#icon-table tr.icon-row:odd td").removeClass('even').addClass("odd");
  $("#icon-table tr.icon-row:even td").removeClass('odd').addClass("even");
};

function bindAdd() {
  $(".icon-row-add").click(function () {
    addNewRow();
    fixButtons();
  });
};

function addNewRow() {
  var new_row = $(".icon-row:last").clone();
  var index = new_row.data('index') + 1;
  new_row.attr('data-index', index);

  // clear all input values in the clone
  var inputs = new_row.find('input');
  inputs.val('');

  // handle the URL field specially
  // because uploads have special UI
  var urlField = inputs.first();
  new_row.find('.conf').remove();
  urlField.show();
  urlField.attr('id', 'icons_'+index+'_url');

  new_row.insertBefore($(".submit-row"));
  return index;
};

function bindRem() {
  $(".icon-row-rem").click(function () {
    var rem_row = $(this).parent().parent();
    rem_row.remove();
    fixButtons();
  });
};

function bindFileInput(fileInput) {
    var form         = $('form.icon-upload');
    var submitButton = form.find('input[type="submit"]');
    var formData     = form.data('form-data');

    fileInput.fileupload({
      fileInput:       fileInput,
      url:             form.data('url'),
      type:            'POST',
      autoUpload:       true,
      formData:         formData,
      paramName:        'file', // S3 does not like nested name fields i.e. name="user[avatar_url]"
      dataType:         'XML',  // S3 returns XML if success_action_status is set to 201
      replaceFileInput: false,

      add: function (e, data) {
        var fileType = data.files[0].type;
        if (!fileType.startsWith('image/')) {
          alert("You must upload files with an image filetype such as .png or .jpg - please retry with a valid file.");
          return;
        } else if (fileType === 'image/tiff') {
          alert("Unfortunately, .tiff files are only supported by Safari - please retry with a valid file.");
          return
        }

        formData["Content-Type"] = fileType;
        data.formData = formData;
        data.submit();
        fileInput.val('');
      },
      start: function (e) {
        submitButton.prop('disabled', true);
      },
      done: function(e, data) {
        submitButton.prop('disabled', false);

        // extract key and generate URL from response
        var key   = $(data.jqXHR.responseXML).find("Key").text();
        var url   = 'https://d1anwqy6ci9o1i.cloudfront.net/' + key;

        // create hidden field
        var iconIndex = addNewRow();
        var urlInput = $("#icons_"+iconIndex+"_url");
        var urlCell = $(urlInput.parents('td:first'));
        urlInput.hide().val(url);
        urlCell.find('.conf').remove();
        var uploaded = ' Uploaded ' + data.files[0].name;
        urlCell.append(""+uploaded+"");
        cleanUpRows();
      },
      fail: function(e, data) {
        var iconIndex = data.iconIndex;
        submitButton.prop('disabled', false);
        var response = data.response().jqXHR
        var policyExpired = response.responseText.includes("Invalid according to Policy: Policy expired.");
        if (!policyExpired) { policyExpired = response.responseText.includes("Idle connections will be closed."); }
        var badFiletype = response.responseText.includes("Policy Condition failed") && response.responseText.includes('"$Content-Type", "image/"');
        var bugsData = {
          'response_status': response.status,
          'response_body': response.responseText,
          'response_text': response.statusText,
          'file_name': data.files[0].name,
          'file_type': data.files[0].type,
        };
        if (policyExpired) {
          alert("Your upload permissions appear to have expired. Please refresh the page and try again.");
        } else if (badFiletype) {
          alert("You must upload files with an image filetype such as .png or .jpg - please retry with a valid file.");
        } else {
          $.post('/bugs', bugsData);
          alert("Upload of " + data.files[0].name + " failed, Marri has been notified.");
        }
      },
    });
};

function cleanUpRows() {
  $(".icon-row").each(function (index) {
    var anySet = false;
    if ($(this).find('.conf').length > 0) { return true; }
    $(this).find('input').each(function() {
      if($(this).val() != '') {
        anySet = true;
        return false;
      }
    });
    if (!anySet) { $(this).remove(); }
  });
  $(".icon-row").each(function (index) {
    $(this).attr('data-index', index);
    $(this).find('input').first().attr('id', 'icons_'+index+'_url');
  });
  fixButtons();
};
<|endoftext|>