<commit_before>function clearStudyQuestionMode() {
    if (userStudyMode){
        if (!tabManager.hopToUnfinishedQuestionInProgress){
            $('#q-and-a-div').empty();
        }
    }
    $("#left-block-div").remove();
    $("#right-block-div").remove();
    //activeStudyQuestionManager = undefined;
}
function getStudyQuestionManager(questions, userId, treatmentId) {
    var sqm = {};
    sqm.renderer = getStudyQuestionRenderer();
    sqm.userId = userId;
    sqm.treatmentId = treatmentId;

    sqm.questionMap = {};
    sqm.questionIds = [];
    sqm.allQuestionsAtDecisionPointAnswered = false;
    sqm.mostRecentlyPosedQuestion = undefined;
    sqm.didWeDisplayWait = [];

    for (var i in questions){
        var question = questions[i];
        var step = question.getStep();
        var questionIndexForStep = question.getQuestionIdForStep();;
        var questionId = getQuestionId(step, questionIndexForStep);
        var answers = question.getAnswersList();
        var qu = {};
        qu.step = step;
        qu.questionIndexForStep = questionIndexForStep;
        qu.questionId = questionId;
        qu.questionText= question.getQuestion();;
        qu.isClickCollectingQuestion = function() {
            return ((this.questionType == "waitForClick") || (this.questionType =="waitForPredictionClick"));
        }
        var allTypeInfo = question.getQuestionType();
        var typeParts = allTypeInfo.split(":");
        qu.questionType = typeParts[0];
        if (qu.isClickCollectingQuestion()){
            qu.regionsToAllow = typeParts[1].split("_");
            qu.clickQuestionText = typeParts[2];
        }
        qu.answers = answers;
        sqm.questionIds.push(questionId);
        sqm.questionMap[questionId] = qu;
    }
    sqm.squim = getStudyQuestionIndexManager(sqm.questionIds);
    studyQuestionIndexManager = sqm.squim;
    sqm.accessManager = getQuestionAccessManager(sqm.squim.getDecisionPointSteps(), sessionIndexManager.getMaxIndex());

    sqm.configureForCurrentStep = function() {
        var currentStep = sessionIndexManager.getCurrentIndex();
        if (this.squim.hasQuestionForStep(currentStep)) {
            this.poseCurrentQuestion();
        }
    }

    sqm.hasMoreQuestions = function() {
        return this.squim.hasMoreQuestions();
    }

    sqm.isFinalQuestionAtDecisionPoint = function(id){
        var step = getStepFromQuestionId(id);
        var index = this.questionIds.indexOf(id);
        if (index == -1) {
            // just move on - shouldn't happen
            return false;
        }
        if (step == "summary"){
            return false;
        }
        if (index == this.questionIds.length - 1){
            // it'sthe last question which is not a summary question, which should not happen, but coding for completeness
            return true;
        }
        else {
            var nextId = this.questionIds[index + 1];
            var stepFromNextId = getStepFromQuestionId(nextId);
            if (stepFromNextId == step) {
                return false;
            }
            return true;
        }
    }
    sqm.poseFirstQuestion = function() {
        var step = this.squim.getCurrentStep();
        jumpToStep(step);// FIXME comment this out first
        this.poseCurrentQuestion();
    }

    sqm.poseNextQuestion = function() {
        var priorStep = this.squim.getCurrentStep();
        this.squim.next();
        var newStep = this.squim.getCurrentStep();
        if (priorStep != newStep && !this.squim.isCurrentQuestionSummary()) {
            // move to next step
            // Jump because we are avoiding the final step of the epoch which is blank and we don't want to render it for long time.
            // this causes backing up to prior keyframe and moving forward
            jumpToStep(newStep);
        }
        this.poseCurrentQuestion();
    }

    sqm.getLegalInstrumentationTargetsForCurrentQuestion =function(){
        var qid = this.squim.getCurrentQuestionId();
        var qu = this.questionMap[qid];
        if (qu.questionType == 'waitForClick' || qu.questionType == 'waitForPredictionClick'){
            return qu.regionsToAllow;
        }
        else {
            return undefined;
        }
    }

    sqm.poseCurrentQuestion = function() {
        currentExplManager.removeAndForgetOverlaysAndOutlines();

        var qid = this.squim.getCurrentQuestionId();
        if (tabManager.wasQuestionAnsweredAlready(qid)){
            return;
        }
        var shouldAskQuestion = false;
        if (this.mostRecentlyPosedQuestion == qid){
            if (tabManager.hopToUnfinishedQuestionInProgress){
                shouldAskQuestion = true;
            }
        }
        else {
            shouldAskQuestion = true;
        }
        if (shouldAskQuestion) {
            this.mostRecentlyPosedQuestion = qid;
            var logLine = templateMap["showQuestion"];
            logLine = logLine.replace("<SHOW_Q>", qid);
            stateMonitor.setUserAction(logLine);
            stateMonitor.setQuestionId(qid);
            var qu = this.questionMap[qid];
            var currentStep = this.squim.getCurrentStep();
            this.renderer.poseQuestion(qu, this.squim.getCurrentDecisionPointNumber(), currentStep);

            this.accessManager.setQuestionState("posed");
            this.accessManager.setQuestionType(qu.questionType);
            currentExplManager.setQuestionType(qu.questionType);
            this.accessManager.setQuestionStep(currentStep);
            if (this.squim.isStepPriorToLastDecisionPoint(currentStep)) {
                this.accessManager.setRelationToFinalDecisionPoint("before");
            }
            else if (currentStep == "summary") {
                if (!tabManager.hasNextTab()) {
                    var logLine = templateMap["waitForResearcherStart"];
                    logLine = logLine.replace("<CONTINUE_BUTTON>", "yes");
                    logLine = logLine.replace("<REGION>", "waitScreen");
                    logLine = logLine.replace("<TARGET>", "enter-wait-screen");
                    userActionMonitor.pendingLogLine = logLine;
                    stateMonitor.setUserAction(logLine);
                    this.renderer.renderWaitScreen();
                }
                this.accessManager.setRelationToFinalDecisionPoint("finalStep");
            }
            else {
                this.accessManager.setRelationToFinalDecisionPoint("finalDpRange");
            }
            this.accessManager.express();
            renderDecisionPointLegend();
            // wait before show first question at DP, but not on DP1
            if (currentStep != "summary" && currentStep != 1){
                var questionIndex = qid.split(".")[1];
                var questionStep = qid.split(".")[0];
                var foundDisplayWait = false;
                if (questionIndex == 0){
                    for (var i in this.didWeDisplayWait) {
                        if (questionStep == this.didWeDisplayWait[i]) {
                            foundDisplayWait = true;
                        }
                    }
                    if (foundDisplayWait == false) {
                        this.makeUserWaitForInstructions();
                        this.didWeDisplayWait.push(questionStep);
                    }
                }
            }
        }
    }

    sqm.makeUserWaitForInstructions = function(){
        var logLine = templateMap["waitForResearcherStart"];
        logLine = logLine.replace("<CONTINUE_BUTTON>", "yes");
        logLine = logLine.replace("<REGION>", "waitScreen");
        logLine = logLine.replace("<TARGET>", "enter-wait-screen");
        userActionMonitor.pendingLogLine = logLine;
        stateMonitor.setUserAction(logLine);
        this.renderer.renderWaitScreen();
    }

    sqm.isOkToDisplayActionName = function(step){
        var currentQuestionId = this.squim.getCurrentQuestionId();
        var currentStep = currentQuestionId.split(".")[0];
        if (currentStep == "summary"){
            // all can be revealed once we make it to summary question
            return true;
        }
        var currentQuestionIndex = currentQuestionId.split(".")[1];
        if (step < currentStep) {
            // any waitForPredictionClick questions in the past would have been answered
            return true;
        }
        if (step == currentStep){
            if (currentQuestionIndex != 0){
                return true;
            }
            // first question, check if its a waitForClickPrediction
            var qu = this.questionMap[currentQuestionId];
            if (qu.questionType == "waitForPredictionClick"){
                return false;
            }
            return true;
        }
        else {
            // step > currentQuestionId's step...
            // Any future waitForPredictionClick questions need to be hidden
            if (this.doesStepHaveWaitForPredictionClickQuestion(step)){
                return false;
            }
            return true;
        }
    }

    sqm.doesStepHaveWaitForPredictionClickQuestion = function(step) {
        if (step == "summary"){
            return false;
        }
        for (var i in this.questionIds){
            var qId = this.questionIds[i];
            var curStep = qId.split(".")[0];
            if (curStep == step){
                var qu = this.questionMap[qId];
                if (qu.questionType == "waitForPredictionClick"){
                    return true;
                }
            }
        }
        return false;
    }

    sqm.getExplanationTitles = function(explanationSteps, explanationTitles){
        var result = [];
        for (var i in explanationSteps){
            var step = explanationSteps[i];
            var title = explanationTitles[i];
            if (this.isOkToDisplayActionName(step)){
                result[i] = title;
            }
            else {
                result[i] = "---";
            }
        }
        return result;
    }

    return sqm;
}

function clearUserIdScreen() {
    $("#user-id-div").remove();
    tabManager.userIdHasBeenSet = true;
    activeStudyQuestionManager.poseFirstQuestion();
}

