diff --git a/src/js/app/challenge-details/app.js b/src/js/app/challenge-details/app.js index 9ddc8fea..086f4bf0 100644 --- a/src/js/app/challenge-details/app.js +++ b/src/js/app/challenge-details/app.js @@ -48,6 +48,9 @@ ]); $locationProvider.html5Mode(true); }]) + .config(function($compileProvider) { + $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|file|javascript):/); + }) .config(DataPreProcessing); DataPreProcessing.$inject = ['$httpProvider', 'RestangularProvider', 'API_URL']; diff --git a/src/js/app/challenge-details/index.html b/src/js/app/challenge-details/index.html index f0c4796f..53f359a9 100644 --- a/src/js/app/challenge-details/index.html +++ b/src/js/app/challenge-details/index.html @@ -12,29 +12,10 @@
-
- - 1 - View Scorecard - - - 2 - Complete Appeals - -
-
- - 1 - - Register For This Challenge - - - Unregister From This Challenge - - - - 2Submit Your Entries +
+ + {{$index + 1}} + {{button.text}}
diff --git a/src/js/app/challenge-details/js/controllers/challenge-details-controller.js b/src/js/app/challenge-details/js/controllers/challenge-details-controller.js index c9caa2b3..c8db2c08 100644 --- a/src/js/app/challenge-details/js/controllers/challenge-details-controller.js +++ b/src/js/app/challenge-details/js/controllers/challenge-details-controller.js @@ -6,7 +6,7 @@ * Changed in 1.1 (topcoder new community site - Removal proxied API calls) * Removed LC related conditionals and calls */ - /* +/* * TODO: * - Bring up to style guide standards * - lots of different stuff under this heading: @@ -89,6 +89,7 @@ vm.challengeApiParams = { filter: 'id=' + challengeId } + vm.buttons = []; $interval(function () { if (vm.challenge && vm.challenge.currentPhaseRemainingTime) { @@ -117,35 +118,33 @@ updateTabForNonResults(); }; - $rootScope.$on('$locationChangeStart', function(event, toUrl, fromUrl) { - var parser = document.createElement('a'); - parser.href = toUrl; - if (!parser.pathname.startsWith("/challenge-details/")) - window.location.reload(); + $rootScope.$on('$locationChangeStart', function (event, toUrl, fromUrl) { + var parser = document.createElement('a'); + parser.href = toUrl; + if (!parser.pathname.startsWith("/challenge-details/")) + window.location.reload(); }); var handlePromise = $q.defer(); //The handle is needed to enable the buttons app - .getHandle(function (handle) { - handlePromise.resolve(handle); - } - ); + .getHandle(function (handle) { + handlePromise.resolve(handle); + }); handlePromise - .promise - .then(function (handle) { - vm.handle = handle; - initChallengeDetail(handle, vm, ChallengeService); - } - ); + .promise + .then(function (handle) { + vm.handle = handle; + initChallengeDetail(handle, vm, ChallengeService); + }); /** * * @param checkRole * @returns {true|false} */ function checkRole(checkRole) { - return _.some(vm.userRole, function(role) { + return _.some(vm.userRole, function (role) { return role === checkRole; }) } @@ -180,39 +179,39 @@ * @param ChallengeService */ function initChallengeDetail(handle, vm, ChallengeService) { - ChallengeService.getChallengeTerms(challengeId).then(function(termsList) { + ChallengeService.getChallengeTerms(challengeId).then(function (termsList) { vm.termsList = termsList; }); ChallengeService - .getUserChallenges(vm.handle, vm.challengeApiParams) - .then(function (challenge) { - if (challenge[0] && challenge[0].result.content.length) { - challenge = challenge[0].result.content[0]; - vm.userRole = challenge.userDetails ? challenge.userDetails.roles : []; - } else { - vm.userRole = []; - } - //Set to test value if defined - vm.userRole = vm.mockUserRole ? vm.mockUserRole : vm.userRole; - }); + .getUserChallenges(vm.handle, vm.challengeApiParams) + .then(function (challenge) { + if (challenge[0] && challenge[0].result.content.length) { + challenge = challenge[0].result.content[0]; + vm.userRole = challenge.userDetails ? challenge.userDetails.roles : []; + } else { + vm.userRole = []; + } + //Set to test value if defined + vm.userRole = vm.mockUserRole ? vm.mockUserRole : vm.userRole; + }); ChallengeService - .getChallenge(challengeId) - .then(function (challenge) { - processChallenge(challenge, handle, vm, ChallengeService); - vm.callComplete = true; - $timeout(function () { - window.prerenderReady = true; - }, 100); - $('#cdNgMain').show(); - }); + .getChallenge(challengeId) + .then(function (challenge) { + processChallenge(challenge, handle, vm, ChallengeService); + vm.callComplete = true; + $timeout(function () { + window.prerenderReady = true; + }, 100); + $('#cdNgMain').show(); + }); } function updateChallengeDetail() { ChallengeService - .getChallenge(challengeId) - .then(function (challenge) { - processChallenge(challenge, vm.handle, vm, ChallengeService); - }); + .getChallenge(challengeId) + .then(function (challenge) { + processChallenge(challenge, vm.handle, vm, ChallengeService); + }); } /** @@ -222,8 +221,8 @@ if (app.isLoggedIn()) { ChallengeService - .registerToChallenge(challengeId) - .then( + .registerToChallenge(challengeId) + .then( function (data) { if (data["message"] === "ok") { showModal("#registerSuccess"); @@ -234,14 +233,15 @@ } updateChallengeDetail(); } - }, function (reason) { + }, + function (reason) { if (reason["error"]["details"] === "You should agree with all terms of use.") { window.location = "/challenge-details/terms/" + vm.challenge.challengeId + "?challenge-type=" + challengeType; } else if (reason["error"]["details"]) { showError(reason["error"]["details"]); } } - ); + ); } else { //set register Delay cookie for auto register when user returns to page //angularjs $cookies is too basic and does not support setting any cookie options such as expires, so must use jQuery method here @@ -261,8 +261,8 @@ function unregisterFromChallenge() { if (app.isLoggedIn()) { ChallengeService - .unregisterFromChallenge(challengeId) - .then( + .unregisterFromChallenge(challengeId) + .then( function (data) { if (data["message"] === "ok") { showModal("#unregisterSuccess"); @@ -270,12 +270,13 @@ document.cookie = 'tcDelayChallengeAction=; path=/; domain=.' + tcconfig.domain + '; expires=' + new Date(0).toUTCString(); updateChallengeDetail(); } - }, function (reason) { + }, + function (reason) { if (reason["error"]["details"]) { showError(reason["error"]["details"]); } } - ); + ); } } @@ -298,31 +299,29 @@ * @param ChallengeService */ function processChallenge(challenge, handle, vm, ChallengeService) { - // Global variable available from ng-page-challenge-details.php challengeName = challenge.challengeName; var reviewScorecardId = challenge.reviewScorecardId; vm.isDesign = (challengeType === 'design'); vm.allowDownloads = challenge.currentStatus === 'Active'; - if ((challenge.currentPhaseName != 'Stalled' && challenge.checkpointSubmissionEndDate && challenge.checkpointSubmissionEndDate != '') || (challenge.checkpoints && challenge.checkpoints.length > 0)) { ChallengeService .getCheckpointData(challengeId) - .then(function(data) { - if (data && !data.error) { - vm.checkpointData = data; - vm.checkpointResults = data.checkpointResults; - //set variables for design challenge checkpoint results - if (vm.isDesign) { - vm.numCheckpointSubmissions = data.numberOfPassedScreeningSubmissions; - vm.numberOfPassedScreeningSubmissions = data.numberOfPassedScreeningSubmissions; - vm.numberOfPassedScreeningUniqueSubmitters = data.numberOfPassedScreeningUniqueSubmitters; - vm.numberOfUniqueSubmitters = data.numberOfUniqueSubmitters; - vm.checkpointPassedScreeningSubmitterPercentage = Math.floor((vm.numberOfPassedScreeningUniqueSubmitters / vm.numberOfUniqueSubmitters) * 100); - vm.checkpointPassedScreeningSubmissionPercentage = Math.floor((vm.numberOfPassedScreeningSubmissions / vm.numCheckpointSubmissions) * 100); + .then(function (data) { + if (data && !data.error) { + vm.checkpointData = data; + vm.checkpointResults = data.checkpointResults; + //set variables for design challenge checkpoint results + if (vm.isDesign) { + vm.numCheckpointSubmissions = data.numberOfPassedScreeningSubmissions; + vm.numberOfPassedScreeningSubmissions = data.numberOfPassedScreeningSubmissions; + vm.numberOfPassedScreeningUniqueSubmitters = data.numberOfPassedScreeningUniqueSubmitters; + vm.numberOfUniqueSubmitters = data.numberOfUniqueSubmitters; + vm.checkpointPassedScreeningSubmitterPercentage = Math.floor((vm.numberOfPassedScreeningUniqueSubmitters / vm.numberOfUniqueSubmitters) * 100); + vm.checkpointPassedScreeningSubmissionPercentage = Math.floor((vm.numberOfPassedScreeningSubmissions / vm.numCheckpointSubmissions) * 100); + } } - } - }); + }); } //Bugfix refactored-challenge-details-40: format currency values with comma delimiters @@ -336,30 +335,34 @@ vm.scope.challenge = vm.challenge = challenge; - var regList = challenge.registrants.map(function(x) { return x.handle; }); - var submitters = challenge.registrants.map(function(x) { + var regList = challenge.registrants.map(function (x) { + return x.handle; + }); + var submitters = challenge.registrants.map(function (x) { if (x.submissionDate.length > 0) { return x.handle; } }); - var provisionalNumFinalSubmitters = challenge.registrants.filter(function(x) { + var provisionalNumFinalSubmitters = challenge.registrants.filter(function (x) { return x.submissionDate.length > 0; }).length; - var submissionMap = challenge.submissions.map(function(x) { return x.handle; }); + var submissionMap = challenge.submissions.map(function (x) { + return x.handle; + }); // these are the buttons for registration, and submission vm.challenge.registrationDisabled = true; - vm.challenge.submissionDisabled = true; + vm.challenge.submissionDisabled = true; // true when to unregister is the valid option - vm.challenge.allowToUnregister = false; + vm.challenge.allowToUnregister = false; // button for peer review for challenges with reviewType === PEER - vm.challenge.peerReviewDisabled = true; + vm.challenge.peerReviewDisabled = true; vm.challenge.url = window.location.href; vm.isRegistered = regList.indexOf(handle) >= 0; - var hasSubmitted = submitters.indexOf(handle) >= 0; + var hasSubmitted = vm.hasSubmitted = submitters.indexOf(handle) >= 0; // If the challenge is active and in the registration phase we allow either // registration, or unregistration. @@ -397,12 +400,12 @@ } var currentDate = new Date(); - if(challenge.challengeCommunity == 'design' && challenge.checkpointSubmissionEndDate && vm.isLoggedIn && regList.indexOf(handle) > -1 && new Date(challenge.currentPhaseEndDate) > new Date(challenge.checkpointSubmissionEndDate)){ + if (challenge.challengeCommunity == 'design' && challenge.checkpointSubmissionEndDate && vm.isLoggedIn && regList.indexOf(handle) > -1 && new Date(challenge.currentPhaseEndDate) > new Date(challenge.checkpointSubmissionEndDate)) { //checkpoint phase - if(currentDate.getTime() < new Date(challenge.checkpointSubmissionEndDate)) { + if (currentDate.getTime() < new Date(challenge.checkpointSubmissionEndDate)) { challenge.currentPhaseEndDate = challenge.checkpointSubmissionEndDate; challenge.currentPhaseName = 'Checkpoint'; - } else if( currentDate.getTime() < new Date(challenge.submissionEndDate)){ //past checkpoint - submission phase + } else if (currentDate.getTime() < new Date(challenge.submissionEndDate)) { //past checkpoint - submission phase challenge.currentPhaseEndDate = challenge.submissionEndDate; challenge.currentPhaseName = 'Submission'; } @@ -410,21 +413,20 @@ if (challenge.currentPhaseEndDate) { var endPhaseDate = new Date(challenge.currentPhaseEndDate); - vm.challenge.currentPhaseRemainingTime = Math.max((endPhaseDate.getTime()-currentDate.getTime())/1000, 0) || -1; - } - else vm.challenge.currentPhaseRemainingTime = -1; + vm.challenge.currentPhaseRemainingTime = Math.max((endPhaseDate.getTime() - currentDate.getTime()) / 1000, 0) || -1; + } else vm.challenge.currentPhaseRemainingTime = -1; - vm.challenge.registrants.map(function(x) { + vm.challenge.registrants.map(function (x) { if (submissionMap[x.handle]) x.submissionStatus = submissionMap[x.handle].submissionStatus; }); vm.reliabilityBonus = challenge.reliabilityBonus; - vm.inSubmission = challenge.currentPhaseName.indexOf('Submission') >= 0; - vm.inScreening = challenge.currentPhaseName.indexOf('Screening') >= 0; - vm.inReview = challenge.currentPhaseName.indexOf('Review') >= 0; - vm.hasFiletypes = ((typeof challenge.filetypes) !== 'undefined') && challenge.filetypes.length > 0; - vm.numRegistrants = challenge.numberOfRegistrants; - vm.numSubmissions = challenge.numberOfSubmissions; + vm.inSubmission = challenge.currentPhaseName.indexOf('Submission') >= 0; + vm.inScreening = challenge.currentPhaseName.indexOf('Screening') >= 0; + vm.inReview = challenge.currentPhaseName.indexOf('Review') >= 0; + vm.hasFiletypes = ((typeof challenge.filetypes) !== 'undefined') && challenge.filetypes.length > 0; + vm.numRegistrants = challenge.numberOfRegistrants; + vm.numSubmissions = challenge.numberOfSubmissions; vm.numCheckpointSubmissions = challenge.numberOfCheckpointSubmissions; vm.isPeerReviewed = vm.challenge.reviewType === 'PEER'; @@ -440,14 +442,14 @@ } else { vm.reviewStyle = 'Community Review Board'; vm.reviewStyleTooltip = 'Community Review Board performs a thorough review based on scorecards.'; - vm.reviewScorecardLink = '//software.' + vm.domain +'/review/actions/ViewScorecard.do?method=viewScorecard&scid=' + reviewScorecardId; + vm.reviewScorecardLink = '//software.' + vm.domain + '/review/actions/ViewScorecard.do?method=viewScorecard&scid=' + reviewScorecardId; } vm.hasCheckpoints = vm.numCheckpointSubmissions > 0; if (vm.numSubmissions == 0 && !vm.hasCheckpoints && provisionalNumFinalSubmitters > 0) { vm.numSubmissions = provisionalNumFinalSubmitters; } - vm.submissionNumberString = function() { + vm.submissionNumberString = function () { if (vm.results || !vm.hasCheckpoints) return '(' + vm.numSubmissions + ')'; return ''; } @@ -457,7 +459,7 @@ if (challenge.currentStatus != 'Draft' && (challenge.currentPhaseName != 'Stalled' || challenge.currentStatus == 'Completed') && (challenge.currentStatus == 'Completed' || challenge.currentPhaseEndDate == '')) { ChallengeService .getResults(challengeId) - .then(function(results) { + .then(function (results) { vm.results = results; vm.firstPlaceSubmission = results.firstPlaceSubmission; vm.secondPlaceSubmission = results.secondPlaceSubmission; @@ -465,7 +467,7 @@ //set variables for design challenge results if (vm.isDesign) { //filter all submitters that passed screening - var passedScreen = results.results.filter(function(element){ + var passedScreen = results.results.filter(function (element) { if (element.submissionStatus !== "Failed Screening") { return true; } @@ -473,21 +475,21 @@ }); //push all passing submitter handles to new array var resultPassingHandles = []; - passedScreen.forEach(function(el){ + passedScreen.forEach(function (el) { resultPassingHandles.push(el.handle); }); //get number of unique final submitters that have passed screening - vm.finalSubmittersPassedScreening = resultPassingHandles.filter(function(element, elIndex, arr){ + vm.finalSubmittersPassedScreening = resultPassingHandles.filter(function (element, elIndex, arr) { return arr.indexOf(element) == elIndex; }).length; //push all submitter handles to new array var resultHandles = []; - results.results.forEach(function(el){ + results.results.forEach(function (el) { resultHandles.push(el.handle); }); //get number of unique final submitters regardless of screening status - vm.numFinalSubmitters = resultHandles.filter(function(element, elIndex, arr){ + vm.numFinalSubmitters = resultHandles.filter(function (element, elIndex, arr) { return arr.indexOf(element) == elIndex; }).length; @@ -498,7 +500,7 @@ } vm.initialScoreSum = 0; vm.finalScoreSum = 0; - vm.submissions.map(function(x) { + vm.submissions.map(function (x) { vm.initialScoreSum += x.initialScore; vm.finalScoreSum += x.finalScore; }); @@ -511,25 +513,84 @@ winnerMap[vm.submissions[i].handle] = true; } } - vm.challenge.registrants.map(function(x) { + vm.challenge.registrants.map(function (x) { if (winnerMap[x.handle]) x.winner = true; }); if (vm.winningSubmissions.length == 0) vm.firstPlaceSubmission = false; if (vm.winningSubmissions.length < 2) vm.secondPlaceSubmission = false; - if(challenge.reviewType === "PEER") { - ChallengeService.getPeerReviewResults(challengeId).then(function(data) { + if (challenge.reviewType === "PEER") { + ChallengeService.getPeerReviewResults(challengeId).then(function (data) { vm.peerReviewResults = data; }); } - } - ); + }); } // top section if (vm.challenge.reviewType == 'PEER') { vm.phaseProgram = getPhaseProgramDetail(challenge.currentPhaseName, challenge.currentStatus); } + initButtons(vm); + } + + /** + * Creates a new button for user actions at the Challenge Details page. + * + * @param {String} button.classes Classes to add to the button. + * @param {String} button.href URL to follow when the button is clicked. + * Alternatively, the caller may provide `button.onClick` instead, but not + * both. + * @param {Function} button.onClick Callback to trigger when the button is + * clicked. Alternatively, the caller may provide `button.href` instead, but + * not both. + * @param {String} button.text Button label. + * @return Button object. + */ + function newButton(button) { + if (!button.text || (!button.onClick && !button.href)) { + throw new Error('Invalid arguments in the newButton() method!'); + } + var res = {}; + res.text = button.text || ''; + res.classes = button.classes || ''; + if (button.href) res.href = button.href; + else res.onClick = button.onClick; + return res; + } + + function initButtons(vm) { + vm.buttons = []; + if (vm.challenge.currentPhaseName === 'Appeals' && vm.hasSubmitted) { + vm.buttons.push(newButton({ + text: 'View Scorecard', + href: '//' + vm.reviewAppURL + '/actions/ViewProjectDetails?pid=' + vm.challenge.challengeId, + })); + vm.buttons.push(newButton({ + text: 'Complete Appeals', + href: '//' + vm.reviewAppURL + '/actions/EarlyAppeals?pid=' + vm.challenge.challengeId, + classes: 'unregister' + })); + } else { + if (vm.challenge.allowToUnregister) { + vm.buttons.push(newButton({ + classes: 'challengeRegisterBtn unregister', + onClick: vm.unregisterFromChallenge, + text: 'Unregister From This Challenge' + })); + } else { + vm.buttons.push(newButton({ + classes: 'challengeRegisterBtn ' + (vm.challenge.registrationDisabled ? 'disabled ' : 'disabledNOT'), + onClick: vm.registerToChallenge, + text: 'Register For This Challenge' + })); + } + vm.buttons.push(newButton({ + href: '/challenge-details/' + vm.challenge.challengeId + '/submit/?type=develop', + classes: (vm.challenge.submissionDisabled ? 'disabled ' : 'disabledNOT'), + text: 'Submit Your Entries' + })); + } } /** @@ -592,4 +653,4 @@ } } -})(); +})(); \ No newline at end of file