function acceptAnswer(e) {
    var asqm = activeStudyQuestionManager;
    var renderer = asqm.renderer;
    //renderer.removeMissingClickInfoMessage();
    // block if no answer specified
    if (renderer.controlsWaitingForClick.length != 0) {
        if (renderer.clickInfoFromUserActionMonitor == undefined) {
            renderer.expressMissingClickInfoMessage();
            return;
        }
    }
    var answer = renderer.getCurrentAnswer();

    if (answer == undefined || answer == "\"\"") {
        renderer.expressMissingQuestionInfoMessage();
        return;
    }
    // gather answer, send to backend
    var currentStep = activeStudyQuestionManager.squim.getCurrentStep();
    var questionId = activeStudyQuestionManager.squim.getCurrentQuestionId();
    tabManager.noteQuestionWasAnswered(questionId);
    var currentQuestionIndexAtStep = getQuestionIndexFromQuestionId(questionId);
    var clickInfo = renderer.collectClickInfo();
    userActionMonitor.clickListener = undefined;
    var squim = activeStudyQuestionManager.squim;
    if (clickInfo == undefined){
        clickInfo = "NA";
    }
    var followupAnswer = "NA";
    if (!(currentStep == 'summary')){
        if (!isTutorial() && asqm.isFinalQuestionAtDecisionPoint(questionId)){
            followupAnswer = renderer.getCurrentFollowupAnswer();
        }
    }
    if (followupAnswer == undefined || followupAnswer == "\"\"") {
        renderer.expressMissingQuestionInfoMessage();
        return;
    }
    renderer.removeMissingQuestionInfoMessage();

    var logLine = templateMap["button-save"];
    logLine = logLine.replace("<CLCK_STEP>", currentStep);
    logLine = logLine.replace("<Q_INDEX_STEP>", currentQuestionIndexAtStep);
    logLine = logLine.replace("<USR_TXT_Q1>", answer);
    logLine = logLine.replace("<USR_TXT_Q2>", followupAnswer);
    logLine = logLine.replace("<USR_CLCK_Q>", clickInfo);
    targetClickHandler(e, logLine);

    renderer.forgetQuestion();
    currentExplManager.noteQuestionWasAnswered();
    if (squim.hasMoreQuestionsAtThisStep()) {
        renderState(gameboard_canvas, masterEntities, gameScaleFactor, 0, 0, true);
        asqm.poseNextQuestion();
    }
    else {
        if (squim.hasMoreQuestions()){
            if (getStepFromQuestionId(asqm.mostRecentlyPosedQuestion) == "summary"){
                if (!controlsManager.isPauseButtonDisplayed()){ // don't draw arrow if playing
                    renderer.renderCueAndArrowToPlayButton();
                }

            }
            else {
                if (!controlsManager.isPauseButtonDisplayed()){ // don't pause or draw arrow if playing
                    if (userInputBlocked == false) {
                        pauseGame();
                    }
                    renderer.renderCueAndArrowToPlayButton();
                }
            }

        }
        asqm.allQuestionsAtDecisionPointAnswered = true;
        if (squim.hasMoreQuestions()){
            // wait for play button to take us to next Decision Point
            controlsManager.enablePauseResume();
        }
        else {
            if (tabManager.hasNextTab()){
                tabManager.nextTab();
            }
            else {
                // renderer.poseThankYouScreen();
            }
        }
        asqm.accessManager.setQuestionState("answered");
    }
    asqm.accessManager.express();
    //currentExplManager.removeOverlaysAndOutlines();
}
<commit_msg>forgot one more with same earlier problem<commit_after>function clearStudyQuestionMode() {
    if (userStudyMode){
        if (!tabManager.hopToUnfinishedQuestionInProgress){
            $('#q-and-a-div').empty();
        }
    }
    $("#left-block-div").remove();
    $("#right-block-div").remove();
    //activeStudyQuestionManager = undefined;
}
function getStudyQuestionManager(questions, userId, treatmentId) {
    var sqm = {};
    sqm.renderer = getStudyQuestionRenderer();
    sqm.userId = userId;
    sqm.treatmentId = treatmentId;

    sqm.questionMap = {};
    sqm.questionIds = [];
    sqm.allQuestionsAtDecisionPointAnswered = false;
    sqm.mostRecentlyPosedQuestion = undefined;
    sqm.didWeDisplayWait = [];

    for (var i in questions){
        var question = questions[i];
        var step = question.getStep();
        var questionIndexForStep = question.getQuestionIdForStep();;
        var questionId = getQuestionId(step, questionIndexForStep);
        var answers = question.getAnswersList();
        var qu = {};
        qu.step = step;
        qu.questionIndexForStep = questionIndexForStep;
        qu.questionId = questionId;
        qu.questionText= question.getQuestion();;
        qu.isClickCollectingQuestion = function() {
            return ((this.questionType == "waitForClick") || (this.questionType =="waitForPredictionClick"));
        }
        var allTypeInfo = question.getQuestionType();
        var typeParts = allTypeInfo.split(":");
        qu.questionType = typeParts[0];
        if (qu.isClickCollectingQuestion()){
            qu.regionsToAllow = typeParts[1].split("_");
            qu.clickQuestionText = typeParts[2];
        }
        qu.answers = answers;
        sqm.questionIds.push(questionId);
        sqm.questionMap[questionId] = qu;
    }
    sqm.squim = getStudyQuestionIndexManager(sqm.questionIds);
    studyQuestionIndexManager = sqm.squim;
    sqm.accessManager = getQuestionAccessManager(sqm.squim.getDecisionPointSteps(), sessionIndexManager.getMaxIndex());

    sqm.configureForCurrentStep = function() {
        var currentStep = sessionIndexManager.getCurrentIndex();
        if (this.squim.hasQuestionForStep(currentStep)) {
            this.poseCurrentQuestion();
        }
    }

    sqm.hasMoreQuestions = function() {
        return this.squim.hasMoreQuestions();
    }

    sqm.isFinalQuestionAtDecisionPoint = function(id){
        var step = getStepFromQuestionId(id);
        var index = this.questionIds.indexOf(id);
        if (index == -1) {
            // just move on - shouldn't happen
            return false;
        }
        if (step == "summary"){
            return false;
        }
        if (index == this.questionIds.length - 1){
            // it'sthe last question which is not a summary question, which should not happen, but coding for completeness
            return true;
        }
        else {
            var nextId = this.questionIds[index + 1];
            var stepFromNextId = getStepFromQuestionId(nextId);
            if (stepFromNextId == step) {
                return false;
            }
            return true;
        }
    }
    sqm.poseFirstQuestion = function() {
        var step = this.squim.getCurrentStep();
        jumpToStep(step);// FIXME comment this out first
        this.poseCurrentQuestion();
    }

    sqm.poseNextQuestion = function() {
        var priorStep = this.squim.getCurrentStep();
        this.squim.next();
        var newStep = this.squim.getCurrentStep();
        if (priorStep != newStep && !this.squim.isCurrentQuestionSummary()) {
            // move to next step
            // Jump because we are avoiding the final step of the epoch which is blank and we don't want to render it for long time.
            // this causes backing up to prior keyframe and moving forward
            jumpToStep(newStep);
        }
        this.poseCurrentQuestion();
    }

    sqm.getLegalInstrumentationTargetsForCurrentQuestion =function(){
        var qid = this.squim.getCurrentQuestionId();
        var qu = this.questionMap[qid];
        if (qu.questionType == 'waitForClick' || qu.questionType == 'waitForPredictionClick'){
            return qu.regionsToAllow;
        }
        else {
            return undefined;
        }
    }

    sqm.poseCurrentQuestion = function() {
        currentExplManager.removeAndForgetOverlaysAndOutlines();

        var qid = this.squim.getCurrentQuestionId();
        if (tabManager.wasQuestionAnsweredAlready(qid)){
            return;
        }
        var shouldAskQuestion = false;
        if (this.mostRecentlyPosedQuestion == qid){
            if (tabManager.hopToUnfinishedQuestionInProgress){
                shouldAskQuestion = true;
            }
        }
        else {
            shouldAskQuestion = true;
        }
        if (shouldAskQuestion) {
            this.mostRecentlyPosedQuestion = qid;
            var logLine = templateMap["showQuestion"];
            logLine = logLine.replace("<SHOW_Q>", qid);
            stateMonitor.setUserAction(logLine);
            stateMonitor.setQuestionId(qid);
            var qu = this.questionMap[qid];
            var currentStep = this.squim.getCurrentStep();
            this.renderer.poseQuestion(qu, this.squim.getCurrentDecisionPointNumber(), currentStep);

            this.accessManager.setQuestionState("posed");
            this.accessManager.setQuestionType(qu.questionType);
            currentExplManager.setQuestionType(qu.questionType);
            this.accessManager.setQuestionStep(currentStep);
            if (this.squim.isStepPriorToLastDecisionPoint(currentStep)) {
                this.accessManager.setRelationToFinalDecisionPoint("before");
            }
            else if (currentStep == "summary") {
                if (!tabManager.hasNextTab()) {
                    var logLine = templateMap["waitForResearcherStart"];
                    logLine = logLine.replace("<CONTINUE_BUTTON>", "yes");
                    logLine = logLine.replace("<REGION>", "waitScreen");
                    logLine = logLine.replace("<TARGET>", "enter-wait-screen");
                    stateMonitor.setUserAction(logLine);
                    this.renderer.renderWaitScreen();
                }
                this.accessManager.setRelationToFinalDecisionPoint("finalStep");
            }
            else {
                this.accessManager.setRelationToFinalDecisionPoint("finalDpRange");
            }
            this.accessManager.express();
            renderDecisionPointLegend();
            // wait before show first question at DP, but not on DP1
            if (currentStep != "summary" && currentStep != 1){
                var questionIndex = qid.split(".")[1];
                var questionStep = qid.split(".")[0];
                var foundDisplayWait = false;
                if (questionIndex == 0){
                    for (var i in this.didWeDisplayWait) {
                        if (questionStep == this.didWeDisplayWait[i]) {
                            foundDisplayWait = true;
                        }
                    }
                    if (foundDisplayWait == false) {
                        this.makeUserWaitForInstructions();
                        this.didWeDisplayWait.push(questionStep);
                    }
                }
            }
        }
    }

    sqm.makeUserWaitForInstructions = function(){
        var logLine = templateMap["waitForResearcherStart"];
        logLine = logLine.replace("<CONTINUE_BUTTON>", "yes");
        logLine = logLine.replace("<REGION>", "waitScreen");
        logLine = logLine.replace("<TARGET>", "enter-wait-screen");
        stateMonitor.setUserAction(logLine);
        this.renderer.renderWaitScreen();
    }

    sqm.isOkToDisplayActionName = function(step){
        var currentQuestionId = this.squim.getCurrentQuestionId();
        var currentStep = currentQuestionId.split(".")[0];
        if (currentStep == "summary"){
            // all can be revealed once we make it to summary question
            return true;
        }
        var currentQuestionIndex = currentQuestionId.split(".")[1];
        if (step < currentStep) {
            // any waitForPredictionClick questions in the past would have been answered
            return true;
        }
        if (step == currentStep){
            if (currentQuestionIndex != 0){
                return true;
            }
            // first question, check if its a waitForClickPrediction
            var qu = this.questionMap[currentQuestionId];
            if (qu.questionType == "waitForPredictionClick"){
                return false;
            }
            return true;
        }
        else {
            // step > currentQuestionId's step...
            // Any future waitForPredictionClick questions need to be hidden
            if (this.doesStepHaveWaitForPredictionClickQuestion(step)){
                return false;
            }
            return true;
        }
    }

    sqm.doesStepHaveWaitForPredictionClickQuestion = function(step) {
        if (step == "summary"){
            return false;
        }
        for (var i in this.questionIds){
            var qId = this.questionIds[i];
            var curStep = qId.split(".")[0];
            if (curStep == step){
                var qu = this.questionMap[qId];
                if (qu.questionType == "waitForPredictionClick"){
                    return true;
                }
            }
        }
        return false;
    }

    sqm.getExplanationTitles = function(explanationSteps, explanationTitles){
        var result = [];
        for (var i in explanationSteps){
            var step = explanationSteps[i];
            var title = explanationTitles[i];
            if (this.isOkToDisplayActionName(step)){
                result[i] = title;
            }
            else {
                result[i] = "---";
            }
        }
        return result;
    }

    return sqm;
}

function clearUserIdScreen() {
    $("#user-id-div").remove();
    tabManager.userIdHasBeenSet = true;
    activeStudyQuestionManager.poseFirstQuestion();
}

function acceptAnswer(e) {
    var asqm = activeStudyQuestionManager;
    var renderer = asqm.renderer;
    //renderer.removeMissingClickInfoMessage();
    // block if no answer specified
    if (renderer.controlsWaitingForClick.length != 0) {
        if (renderer.clickInfoFromUserActionMonitor == undefined) {
            renderer.expressMissingClickInfoMessage();
            return;
        }
    }
    var answer = renderer.getCurrentAnswer();

    if (answer == undefined || answer == "\"\"") {
        renderer.expressMissingQuestionInfoMessage();
        return;
    }
    // gather answer, send to backend
    var currentStep = activeStudyQuestionManager.squim.getCurrentStep();
    var questionId = activeStudyQuestionManager.squim.getCurrentQuestionId();
    tabManager.noteQuestionWasAnswered(questionId);
    var currentQuestionIndexAtStep = getQuestionIndexFromQuestionId(questionId);
    var clickInfo = renderer.collectClickInfo();
    userActionMonitor.clickListener = undefined;
    var squim = activeStudyQuestionManager.squim;
    if (clickInfo == undefined){
        clickInfo = "NA";
    }
    var followupAnswer = "NA";
    if (!(currentStep == 'summary')){
        if (!isTutorial() && asqm.isFinalQuestionAtDecisionPoint(questionId)){
            followupAnswer = renderer.getCurrentFollowupAnswer();
        }
    }
    if (followupAnswer == undefined || followupAnswer == "\"\"") {
        renderer.expressMissingQuestionInfoMessage();
        return;
    }
    renderer.removeMissingQuestionInfoMessage();

    var logLine = templateMap["button-save"];
    logLine = logLine.replace("<CLCK_STEP>", currentStep);
    logLine = logLine.replace("<Q_INDEX_STEP>", currentQuestionIndexAtStep);
    logLine = logLine.replace("<USR_TXT_Q1>", answer);
    logLine = logLine.replace("<USR_TXT_Q2>", followupAnswer);
    logLine = logLine.replace("<USR_CLCK_Q>", clickInfo);
    targetClickHandler(e, logLine);

    renderer.forgetQuestion();
    currentExplManager.noteQuestionWasAnswered();
    if (squim.hasMoreQuestionsAtThisStep()) {
        renderState(gameboard_canvas, masterEntities, gameScaleFactor, 0, 0, true);
        asqm.poseNextQuestion();
    }
    else {
        if (squim.hasMoreQuestions()){
            if (getStepFromQuestionId(asqm.mostRecentlyPosedQuestion) == "summary"){
                if (!controlsManager.isPauseButtonDisplayed()){ // don't draw arrow if playing
                    renderer.renderCueAndArrowToPlayButton();
                }

            }
            else {
                if (!controlsManager.isPauseButtonDisplayed()){ // don't pause or draw arrow if playing
                    if (userInputBlocked == false) {
                        pauseGame();
                    }
                    renderer.renderCueAndArrowToPlayButton();
                }
            }

        }
        asqm.allQuestionsAtDecisionPointAnswered = true;
        if (squim.hasMoreQuestions()){
            // wait for play button to take us to next Decision Point
            controlsManager.enablePauseResume();
        }
        else {
            if (tabManager.hasNextTab()){
                tabManager.nextTab();
            }
            else {
                // renderer.poseThankYouScreen();
            }
        }
        asqm.accessManager.setQuestionState("answered");
    }
    asqm.accessManager.express();
    //currentExplManager.removeOverlaysAndOutlines();
}
<|endoftext|>


<commit_before>// ==UserScript==
// @name                OLog
// @namespace	        http://www.olog.com/
// @description	        OLog Userscript
// @include	            http://s135-en.ogame.gameforge.com/game/*
// ==/UserScript==

var page = getQueryVariable("page");

if (page === "messages") {
    var observer = new MutationObserver(function(mutations) {
        mutations.forEach(function(mutation) {
            for (var node of mutation.addedNodes) {
                if (node.localName === "ul" && node.classList.contains("tab_inner")) {
                    //send all messages at once such that all SR keys can be sent at once to the server
                    processMessageNodes(node.querySelectorAll(".msg"));
                }
            }
        });
    });

    observer.observe(document, { childList: true, subtree: true });
}

function processMessageNodes(nodes) {
    var srKeys = [];    //spy report
    var crKeys = [];    //combat report
    var rrKeys = [];    //recycle report
    var mrKeys = [];    //missile report
    for (var node of nodes) {
        var apiElement = node.querySelector(".icon_apikey");
        if (apiElement !== null) {
            var key = node.querySelector(".icon_apikey").title;
            var type = key.substring(0, 2);
            if (type === "sr") {
                srKeys.push(key);
            }
            else if (type === "cr") {
                crKeys.push(key);
            }
            else if (type === "rr") {
                rrKeys.push(key);
            }
            else if (type === "mr") {
                mrKeys.push(key);
            }
        }
    }
    console.log(srKeys);
    console.log(crKeys);
    console.log(rrKeys);
    console.log(mrKeys);
}

function getQueryVariable(variable) {
    var query = window.location.search.substring(1);
    var vars = query.split('&');
    for (var i = 0; i < vars.length; i++) {
        var pair = vars[i].split('=');
        if (decodeURIComponent(pair[0]) == variable) {
            return decodeURIComponent(pair[1]);
        }
    }
    console.log('Query variable %s not found', variable);
}<commit_msg>Fixed issue with tabs in the header<commit_after>// ==UserScript==
// @name                OLog
// @namespace           http://www.olog.com/
// @description         OLog Userscript
// @include             http://s135-en.ogame.gameforge.com/game/*
// ==/UserScript==

var page = getQueryVariable("page");

if (page === "messages") {
    var observer = new MutationObserver(function(mutations) {
        mutations.forEach(function(mutation) {
            for (var node of mutation.addedNodes) {
                if (node.localName === "ul" && node.classList.contains("tab_inner")) {
                    //send all messages at once such that all SR keys can be sent at once to the server
                    processMessageNodes(node.querySelectorAll(".msg"));
                }
            }
        });
    });

    observer.observe(document, { childList: true, subtree: true });
}

function processMessageNodes(nodes) {
    var srKeys = [];    //spy report
    var crKeys = [];    //combat report
    var rrKeys = [];    //recycle report
    var mrKeys = [];    //missile report
    for (var node of nodes) {
        var apiElement = node.querySelector(".icon_apikey");
        if (apiElement !== null) {
            var key = node.querySelector(".icon_apikey").title;
            var type = key.substring(0, 2);
            if (type === "sr") {
                srKeys.push(key);
            }
            else if (type === "cr") {
                crKeys.push(key);
            }
            else if (type === "rr") {
                rrKeys.push(key);
            }
            else if (type === "mr") {
                mrKeys.push(key);
            }
        }
    }
    console.log(srKeys);
    console.log(crKeys);
    console.log(rrKeys);
    console.log(mrKeys);
}

function getQueryVariable(variable) {
    var query = window.location.search.substring(1);
    var vars = query.split('&');
    for (var i = 0; i < vars.length; i++) {
        var pair = vars[i].split('=');
        if (decodeURIComponent(pair[0]) == variable) {
            return decodeURIComponent(pair[1]);
        }
    }
    console.log('Query variable %s not found', variable);
}<|endoftext|>


<commit_before>// ==UserScript==
// @name                OLog
// @namespace           http://www.olog.com/
// @description         OLog Userscript
// @downloadURL         https://github.com/skiwi2/OLog-Userscript/raw/master/olog.user.js
// @updateURL           https://github.com/skiwi2/OLog-Userscript/raw/master/olog.user.js
// @version             0.1pre
// @include             http://s*-*.ogame.gameforge.com/game/*
// @grant               GM_xmlhttpRequest
// @grant               GM_getValue
// @grant               GM_setValue
// ==/UserScript==

"use strict";

var oLogInstanceUrl = getSetting("settings.ologinstanceurl", "http://localhost:8080/");

var menuTable = document.getElementById("menuTable");

var oLogLi = document.createElement("li");
oLogLi.onfocus = function(c) {
    if (b(c.target).closest(".dropdown").length == 0) {
        b(".currentlySelected a").removeClass("hover");
        b(".currentlySelected").removeClass("focus");
    }
}

var oLogAnchor = document.createElement("a");
oLogAnchor.className = "menubutton";
oLogAnchor.href = "#ologsettings";
oLogAnchor.onclick = function() {
    showOLogSettings();
};

var oLogSpan = document.createElement("span");
oLogSpan.className = "textlabel"

var oLogText = document.createTextNode("OLog Settings");

oLogSpan.appendChild(oLogText);
oLogAnchor.appendChild(oLogSpan);
oLogLi.appendChild(oLogAnchor);
menuTable.appendChild(oLogLi);

if (window.location.hash === "#ologsettings") {
    showOLogSettings();
}

function showOLogSettings() {
    var menuTableLiList = menuTable.querySelectorAll("li");
    for (var i = 0; i < menuTableLiList.length; i++) {
        menuTableLiList[i].querySelector(".menubutton").classList.remove("selected");
    }

    oLogAnchor.classList.add("selected");

    var contentWrapperDiv = document.getElementById("contentWrapper");
    while (contentWrapperDiv.firstChild) {
        contentWrapperDiv.removeChild(contentWrapperDiv.firstChild);
    }

    var buttonzDiv = document.createElement("div");
    buttonzDiv.id = "buttonz";

    var headerDiv = document.createElement("div");
    headerDiv.className = "header";

    var headerH2 = document.createElement("h2");

    var headerText = document.createTextNode("OLog Settings");

    var contentDiv = document.createElement("div");
    contentDiv.className = "content";

    var fieldwrapperDiv = document.createElement("div");
    fieldwrapperDiv.className = "fieldwrapper";

    var oLogInstanceUrlLabel = document.createElement("label");
    oLogInstanceUrlLabel.className = "styled textBeefy";

    var oLogInstanceUrlText = document.createTextNode("OLog Instance URL:");

    var oLogInstanceUrlTheFieldDiv = document.createElement("div");
    oLogInstanceUrlTheFieldDiv.className = "thefield";

    var oLogInstanceUrlInput = document.createElement("input");
    oLogInstanceUrlInput.className = "textinput w200";
    oLogInstanceUrlInput.type = "text";
    oLogInstanceUrlInput.size = "30";
    oLogInstanceUrlInput.value = oLogInstanceUrl;
    oLogInstanceUrlInput.maxlength = "20";

    var settingsSaveDiv = document.createElement("div");
    settingsSaveDiv.className = "textCenter";

    var settingsSaveInput = document.createElement("input");
    settingsSaveInput.className = "btn_blue";
    settingsSaveInput.type = "submit";
    settingsSaveInput.value = "Save settings";
    settingsSaveInput.onclick = function() {
        saveSetting("settings.ologinstanceurl", oLogInstanceUrlInput.value);
        showSuccessMessage("Settings have been saved.");
    };

    oLogInstanceUrlLabel.appendChild(oLogInstanceUrlText);
    oLogInstanceUrlTheFieldDiv.appendChild(oLogInstanceUrlInput);
    fieldwrapperDiv.appendChild(oLogInstanceUrlLabel);
    fieldwrapperDiv.appendChild(oLogInstanceUrlTheFieldDiv);

    settingsSaveDiv.appendChild(settingsSaveInput);

    contentDiv.appendChild(fieldwrapperDiv);
    contentDiv.appendChild(settingsSaveDiv);

    headerH2.appendChild(headerText);
    headerDiv.appendChild(headerH2);
    buttonzDiv.appendChild(headerDiv);
    buttonzDiv.appendChild(contentDiv);
    contentWrapperDiv.appendChild(buttonzDiv);
}

var page = getWindowVariable("currentPage");

if (page === "messages") {
    var observer = new MutationObserver(function(mutations) {
        mutations.forEach(function(mutation) {
            for(var i = 0; i < mutation.addedNodes.length; i++) {
                var node = mutation.addedNodes[i];
                if (node.localName === "ul" && node.classList.contains("tab_inner")) {
                    //send all messages at once such that all SR keys can be sent at once to the server
                    processMessageNodes(node.querySelectorAll(".msg"));
                }
            }
        });
    });

    observer.observe(document, { childList: true, subtree: true });
}

function processMessageNodes(nodes) {
    var reportKeys = {
        sr: [],     //spy report
        cr: [],     //combat report
        rr: [],     //recycle report
        mr: []      //missile report
    };

    for (var i = 0; i < nodes.length; i++) {
        var node = nodes[i];
        var apiElement = node.querySelector(".icon_apikey");
        if (apiElement !== null) {
            var key = apiElement.parentNode.href.replace(/.*?:\/\//g, "");
            var type = key.substring(0, 2);
            if (reportKeys.hasOwnProperty(type)) {
                reportKeys[type].push(key);
            }
        }
    }

    console.log(reportKeys);

    postData({
        endpoint: "keys",
        data: {
            reportKeys: reportKeys
        }
    });
}

function postData(object) {
    addPlayerData(object.data);
    console.log(JSON.stringify(object.data));
    GM_xmlhttpRequest({
        method: "POST",
        url: oLogInstanceUrl + "api/userscript/" + object.endpoint,
        data: JSON.stringify(object.data),
        headers: {
            "Content-Type": "application/json"
        },
        onload: function(response) {
            console.log("load");
        },
        onerror: function(response) {
            console.log("error");
        }
    });
}

function addPlayerData(data) {
    data.serverGroup = getWindowVariable("constants.language");
    data.universe = getWindowVariable("constants.name");
    data.playerId = getWindowVariable("playerId");
    data.playerName = getWindowVariable("playerName");
}

/**
 * Returns a global variable.
 *
 * Needed because a @grant other than none puts the script
 * in a separate scope.
 *
 * @param {string} name The name of the global variable.
 */
function getWindowVariable(name) {
    return window.eval(name);
}

function showSuccessMessage(message) {
    getWindowVariable("fadeBox")(message, false);
}

function showErrorMessage(message) {
    getWindowVariable("fadeBox")(message, true);
}

function saveSetting(key, value) {
    var fullKey = getWindowVariable("constants.language") + ":" + getWindowVariable("constants.name") + ":" + getWindowVariable("playerId") + ":" + key;
    GM_setValue(fullKey, value);
}

function getSetting(key, defaultValue) {
    var fullKey = getWindowVariable("constants.language") + ":" + getWindowVariable("constants.name") + ":" + getWindowVariable("playerId") + ":" + key;
    return GM_getValue(fullKey, defaultValue);
}<commit_msg>Updated version to 0.1.<commit_after>// ==UserScript==
// @name                OLog
// @namespace           http://www.olog.com/
// @description         OLog Userscript
// @downloadURL         https://github.com/skiwi2/OLog-Userscript/raw/master/olog.user.js
// @updateURL           https://github.com/skiwi2/OLog-Userscript/raw/master/olog.user.js
// @version             0.1
// @include             http://s*-*.ogame.gameforge.com/game/*
// @grant               GM_xmlhttpRequest
// @grant               GM_getValue
// @grant               GM_setValue
// ==/UserScript==

"use strict";

var oLogInstanceUrl = getSetting("settings.ologinstanceurl", "http://localhost:8080/");

var menuTable = document.getElementById("menuTable");

var oLogLi = document.createElement("li");
oLogLi.onfocus = function(c) {
    if (b(c.target).closest(".dropdown").length == 0) {
        b(".currentlySelected a").removeClass("hover");
        b(".currentlySelected").removeClass("focus");
    }
}

var oLogAnchor = document.createElement("a");
oLogAnchor.className = "menubutton";
oLogAnchor.href = "#ologsettings";
oLogAnchor.onclick = function() {
    showOLogSettings();
};

var oLogSpan = document.createElement("span");
oLogSpan.className = "textlabel"

var oLogText = document.createTextNode("OLog Settings");

oLogSpan.appendChild(oLogText);
oLogAnchor.appendChild(oLogSpan);
oLogLi.appendChild(oLogAnchor);
menuTable.appendChild(oLogLi);

if (window.location.hash === "#ologsettings") {
    showOLogSettings();
}

function showOLogSettings() {
    var menuTableLiList = menuTable.querySelectorAll("li");
    for (var i = 0; i < menuTableLiList.length; i++) {
        menuTableLiList[i].querySelector(".menubutton").classList.remove("selected");
    }

    oLogAnchor.classList.add("selected");

    var contentWrapperDiv = document.getElementById("contentWrapper");
    while (contentWrapperDiv.firstChild) {
        contentWrapperDiv.removeChild(contentWrapperDiv.firstChild);
    }

    var buttonzDiv = document.createElement("div");
    buttonzDiv.id = "buttonz";

    var headerDiv = document.createElement("div");
    headerDiv.className = "header";

    var headerH2 = document.createElement("h2");

    var headerText = document.createTextNode("OLog Settings");

    var contentDiv = document.createElement("div");
    contentDiv.className = "content";

    var fieldwrapperDiv = document.createElement("div");
    fieldwrapperDiv.className = "fieldwrapper";

    var oLogInstanceUrlLabel = document.createElement("label");
    oLogInstanceUrlLabel.className = "styled textBeefy";

    var oLogInstanceUrlText = document.createTextNode("OLog Instance URL:");

    var oLogInstanceUrlTheFieldDiv = document.createElement("div");
    oLogInstanceUrlTheFieldDiv.className = "thefield";

    var oLogInstanceUrlInput = document.createElement("input");
    oLogInstanceUrlInput.className = "textinput w200";
    oLogInstanceUrlInput.type = "text";
    oLogInstanceUrlInput.size = "30";
    oLogInstanceUrlInput.value = oLogInstanceUrl;
    oLogInstanceUrlInput.maxlength = "20";

    var settingsSaveDiv = document.createElement("div");
    settingsSaveDiv.className = "textCenter";

    var settingsSaveInput = document.createElement("input");
    settingsSaveInput.className = "btn_blue";
    settingsSaveInput.type = "submit";
    settingsSaveInput.value = "Save settings";
    settingsSaveInput.onclick = function() {
        saveSetting("settings.ologinstanceurl", oLogInstanceUrlInput.value);
        showSuccessMessage("Settings have been saved.");
    };

    oLogInstanceUrlLabel.appendChild(oLogInstanceUrlText);
    oLogInstanceUrlTheFieldDiv.appendChild(oLogInstanceUrlInput);
    fieldwrapperDiv.appendChild(oLogInstanceUrlLabel);
    fieldwrapperDiv.appendChild(oLogInstanceUrlTheFieldDiv);

    settingsSaveDiv.appendChild(settingsSaveInput);

    contentDiv.appendChild(fieldwrapperDiv);
    contentDiv.appendChild(settingsSaveDiv);

    headerH2.appendChild(headerText);
    headerDiv.appendChild(headerH2);
    buttonzDiv.appendChild(headerDiv);
    buttonzDiv.appendChild(contentDiv);
    contentWrapperDiv.appendChild(buttonzDiv);
}

var page = getWindowVariable("currentPage");

if (page === "messages") {
    var observer = new MutationObserver(function(mutations) {
        mutations.forEach(function(mutation) {
            for(var i = 0; i < mutation.addedNodes.length; i++) {
                var node = mutation.addedNodes[i];
                if (node.localName === "ul" && node.classList.contains("tab_inner")) {
                    //send all messages at once such that all SR keys can be sent at once to the server
                    processMessageNodes(node.querySelectorAll(".msg"));
                }
            }
        });
    });

    observer.observe(document, { childList: true, subtree: true });
}

function processMessageNodes(nodes) {
    var reportKeys = {
        sr: [],     //spy report
        cr: [],     //combat report
        rr: [],     //recycle report
        mr: []      //missile report
    };

    for (var i = 0; i < nodes.length; i++) {
        var node = nodes[i];
        var apiElement = node.querySelector(".icon_apikey");
        if (apiElement !== null) {
            var key = apiElement.parentNode.href.replace(/.*?:\/\//g, "");
            var type = key.substring(0, 2);
            if (reportKeys.hasOwnProperty(type)) {
                reportKeys[type].push(key);
            }
        }
    }

    console.log(reportKeys);

    postData({
        endpoint: "keys",
        data: {
            reportKeys: reportKeys
        }
    });
}

function postData(object) {
    addPlayerData(object.data);
    console.log(JSON.stringify(object.data));
    GM_xmlhttpRequest({
        method: "POST",
        url: oLogInstanceUrl + "api/userscript/" + object.endpoint,
        data: JSON.stringify(object.data),
        headers: {
            "Content-Type": "application/json"
        },
        onload: function(response) {
            console.log("load");
        },
        onerror: function(response) {
            console.log("error");
        }
    });
}

function addPlayerData(data) {
    data.serverGroup = getWindowVariable("constants.language");
    data.universe = getWindowVariable("constants.name");
    data.playerId = getWindowVariable("playerId");
    data.playerName = getWindowVariable("playerName");
}

/**
 * Returns a global variable.
 *
 * Needed because a @grant other than none puts the script
 * in a separate scope.
 *
 * @param {string} name The name of the global variable.
 */
function getWindowVariable(name) {
    return window.eval(name);
}

function showSuccessMessage(message) {
    getWindowVariable("fadeBox")(message, false);
}

function showErrorMessage(message) {
    getWindowVariable("fadeBox")(message, true);
}

function saveSetting(key, value) {
    var fullKey = getWindowVariable("constants.language") + ":" + getWindowVariable("constants.name") + ":" + getWindowVariable("playerId") + ":" + key;
    GM_setValue(fullKey, value);
}

function getSetting(key, defaultValue) {
    var fullKey = getWindowVariable("constants.language") + ":" + getWindowVariable("constants.name") + ":" + getWindowVariable("playerId") + ":" + key;
    return GM_getValue(fullKey, defaultValue);
}<|endoftext|>


<commit_before>var MegalinkCardView = require('./MegalinkCardView');

function MegalinkRangeView() {
    this.initialize();
}

module.exports = MegalinkRangeView;

// --- External API ---
MegalinkRangeView.prototype.setRange = function (range) {
    this.range = range;

    while (this.cardViews.length < range.cards.length) {
        var cardView = new MegalinkCardView();
        cardView.canvas.style.marginBottom = '-4px';
        this.el.appendChild(cardView.canvas);

        this.cardViews.push(cardView);
    }

    while (this.cardViews.length > range.cards.length) {
        var cardView = this.cardViews.pop();
        this.el.removeChild(cardView.canvas);
    }

    var i = 0;
    for (var idx in range.cards) {
        var card = range.cards[idx];
        var cardView = this.cardViews[i++];

        cardView.setCard(card);
    }

    this.updateSize();
    this.draw();
};

// --- Internal API ---
MegalinkRangeView.HEADER_HEIGHT = 90;
MegalinkRangeView.HEADER_MARGIN = 8;
MegalinkRangeView.HEADER_FONT_COLOR = 'rgb(0, 0, 0)';

MegalinkRangeView.prototype.initialize = function () {
    this.el = document.createElement('div');

    this.header = document.createElement('canvas');
    this.el.appendChild(this.header);

    this.cardViews = [];
};

MegalinkRangeView.prototype.draw = function () {
    if (this.range) {
        this.drawHeader();
    }

    for (var idx in this.cardViews) {
        var cardView = this.cardViews[idx];

        cardView.draw();
    }
};

MegalinkRangeView.prototype.drawHeader = function () {
    var ctx = this.header.getContext('2d');
    var rect = {
        x:0,
        y:0,
        width:this.header.width,
        height:this.header.height
    };

    ctx.clearRect(rect.x, rect.y, rect.width, rect.height);

    this.renderHeader(ctx, rect);
};

MegalinkRangeView.prototype.renderHeader = function (ctx, rect) {
    this.renderHost(ctx, rect);
    this.renderRangeRelay(ctx, rect);
    this.renderLogo(ctx, rect);
};

MegalinkRangeView.prototype.renderHost = function (ctx, rect) {
    var hostRect = MegalinkRangeView.getHostRect(rect);
    var host = this.range.host;

    ctx.fillStyle = MegalinkRangeView.HEADER_FONT_COLOR;
    this.setFont(ctx, host, hostRect.width, hostRect.height);
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    ctx.fillText(host, hostRect.x + hostRect.width/2, hostRect.y + hostRect.height/2);
    ctx.textAlign = 'left';
    ctx.textBaseline = 'alphabetic';
};

MegalinkRangeView.prototype.renderRangeRelay = function (ctx, rect) {
    var rangeRelay = this.range.name + ' - Lag nr ' + this.range.relay;
    var rangeRelayRect = MegalinkRangeView.getRangeRelayRect(rect);

    ctx.fillStyle = MegalinkRangeView.HEADER_FONT_COLOR;
    this.setFont(ctx, rangeRelay, rangeRelayRect.width, rangeRelayRect.height);

    ctx.textBaseline = 'middle';
    ctx.fillText(rangeRelay, rangeRelayRect.x, rangeRelayRect.y + rangeRelayRect.height/2);
    ctx.textBaseline = 'alphabetic';
};

MegalinkRangeView.prototype.renderLogo = function (ctx, rect) {
    if (!this.logo || this.logo.width == 0) {
        this.logo = new Image();
        this.logo.src = 'images/mllogo.png';

        var self = this;
        this.logo.onload = function () {
            self.renderLogo(ctx, rect);
        };

        return;
    }

    var left = rect.width - MegalinkRangeView.HEADER_MARGIN - this.logo.width;
    var top = MegalinkRangeView.HEADER_MARGIN;

    ctx.drawImage(this.logo, left, top);
};

MegalinkRangeView.prototype.updateSize = function () {
    var width = this.el.clientWidth;
    var height = this.el.clientHeight - MegalinkRangeView.HEADER_HEIGHT;

    this.header.width = width;
    this.header.height = MegalinkRangeView.HEADER_HEIGHT;

    var N = this.cardViews.length;
    var minBadness = Number.MAX_VALUE;
    var bestM = 0;
    var bestN = 0;

    for (var m = 1; m <= N; ++m) {
        var n = Math.ceil(N / m);
        var cardWidth = width/n;
        var cardHeight = height/m;
        var targetRect = MegalinkCardView.getTargetRect({x:0, y:0, width:cardWidth, height:cardHeight});

        var aspectRatio = targetRect.width / targetRect.height;
        var optimalRatio = 1;
        var ratioBadness =  Math.abs(aspectRatio - optimalRatio) + Math.abs(1/aspectRatio - 1/optimalRatio);
        var cellCountBadness = Math.abs(n*m - N);
        var badness = ratioBadness + cellCountBadness;

        if (badness < minBadness) {
            minBadness = badness;
            bestM = m;
            bestN = n;
        }
    }

    var m = bestM;
    var n = bestN;

    var cardWidth = width/n;
    var cardHeight = height/m;

    for (var i = 0; i < m; ++i) {
        for (var j = 0; j < n; ++j) {
            var cardViewIdx = i*n + j;
            if (cardViewIdx >= this.cardViews.length) {
                break;
            }

            var cardView = this.cardViews[cardViewIdx];

            var leftEdge = Math.floor(j*cardWidth);
            var rightEdge = Math.floor((j + 1)*cardWidth);
            cardView.canvas.width = rightEdge - leftEdge;
            cardView.canvas.style.width = cardView.canvas.width + 'px';

            var topEdge = Math.floor(i*cardHeight);
            var bottomEdge = Math.floor((i + 1)*cardHeight);
            cardView.canvas.height = bottomEdge - topEdge;
            cardView.canvas.style.height = cardView.canvas.height + 'px';
        }
    }
};

MegalinkRangeView.prototype.setFont = function (ctx, text, width, height) {
    var fontName = "arial";
    var refSize = 10;

    // get reference text width
    ctx.font = refSize + "px " + fontName;
    var refTextWidth = ctx.measureText(text).width;

    // calculate maximum textHeight
    var textHeight = Math.min(height, width/refTextWidth * refSize);

    // assemble font name
    ctx.font = textHeight + "px " + fontName;
};

MegalinkRangeView.getRangeRelayRect = function (rect) {
    return {
        x:rect.x + 3*MegalinkRangeView.HEADER_MARGIN,
        y:rect.y + MegalinkRangeView.HEADER_MARGIN,
        width:rect.width/5,
        height:rect.height - 2*MegalinkRangeView.HEADER_MARGIN
    };
};

MegalinkRangeView.getHostRect = function (rect) {
    return {
        x:rect.x + rect.width/4,
        y:rect.y + 2*MegalinkRangeView.HEADER_MARGIN,
        width:rect.width/2,
        height:rect.height - 4*MegalinkRangeView.HEADER_MARGIN
    };
};
<commit_msg>Added fullscreen support to MegalinkRangeView<commit_after>var MegalinkCardView = require('./MegalinkCardView');

function MegalinkRangeView() {
    this.initialize();
}

module.exports = MegalinkRangeView;

// --- External API ---
MegalinkRangeView.prototype.setRange = function (range) {
    this.range = range;

    while (this.cardViews.length < range.cards.length) {
        var cardView = new MegalinkCardView();
        cardView.canvas.style.marginBottom = '-4px';
        this.el.appendChild(cardView.canvas);

        this.cardViews.push(cardView);
    }

    while (this.cardViews.length > range.cards.length) {
        var cardView = this.cardViews.pop();
        this.el.removeChild(cardView.canvas);
    }

    var i = 0;
    for (var idx in range.cards) {
        var card = range.cards[idx];
        var cardView = this.cardViews[i++];

        cardView.setCard(card);
    }

    this.updateSize();
    this.draw();
};

// --- Internal API ---
MegalinkRangeView.HEADER_HEIGHT = 90;
MegalinkRangeView.HEADER_MARGIN = 8;
MegalinkRangeView.HEADER_FONT_COLOR = 'rgb(0, 0, 0)';

MegalinkRangeView.prototype.initialize = function () {
    this.el = document.createElement('div');

    this.header = document.createElement('canvas');
    this.el.appendChild(this.header);

    this.el.onclick = function () {
        toggleFullscreen();

        return false;
    };

    this.cardViews = [];
};

MegalinkRangeView.prototype.draw = function () {
    if (this.range) {
        this.drawHeader();
    }

    for (var idx in this.cardViews) {
        var cardView = this.cardViews[idx];

        cardView.draw();
    }
};

MegalinkRangeView.prototype.drawHeader = function () {
    var ctx = this.header.getContext('2d');
    var rect = {
        x:0,
        y:0,
        width:this.header.width,
        height:this.header.height
    };

    ctx.clearRect(rect.x, rect.y, rect.width, rect.height);

    this.renderHeader(ctx, rect);
};

MegalinkRangeView.prototype.renderHeader = function (ctx, rect) {
    this.renderHost(ctx, rect);
    this.renderRangeRelay(ctx, rect);
    this.renderLogo(ctx, rect);
};

MegalinkRangeView.prototype.renderHost = function (ctx, rect) {
    var hostRect = MegalinkRangeView.getHostRect(rect);
    var host = this.range.host;

    ctx.fillStyle = MegalinkRangeView.HEADER_FONT_COLOR;
    this.setFont(ctx, host, hostRect.width, hostRect.height);
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    ctx.fillText(host, hostRect.x + hostRect.width/2, hostRect.y + hostRect.height/2);
    ctx.textAlign = 'left';
    ctx.textBaseline = 'alphabetic';
};

MegalinkRangeView.prototype.renderRangeRelay = function (ctx, rect) {
    var rangeRelay = this.range.name + ' - Lag nr ' + this.range.relay;
    var rangeRelayRect = MegalinkRangeView.getRangeRelayRect(rect);

    ctx.fillStyle = MegalinkRangeView.HEADER_FONT_COLOR;
    this.setFont(ctx, rangeRelay, rangeRelayRect.width, rangeRelayRect.height);

    ctx.textBaseline = 'middle';
    ctx.fillText(rangeRelay, rangeRelayRect.x, rangeRelayRect.y + rangeRelayRect.height/2);
    ctx.textBaseline = 'alphabetic';
};

MegalinkRangeView.prototype.renderLogo = function (ctx, rect) {
    if (!this.logo || this.logo.width == 0) {
        this.logo = new Image();
        this.logo.src = 'images/mllogo.png';

        var self = this;
        this.logo.onload = function () {
            self.renderLogo(ctx, rect);
        };

        return;
    }

    var left = rect.width - MegalinkRangeView.HEADER_MARGIN - this.logo.width;
    var top = MegalinkRangeView.HEADER_MARGIN;

    ctx.drawImage(this.logo, left, top);
};

MegalinkRangeView.prototype.updateSize = function () {
    var width = this.el.clientWidth;
    var height = this.el.clientHeight - MegalinkRangeView.HEADER_HEIGHT;

    this.header.width = width;
    this.header.height = MegalinkRangeView.HEADER_HEIGHT;

    var N = this.cardViews.length;
    var minBadness = Number.MAX_VALUE;
    var bestM = 0;
    var bestN = 0;

    for (var m = 1; m <= N; ++m) {
        var n = Math.ceil(N / m);
        var cardWidth = width/n;
        var cardHeight = height/m;
        var targetRect = MegalinkCardView.getTargetRect({x:0, y:0, width:cardWidth, height:cardHeight});

        var aspectRatio = targetRect.width / targetRect.height;
        var optimalRatio = 1;
        var ratioBadness =  Math.abs(aspectRatio - optimalRatio) + Math.abs(1/aspectRatio - 1/optimalRatio);
        var cellCountBadness = Math.abs(n*m - N);
        var badness = ratioBadness + cellCountBadness;

        if (badness < minBadness) {
            minBadness = badness;
            bestM = m;
            bestN = n;
        }
    }

    var m = bestM;
    var n = bestN;

    var cardWidth = width/n;
    var cardHeight = height/m;

    for (var i = 0; i < m; ++i) {
        for (var j = 0; j < n; ++j) {
            var cardViewIdx = i*n + j;
            if (cardViewIdx >= this.cardViews.length) {
                break;
            }

            var cardView = this.cardViews[cardViewIdx];

            var leftEdge = Math.floor(j*cardWidth);
            var rightEdge = Math.floor((j + 1)*cardWidth);
            cardView.canvas.width = rightEdge - leftEdge;
            cardView.canvas.style.width = cardView.canvas.width + 'px';

            var topEdge = Math.floor(i*cardHeight);
            var bottomEdge = Math.floor((i + 1)*cardHeight);
            cardView.canvas.height = bottomEdge - topEdge;
            cardView.canvas.style.height = cardView.canvas.height + 'px';
        }
    }
};

MegalinkRangeView.prototype.setFont = function (ctx, text, width, height) {
    var fontName = "arial";
    var refSize = 10;

    // get reference text width
    ctx.font = refSize + "px " + fontName;
    var refTextWidth = ctx.measureText(text).width;

    // calculate maximum textHeight
    var textHeight = Math.min(height, width/refTextWidth * refSize);

    // assemble font name
    ctx.font = textHeight + "px " + fontName;
};

MegalinkRangeView.getRangeRelayRect = function (rect) {
    return {
        x:rect.x + 3*MegalinkRangeView.HEADER_MARGIN,
        y:rect.y + MegalinkRangeView.HEADER_MARGIN,
        width:rect.width/5,
        height:rect.height - 2*MegalinkRangeView.HEADER_MARGIN
    };
};

MegalinkRangeView.getHostRect = function (rect) {
    return {
        x:rect.x + rect.width/4,
        y:rect.y + 2*MegalinkRangeView.HEADER_MARGIN,
        width:rect.width/2,
        height:rect.height - 4*MegalinkRangeView.HEADER_MARGIN
    };
};

// --- Fullscreen handling ---
function toggleFullscreen() {
    if (isFullscreen()) {
        exitFullscreen();
    } else {
        requestFullscreen();
    }

}

function fullscreenAvailable() {
    var docElm = document.documentElement;
    return (docElm.requestFullscreen || docElm.requestFullScreen ||
            docElm.mozRequestFullScreen || docElm.webkitRequestFullScreen);
}

function isFullscreen() {
    return (document.fullscreen || document.fullScreen ||
            document.mozFullScreen || document.webkitIsFullScreen);
}

function requestFullscreen() {
    var docElm = document.documentElement;
    if (docElm.requestFullScreen) {
        docElm.requestFullScreen();
    } else if (docElm.mozRequestFullScreen) {
        docElm.mozRequestFullScreen();
    } else if (docElm.webkitRequestFullScreen) {
        docElm.webkitRequestFullScreen();
    } else if (docElm.requestFullscreen) {
        docElm.requestFullscreen();
    }
}

function exitFullscreen() {
    if (document.exitFullscreen) {
        document.exitFullscreen();
    } else if (document.mozCancelFullScreen) {
        document.mozCancelFullScreen();
    } else if (document.webkitCancelFullScreen) {
        document.webkitCancelFullScreen();
    } else if (document.cancelFullscreen) {
        document.cancelFullscreen();
    }
}
<|endoftext|>


<commit_before>Spider.Sortable = Spider.Plugin.extend({
    makeSortable: function(options){
        var options = $.extend({
            listSelector: '>ul',
            items: '>li',
            update: this.handleSort.bind(this),
            receive: this.handleReceive.bind(this),
            onSort: function(){},
            // if true, an element with class sort-pos inside the li is used to determine the li position in the storage.
            // This is useful if the displayed items are a subset (with holes) of the sorted items in the storage
            useSortPos: false
        }, options);
        this.listEl = options.listEl;
        if (!this.listEl) this.listEl = $(options.listSelector, this.el);
        this.prevMinHeight = this.listEl.css('min-height');
        this.listEl.css('min-height', '20px');
        if (this.el.hasClass('tree')){
            options = $.extend(options, {
                //revert: true,
                sortIndication: {
                    down: function(item) {
                        item.before($('
'));
                    },
                    up: function(item) {
                        item.after($('
'));
                    },
                    remove: function(item) {
                        $('#list-sort-indicator').remove();
                    }
                },
                start: function(e, ui) {
                    console.log("Tree start:");
                    console.log(e);
                    console.log(ui);
                    //					ui.instance.element.treeview({update: ui.item});
                },
                update: this.handleTreeUpdate.bind(this)
            });
            this.listEl.sortableTree(options);
            // handles drops on non-subtrees nodes
            //            debugger;
            $('.desc', this.el).droppable({
                accept: "li",
                hoverClass: "drop",
                tolerance: "pointer",
                //                greedy: true,
                drop: this.handleTreeDrop.bind(this)
                // over: function(e,ui) {
                    //     ui.helper.css("outline", "1px dotted green");
                    // },
                    // out: function(e,ui) {
                        //     ui.helper.css("outline", "1px dotted red");
                        // }
            });
        }
        else{
            this.listEl.sortable(options);
        }
        this.sortableOptions = options;
    },

    disableSortable: function(){
        if (this.listEl){
            this.listEl.css('min-height', this.prevMinHeight);
            this.listEl.sortable('destroy');
        }
    },

    handleSort: function(e, ui){
        if (ui.sender) return; // handled by handleReceive
        if (!$.contains(this.listEl.get(0), ui.item.get(0))) return; // handled by handleReceive
        var mySortable = this.listEl.data('sortable');
        var realTarget = null;
        ui.item.parents().each(function(){
            var $this = $(this);
            var s = $this.data('sortable');
            if (s){
                if (s != mySortable) realTarget = $this;
                return false;
            }
        });
        if (realTarget){
            ui.sender = this.listEl;
            return realTarget.parentWidget().handleReceive(e, ui);
        }
        var pos = this.findLiPosition(ui.item);
        if (pos == -1) return;
        if (this.listEl.data('sortable').fromOutside){ // hack to work around strange jquery ui behaviour...
            return this.acceptFromSender(null, ui.item, pos);
        }
        this.remote('sort', this.getSortItemId(ui.item), pos, this.sortableOptions.onSort.bind(this));
    },

    handleReceive: function(e, ui){
        if (ui.sender == ui.item){
            // the item is received from a draggable, not from a list. For some reason the receiver is not
            // yet ready to find the position; will call acceptFromSender from handleSort.
            return;
        }
        var pos = this.findLiPosition(ui.item);
        return this.acceptFromSender(ui.sender, ui.item, pos);
    },

    handleTreeUpdate: function(e, ui){
        var parentId = ui.item.parents('li.tree').eq(0).dataObjectKey();
        var prevId = ui.item.prev('li.tree').dataObjectKey();
        this.remote('tree_sort', this.getItemId(ui.item), parentId, prevId, this.sortableOptions.onSort.bind(this));
    },

    handleTreeDrop: function(e, ui){
        if (e.target.parentNode == ui.draggable[0]) return false; //dropped over itself
        console.log('dropped inside');
        var dropLi = $(e.target.parentNode);
        var subUl = $("> "+this.listTagName, dropLi);
        if (subUl.length == 0){
            subUl = $("<"+this.listTagName+" />").appendTo(dropLi);
            this.el.treeview({add: e.target.parentNode});
        }
        subUl.append(ui.draggable);
        var parentId = $(e.target).parents('li.tree').eq(0).dataObjectKey();
        var prevId = null;
        this.remote('tree_sort', ui.draggable.dataObjectKey(), parentId, prevId);
        return false;
    },

    acceptFromSender: function(sender, item, pos){
        console.error("Accept from sender must be implemented by the widget instance");
    },

    findLiPosition: function(item){
        var cnt = 1;
        var lis = $(this.sortableOptions.items, this.listEl);
        lis.each(function(){
            if (this == item.get(0)) return false;
            cnt++;
        });
        if (cnt > lis.length) return -1; // the row was dropped outside
        if (this.sortableOptions.useSortPos && lis.length > 1){
            var realPos = -1;
            if (cnt == 1){
                realPos = parseInt(item.next().find('> .sort-pos').text(), 10) - 1;
            }
            else realPos = parseInt(item.prev().find('> .sort-pos').text(), 10) + 1;
            return realPos;
        }
        return cnt;
    },

    getSortItemId: function(li){
        var k = $('> .sort-key', li);
        if (k.length > 0) return k.text();
        return li.getDataObjectKey();
    }

});<commit_msg>In sortable.js, don't accept an item if it is not found in the list (happens in nested lists)<commit_after>Spider.Sortable = Spider.Plugin.extend({
    makeSortable: function(options){
        var options = $.extend({
            listSelector: '>ul',
            items: '>li',
            update: this.handleSort.bind(this),
            receive: this.handleReceive.bind(this),
            onSort: function(){},
            // if true, an element with class sort-pos inside the li is used to determine the li position in the storage.
            // This is useful if the displayed items are a subset (with holes) of the sorted items in the storage
            useSortPos: false
        }, options);
        this.listEl = options.listEl;
        if (!this.listEl) this.listEl = $(options.listSelector, this.el);
        this.prevMinHeight = this.listEl.css('min-height');
        this.listEl.css('min-height', '20px');
        if (this.el.hasClass('tree')){
            options = $.extend(options, {
                //revert: true,
                sortIndication: {
                    down: function(item) {
                        item.before($('
'));
                    },
                    up: function(item) {
                        item.after($('
'));
                    },
                    remove: function(item) {
                        $('#list-sort-indicator').remove();
                    }
                },
                start: function(e, ui) {
                    console.log("Tree start:");
                    console.log(e);
                    console.log(ui);
                    //					ui.instance.element.treeview({update: ui.item});
                },
                update: this.handleTreeUpdate.bind(this)
            });
            this.listEl.sortableTree(options);
            // handles drops on non-subtrees nodes
            //            debugger;
            $('.desc', this.el).droppable({
                accept: "li",
                hoverClass: "drop",
                tolerance: "pointer",
                //                greedy: true,
                drop: this.handleTreeDrop.bind(this)
                // over: function(e,ui) {
                    //     ui.helper.css("outline", "1px dotted green");
                    // },
                    // out: function(e,ui) {
                        //     ui.helper.css("outline", "1px dotted red");
                        // }
            });
        }
        else{
            this.listEl.sortable(options);
        }
        this.sortableOptions = options;
    },

    disableSortable: function(){
        if (this.listEl){
            this.listEl.css('min-height', this.prevMinHeight);
            this.listEl.sortable('destroy');
        }
    },

    handleSort: function(e, ui){
        if (ui.sender) return; // handled by handleReceive
        if (!$.contains(this.listEl.get(0), ui.item.get(0))) return; // handled by handleReceive
        var mySortable = this.listEl.data('sortable');
        var realTarget = null;
        ui.item.parents().each(function(){
            var $this = $(this);
            var s = $this.data('sortable');
            if (s){
                if (s != mySortable) realTarget = $this;
                return false;
            }
        });
        if (realTarget){
            ui.sender = this.listEl;
            return realTarget.parentWidget().handleReceive(e, ui);
        }
        var pos = this.findLiPosition(ui.item);
        if (pos == -1) return;
        if (this.listEl.data('sortable').fromOutside){ // hack to work around strange jquery ui behaviour...
            return this.acceptFromSender(null, ui.item, pos);
        }
        this.remote('sort', this.getSortItemId(ui.item), pos, this.sortableOptions.onSort.bind(this));
    },

    handleReceive: function(e, ui){
        if (ui.sender == ui.item){
            // the item is received from a draggable, not from a list. For some reason the receiver is not
            // yet ready to find the position; will call acceptFromSender from handleSort.
            return;
        }
        var pos = this.findLiPosition(ui.item);
        if (pos == -1) return;
        return this.acceptFromSender(ui.sender, ui.item, pos);
    },

    handleTreeUpdate: function(e, ui){
        var parentId = ui.item.parents('li.tree').eq(0).dataObjectKey();
        var prevId = ui.item.prev('li.tree').dataObjectKey();
        this.remote('tree_sort', this.getItemId(ui.item), parentId, prevId, this.sortableOptions.onSort.bind(this));
    },

    handleTreeDrop: function(e, ui){
        if (e.target.parentNode == ui.draggable[0]) return false; //dropped over itself
        console.log('dropped inside');
        var dropLi = $(e.target.parentNode);
        var subUl = $("> "+this.listTagName, dropLi);
        if (subUl.length == 0){
            subUl = $("<"+this.listTagName+" />").appendTo(dropLi);
            this.el.treeview({add: e.target.parentNode});
        }
        subUl.append(ui.draggable);
        var parentId = $(e.target).parents('li.tree').eq(0).dataObjectKey();
        var prevId = null;
        this.remote('tree_sort', ui.draggable.dataObjectKey(), parentId, prevId);
        return false;
    },

    acceptFromSender: function(sender, item, pos){
        console.error("Accept from sender must be implemented by the widget instance");
    },

    findLiPosition: function(item){
        var cnt = 1;
        var lis = $(this.sortableOptions.items, this.listEl);
        lis.each(function(){
            if (this == item.get(0)) return false;
            cnt++;
        });
        if (cnt > lis.length) return -1; // the row was dropped outside
        if (this.sortableOptions.useSortPos && lis.length > 1){
            var realPos = -1;
            if (cnt == 1){
                realPos = parseInt(item.next().find('> .sort-pos').text(), 10) - 1;
            }
            else realPos = parseInt(item.prev().find('> .sort-pos').text(), 10) + 1;
            return realPos;
        }
        return cnt;
    },

    getSortItemId: function(li){
        var k = $('> .sort-key', li);
        if (k.length > 0) return k.text();
        return li.getDataObjectKey();
    }

});<|endoftext|>


<commit_before>'use strict';

angular.module('publicApp')
  .controller('UsersCtrl', ['$scope', '$http', '$location', '$routeParams', 'UserService', function ($scope, $http, $location, $user, $routeParams) {
    console.log('user id', $routeParams.id);
    if ($user) {
      console.log('user is logged in');
      if (($user.id == $routeParams.id) || $user.admin) {
        console.log('user is allowed to access this resource');
      } else {
        $location.path = '/users/'+$user.id;
      }
    } else {
      $location.path = '/login';
    }

  }]);
<commit_msg>[FEATURE] Add user data variables to scope<commit_after>'use strict';

angular.module('publicApp')
  .controller('UsersCtrl', ['$scope', '$http', '$location', '$route', '$routeParams', 'UserService', function ($scope, $http, $location, $route, $routeParams, $user) {
    $scope.user = $user;
    if ($user.isLogged) {
      if (($user.id == $routeParams.id) || $user.admin) {
        // do ALL THE THINGS!
        setupDashboard();
        console.log($scope.user);
      } else {
        $location.path('/users/'+$user.id);
      }
    } else {
      $location.path('/login');
    }

    function setupDashboard() {
      $scope.user.balances = [{ currency: 'USD', amount: 1510 }, { currency: 'XAG', amount: 75 }];
      $scope.user.ripple_transactions = [];
      $scope.user.external_transaction = [];
      $scope.user.external_accounts = [];
      $scope.user.ripple_addresses = [];
    }

  }]);
<|endoftext|>


<commit_before>/* File: common.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/>.
 *
 */

'use strict';

angular.module('cnedApp').controller('CommonCtrl', function($scope, $rootScope, $location, serviceCheck, gettextCatalog, $http, configuration) {

	$scope.logout = $rootScope.loged;
	$scope.admin = $rootScope.admin;
	$scope.missingDropbox = $rootScope.dropboxWarning;
	$scope.showMenuParam = false;

	$scope.currentUserData = {};
	$rootScope.updateListProfile = false;
	$rootScope.updateProfilListe = false;
	$rootScope.modifProfilListe = false;

	//if ($location.absUrl().indexOf('http://dl.dropboxusercontent.com/') > -1) {
	//$scope.deconnectionLink = window.location.href + 'logout';

	//};
	$scope.languages = [{
		name: 'FRANCAIS',
		shade: 'fr_FR'
	}, {
		name: 'ANGLAIS',
		shade: 'en_US'
	}];
	$scope.langue = $scope.languages[0];

	$scope.workspaceLink = $location.absUrl().substring(0, $location.absUrl().indexOf('#/') + 2) + 'listDocument';
	$scope.profilLink = $location.absUrl().substring(0, $location.absUrl().indexOf('#/') + 2) + 'profiles';
	$scope.userAccountLink = $location.absUrl().substring(0, $location.absUrl().indexOf('#/') + 2) + 'userAccount';
	$scope.adminLink = $location.absUrl().substring(0, $location.absUrl().indexOf('#/') + 2) + 'adminPanel';
	$scope.docUrl = configuration.URL_REQUEST + '/styles/images/docs.png';
	$scope.logoUrl = configuration.URL_REQUEST + '/styles/images/header_logoCned.png';
	$scope.connectLink = $location.absUrl().substring(0, $location.absUrl().indexOf('#/') + 2);
	// detect current location
	$scope.isActive = function(route) {
		return route === $location.path();
	};

	$scope.showMenu = function() {
		$scope.showMenuParam = !$scope.showMenuParam;
	};

	// Changer la langue
	$scope.changerLangue = function() {
		gettextCatalog.currentLanguage = $scope.langue.shade;
		$scope.showMenuParam = false;
	};

	$rootScope.$watch('loged', function() {
		$scope.logout = $rootScope.loged;
		$scope.apply; // jshint ignore:line
	});

	$rootScope.$watch('admin', function() {
		$scope.admin = $rootScope.admin;
		$scope.apply; // jshint ignore:line
	});

	$rootScope.$watch('dropboxWarning', function() {
		$scope.guest = $rootScope.loged;
		$scope.apply; // jshint ignore:line
	});

	$rootScope.$watch('currentUser', function() {
		$scope.currentUserData = $rootScope.currentUser;
		$scope.apply; // jshint ignore:line
		if ($scope.currentUserData) {
			$scope.afficherProfilsParUser();
		}
	});

	$rootScope.$watch('updateListProfile', function() {
		if ($scope.currentUserData) {
			$scope.afficherProfilsParUser();
		}
	});

	$rootScope.$watch('updateProfilListe', function() {
		if ($scope.currentUserData) {
			$scope.afficherProfilsParUser();
		}
	});

	$rootScope.$watch('modifProfilListe', function() {
		if ($scope.currentUserData) {
			$scope.afficherProfilsParUser();
		}
	});

	$rootScope.$watch('listDocumentDropBox', function() {
		if ($rootScope.currentUser) {
			$scope.listDocumentDropBox = $rootScope.listDocumentDropBox + '#/listDocument?key=' + $rootScope.currentUser._id;
			$scope.apply;
		};

	});

	$scope.initCommon = function() {

		// var appCache = window.applicationCache;

		// console.log(appCache);
		//appCache.update(); // Attempt to update the user's cache.
		if ($location.absUrl().indexOf('key=') > -1) {
			var callbackKey = $location.absUrl().substring($location.absUrl().indexOf('key=') + 4, $location.absUrl().length);
			localStorage.setItem('compteId', callbackKey);
		};
		$('#masterContainer').show();
		var tmp = serviceCheck.getData();
		tmp.then(function(result) { // this is only run after $http completes
			if (result.loged) {
				console.log('i am loged');
				if (result.dropboxWarning === false) {
					$rootScope.dropboxWarning = false;
					$scope.missingDropbox = false;
					$rootScope.loged = true;
					$rootScope.admin = result.admin;
					$rootScope.apply; // jshint ignore:line
					if ($location.path() !== '/inscriptionContinue') {
						$location.path('/inscriptionContinue');
					}
				} else {
					$rootScope.loged = true;
					$rootScope.dropboxWarning = true;
					$rootScope.admin = result.admin;
					$rootScope.currentUser = result.user;
					$rootScope.apply; // jshint ignore:line

				}
			} else {
				var lien = window.location.href;
				var verif = false;
				if ((lien.indexOf('http://dl.dropboxusercontent.com') > -1)) {
					verif = true;
				}
				if ($location.path() !== '/' && verif !== true) {
					$location.path('/');
				}
			}
		});
	};

	$scope.logoutFonction = function() {
		if (localStorage.getItem('compteId')) {
			localStorage.removeItem('compteId');
			console.log('se deconnecter');
			$rootScope.loged = false;
			$rootScope.dropboxWarning = false;
			$rootScope.admin = null;
			$rootScope.currentUser = {};
			$rootScope.apply; // jshint ignore:line
			$location.path('/#/');
		};
	}
	//displays user profiles
	$scope.afficherProfilsParUser = function() {
		$http.post(configuration.URL_REQUEST + '/profilParUser', {
			id: $scope.currentUserData._id
		})
			.success(function(data) {
				$scope.listeProfilsParUser = data;
				console.log('profil/user ==>');
				console.log(data);
			});

	};

	$scope.changeProfilActuel = function() {
		$scope.profilUser = {
			profilID: JSON.parse($scope.profilActuel)._id,
			userID: $scope.currentUserData._id,
		};
		console.log('$scope.profilUser ====>');
		console.log($scope.profilUser);
		$http.post(configuration.URL_REQUEST + '/ajouterUserProfil', $scope.profilUser)
			.success(function(data) {
				$scope.userProfilFlag = data;
				localStorage.setItem('profilActuel', $scope.profilActuel);

			});

		$http.get(configuration.URL_REQUEST + '/readTags')
			.success(function(data) {
				$scope.listTags = data;
				localStorage.setItem('listTags', JSON.stringify($scope.listTags));
			});

		$http.post(configuration.URL_REQUEST + '/chercherTagsParProfil', {
			idProfil: JSON.parse($scope.profilActuel)._id
		}).success(function(data) {
			$scope.listTagsByProfil = data;
			localStorage.setItem('listTagsByProfil', JSON.stringify($scope.listTagsByProfil));
		});
	};

	$scope.showLastDocument = function() {
		var lastDocument = localStorage.getItem('lastDocument');
		$scope.lastDoc = '';
		if (lastDocument && lastDocument.length > 0) {
			$scope.lastDoc = lastDocument;
			var url = lastDocument.replace('#/apercu', '');
			$scope.lastDocTitre = url.substring(url.lastIndexOf('/') + 1, url.lastIndexOf('.html'));
			return true;
		}
		return false;
	};

});<commit_msg>Corriger le bug des espaces et les accents sont mal interprétés dans le titre du dernier document consulté.<commit_after>/* File: common.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/>.
 *
 */

'use strict';

angular.module('cnedApp').controller('CommonCtrl', function($scope, $rootScope, $location, serviceCheck, gettextCatalog, $http, configuration) {

	$scope.logout = $rootScope.loged;
	$scope.admin = $rootScope.admin;
	$scope.missingDropbox = $rootScope.dropboxWarning;
	$scope.showMenuParam = false;

	$scope.currentUserData = {};
	$rootScope.updateListProfile = false;
	$rootScope.updateProfilListe = false;
	$rootScope.modifProfilListe = false;

	//if ($location.absUrl().indexOf('http://dl.dropboxusercontent.com/') > -1) {
	//$scope.deconnectionLink = window.location.href + 'logout';

	//};
	$scope.languages = [{
		name: 'FRANCAIS',
		shade: 'fr_FR'
	}, {
		name: 'ANGLAIS',
		shade: 'en_US'
	}];
	$scope.langue = $scope.languages[0];

	$scope.workspaceLink = $location.absUrl().substring(0, $location.absUrl().indexOf('#/') + 2) + 'listDocument';
	$scope.profilLink = $location.absUrl().substring(0, $location.absUrl().indexOf('#/') + 2) + 'profiles';
	$scope.userAccountLink = $location.absUrl().substring(0, $location.absUrl().indexOf('#/') + 2) + 'userAccount';
	$scope.adminLink = $location.absUrl().substring(0, $location.absUrl().indexOf('#/') + 2) + 'adminPanel';
	$scope.docUrl = configuration.URL_REQUEST + '/styles/images/docs.png';
	$scope.logoUrl = configuration.URL_REQUEST + '/styles/images/header_logoCned.png';
	$scope.connectLink = $location.absUrl().substring(0, $location.absUrl().indexOf('#/') + 2);
	// detect current location
	$scope.isActive = function(route) {
		return route === $location.path();
	};

	$scope.showMenu = function() {
		$scope.showMenuParam = !$scope.showMenuParam;
	};

	// Changer la langue
	$scope.changerLangue = function() {
		gettextCatalog.currentLanguage = $scope.langue.shade;
		$scope.showMenuParam = false;
	};

	$rootScope.$watch('loged', function() {
		$scope.logout = $rootScope.loged;
		$scope.apply; // jshint ignore:line
	});

	$rootScope.$watch('admin', function() {
		$scope.admin = $rootScope.admin;
		$scope.apply; // jshint ignore:line
	});

	$rootScope.$watch('dropboxWarning', function() {
		$scope.guest = $rootScope.loged;
		$scope.apply; // jshint ignore:line
	});

	$rootScope.$watch('currentUser', function() {
		$scope.currentUserData = $rootScope.currentUser;
		$scope.apply; // jshint ignore:line
		if ($scope.currentUserData) {
			$scope.afficherProfilsParUser();
		}
	});

	$rootScope.$watch('updateListProfile', function() {
		if ($scope.currentUserData) {
			$scope.afficherProfilsParUser();
		}
	});

	$rootScope.$watch('updateProfilListe', function() {
		if ($scope.currentUserData) {
			$scope.afficherProfilsParUser();
		}
	});

	$rootScope.$watch('modifProfilListe', function() {
		if ($scope.currentUserData) {
			$scope.afficherProfilsParUser();
		}
	});

	$rootScope.$watch('listDocumentDropBox', function() {
		if ($rootScope.currentUser) {
			$scope.listDocumentDropBox = $rootScope.listDocumentDropBox + '#/listDocument?key=' + $rootScope.currentUser._id;
			$scope.apply;
		};

	});

	$scope.initCommon = function() {

		// var appCache = window.applicationCache;

		// console.log(appCache);
		//appCache.update(); // Attempt to update the user's cache.
		if ($location.absUrl().indexOf('key=') > -1) {
			var callbackKey = $location.absUrl().substring($location.absUrl().indexOf('key=') + 4, $location.absUrl().length);
			localStorage.setItem('compteId', callbackKey);
		};
		$('#masterContainer').show();
		var tmp = serviceCheck.getData();
		tmp.then(function(result) { // this is only run after $http completes
			if (result.loged) {
				console.log('i am loged');
				if (result.dropboxWarning === false) {
					$rootScope.dropboxWarning = false;
					$scope.missingDropbox = false;
					$rootScope.loged = true;
					$rootScope.admin = result.admin;
					$rootScope.apply; // jshint ignore:line
					if ($location.path() !== '/inscriptionContinue') {
						$location.path('/inscriptionContinue');
					}
				} else {
					$rootScope.loged = true;
					$rootScope.dropboxWarning = true;
					$rootScope.admin = result.admin;
					$rootScope.currentUser = result.user;
					$rootScope.apply; // jshint ignore:line

				}
			} else {
				var lien = window.location.href;
				var verif = false;
				if ((lien.indexOf('http://dl.dropboxusercontent.com') > -1)) {
					verif = true;
				}
				if ($location.path() !== '/' && verif !== true) {
					$location.path('/');
				}
			}
		});
	};

	$scope.logoutFonction = function() {
		if (localStorage.getItem('compteId')) {
			localStorage.removeItem('compteId');
			console.log('se deconnecter');
			$rootScope.loged = false;
			$rootScope.dropboxWarning = false;
			$rootScope.admin = null;
			$rootScope.currentUser = {};
			$rootScope.apply; // jshint ignore:line
			$location.path('/#/');
		};
	}
	//displays user profiles
	$scope.afficherProfilsParUser = function() {
		$http.post(configuration.URL_REQUEST + '/profilParUser', {
			id: $scope.currentUserData._id
		})
			.success(function(data) {
				$scope.listeProfilsParUser = data;
				console.log('profil/user ==>');
				console.log(data);
			});

	};

	$scope.changeProfilActuel = function() {
		$scope.profilUser = {
			profilID: JSON.parse($scope.profilActuel)._id,
			userID: $scope.currentUserData._id,
		};
		console.log('$scope.profilUser ====>');
		console.log($scope.profilUser);
		$http.post(configuration.URL_REQUEST + '/ajouterUserProfil', $scope.profilUser)
			.success(function(data) {
				$scope.userProfilFlag = data;
				localStorage.setItem('profilActuel', $scope.profilActuel);

			});

		$http.get(configuration.URL_REQUEST + '/readTags')
			.success(function(data) {
				$scope.listTags = data;
				localStorage.setItem('listTags', JSON.stringify($scope.listTags));
			});

		$http.post(configuration.URL_REQUEST + '/chercherTagsParProfil', {
			idProfil: JSON.parse($scope.profilActuel)._id
		}).success(function(data) {
			$scope.listTagsByProfil = data;
			localStorage.setItem('listTagsByProfil', JSON.stringify($scope.listTagsByProfil));
		});
	};

	$scope.showLastDocument = function() {
		var lastDocument = localStorage.getItem('lastDocument');
		$scope.lastDoc = '';
		if (lastDocument && lastDocument.length > 0) {
			$scope.lastDoc = lastDocument;
			var url = lastDocument.replace('#/apercu', '');
			$scope.lastDocTitre = decodeURI(url.substring(url.lastIndexOf('/') + 1, url.lastIndexOf('.html')));
			return true;
		}
		return false;
	};

});<|endoftext|>