diff --git a/src/js/main.js b/src/js/main.js index 1ad3c452..765dd0f4 100755 --- a/src/js/main.js +++ b/src/js/main.js @@ -24,6 +24,7 @@ import tinyMCEEditor from './modules/tinyMCEEditor'; import uob from './3party/uob7.js'; import util from './modules/util.js'; import utilRoot from './utilRoot.js'; +import uucheck from './modules/uucheck.js'; jQuery(function($) { //KURSP-469 Support embedding of KPAS LTI tool. In general our design should not load in iframes. @@ -212,6 +213,8 @@ jQuery(function($) { coursesettings.addListUsersButton(); coursesettings.addListGroupsButton(); coursesettings.addListAssignmentsButton(); + uucheck.addUUButton(); + }); routes.addRouteForPath(/\/profile\/settings$/, function() { diff --git a/src/js/modules/fknr.js b/src/js/modules/fknr.js index 3dd20cb2..6a698e94 100644 --- a/src/js/modules/fknr.js +++ b/src/js/modules/fknr.js @@ -1,4 +1,4 @@ -utgaatteKommuneNr = [ +var fknr = { utgaatteKommuneNr : [ 1, 2, 4, @@ -425,4 +425,6 @@ utgaatteKommuneNr = [ 2121, 2131, 2111 -] \ No newline at end of file +]}; + +export default fknr; diff --git a/src/js/modules/menu.js b/src/js/modules/menu.js index 4f54fc94..ba7144c1 100755 --- a/src/js/modules/menu.js +++ b/src/js/modules/menu.js @@ -297,7 +297,7 @@ export default (function() { if(moduleItemSequence && moduleItemSequence.items.length && moduleItemSequence.items[0].next) { var nextItem = moduleItemSequence.items[0].next; if(nextItem.indent) { - id = nextItem.id; + var id = nextItem.id; api.getModuleItemSequence(courseId, id, handleNextModuleItem); } else { var nextButton = $(".module-sequence-footer-button--next"); diff --git a/src/js/modules/util.js b/src/js/modules/util.js index 6361cd25..eed1c7e8 100755 --- a/src/js/modules/util.js +++ b/src/js/modules/util.js @@ -4,6 +4,7 @@ import { hrefAmpQueryString, hrefQueryString } from "../settingsRoot"; import { CourseOptions } from "../utilities/course-options"; import api from '../api/api.js' +import fknr from './fknr.js'; import pages from './pages.js' import settings from "../settings"; @@ -322,6 +323,7 @@ export default (function () { }); }, isMemberOfExpiredCommunity(course, callback) { + let self = this if(!course) { return; } @@ -330,9 +332,9 @@ export default (function () { if (groups.length) { for (var i = 0; i < groups.length; i++) { var group = groups[i]; - var countyOrCommunityNumber = getCountyOrCommunityNumber(group.description); + var countyOrCommunityNumber = self.getCountyOrCommunityNumber(group.description); if (countyOrCommunityNumber) { - if (utgaatteKommuneNr.indexOf(countyOrCommunityNumber) > -1) { + if (fknr.utgaatteKommuneNr.indexOf(countyOrCommunityNumber) > -1) { memberOfUtgaattKommune = true; break; } diff --git a/src/js/modules/uucheck.js b/src/js/modules/uucheck.js new file mode 100644 index 00000000..078217e5 --- /dev/null +++ b/src/js/modules/uucheck.js @@ -0,0 +1,210 @@ +export default (function () { + class Translated { + constructor (words, defaultlang='nb'){ + this.words = words; + this.defaultlang = defaultlang; + } + toString(){ + return this.words[ENV.LOCALE]?this.words[ENV.LOCALE]:this.words[this.defaultlang]; + } + use(...values){ + let returnstring = this.words[ENV.LOCALE]?this.words[ENV.LOCALE]:this.words[this.defaultlang]; + for (let i=0; i item.trim().startsWith('_csrf_token')).replace(/\s*_csrf_token\s*\=\s*(.*)$/,"$1")); + if (typeof(querydata)=="string") querydata = {'query': querydata}; + //create the graphql query using the querydata input + return fetch(location.origin+"/api/graphql",{ + method: 'POST', + mode: 'cors', + credentials: 'same-origin', + headers: { + 'Accept': 'application/json+canvas-string-ids, application/json, text/plain, */*', + 'Content-Type': 'application/json', + 'x-csrf-token': csrf_token + }, + body: JSON.stringify(querydata) + }) + + } + function Get (last_part_of_url){ + //Does a Canvas API call and returns a JS-object. + return fetch(location.origin+'/api/v1/'+last_part_of_url); + } + + + let error = new Translated({en: 'Error', nb: 'Feil', nn: 'Feil'}) + let warning = new Translated({en: 'Warning', nb: 'Advarsel', nn: 'Åtvaring'}) + let imgerror = new Translated({en: "must be marked as decorative or get an alt text which isn't the filename.", nb:'må markeres som dekorativt eller få alternativ tekst som ikke er filnavnet.', nn:'må markerast som dekorativt eller få alternativ tekst som ikkje er filnamnet.'}) + let imgwarning = new Translated({en: "An image is marked as decorative in the old Canvas unstandared way. Open the Image Options and choose Done to rectify.", nb: "Et bilde er merket som dekorativt på den gamle ustandardiserte måten. Åpne Bilde-alternativer og klikk Ferdig for å rette opp.", nn: "Eit bilde er merka som dekorativt på den gamle ustandardiserte måten. Åpne Bilde-alternativ og klikk Ferdig for å retta opp."}) + let tablecaptionerror = new Translated({en: 'Table is missing caption.', nb:'Tabell mangler overskrift.', nn:'Tabell manglar overskrift.'}) + let tableheadererror = new Translated({en: 'Table is missing headers for rows and/or columns.', nb:'Tabell mangler titler på rader og/eller kolonner.', nn:'Tabell manglar titlar på rader og/eller kolonnar.'}) + let herror = new Translated({en: 'Error in the heading hierarchy.', nb:'Feil i overskriftshierarkiet.', nn:'Feil i overskriftshierarkiet.'}) + let stylewarning = new Translated({en:'Uses style - check if it is used to make a headline, destroys contrast or leads to other problems.', nb:'Bruker style - sjekk om det brukes for å lage overskrift, ødelegger kontrast eller fører til andre problemer.', nn:'Brukar style - sjekk om det blir brukt for å laga overskrift, øydelegg kontrast eller fører til andre problem.'}) + let summary = new Translated({en:'[0] errors, [1] warnings. Remember that this test does not check files, and only does a limited check of pages.', nb:'

[0] feil, [1] advarsler. Husk at denne testen ikke sjekker filer, og bare gjør en begrenset sjekk av sider.

', nn:'[0] feil, [1] Åtvaringar. Hugs at denne testen ikkje sjekkar filer, og berre gjer ein avgrensa sjekk av sider.'}) + let nothing = new Translated({en: "Can't find anything to check.", nb:'Finner ingenting å sjekke.', nn: 'Finn ikkje noko å sjekka.'}) + let buttonname = new Translated({en: 'Mini accessibility check', nb:'Mini UU-sjekk', nn:'Mini UU-sjekk'}) + let assignment = new Translated({en: 'Assignment', nb: 'Oppgave', nn: 'Oppgåve'}) + let discussion = new Translated({en: 'Discussion', nb: 'Diskusjon', nn: 'Diskusjon'}) + let title = new Translated({en:'Mini accessibility check of', nb:'Mini-UUsjekk av', nn:'Mini-UUsjekk av'}) + let moduleword = new Translated({en:'Module', nb:'Modul', nn:'Modul'}) + let frontpage = new Translated({en:'Front page', nb:'Framside', nn:'Framside'}) + + + + + let content + let myReport = document.getElementById('content') + let warningimg = `${warning}` + let warningcount = 0 + let errorimage = `${error}` + let errorcount = 0 + + function addToReport (htmlstring){ + let div=document.createElement('div') + div.innerHTML = htmlstring + myReport.append(div) + } + + function HTMLcheck(html){ + let div = document.createElement('div') + div.innerHTML = html + let HTMLoutput = '' + //imagecheck + let imgtags = div.querySelectorAll('img') + for (const img of imgtags){ + if (img.getAttribute('role') == 'presentation') continue + if (img.getAttribute('data-decorative')){ + HTMLoutput += `

${warningimg} ${img.alt} ${imgwarning}

` + warningcount++ + continue + } + if (!['.jpg','.jpeg','.gif','.png','.svg'].includes(img.alt.substring(img.alt.lastIndexOf('.')))) continue + HTMLoutput += `

${errorimage} ${img.alt} ${imgerror}

` + errorcount++ + } + let tables = div.querySelectorAll('table') + for (const table of tables){ + if (!table.querySelector('caption')){ + HTMLoutput += `

${errorimage} ${tablecaptionerror}

` + errorcount++ + } + if (!table.querySelector('th')){ + HTMLoutput += `

${errorimage} ${tableheadererror}

` + errorcount++ + } + } + let headers = div.querySelectorAll("h2, h3, h4, h5, h6"); + let startlevel = 1; + for (const header of headers){ + let newlevel = Number(header.tagName.substring(1)) + if (newlevel > startlevel+1){ + HTMLoutput += `

${errorimage} ${herror}

` + errorcount++ + break + } + startlevel = newlevel + } + if (html.includes('style=')){ + HTMLoutput += `

${warningimg} ${stylewarning}

` + warningcount++ + } + + return HTMLoutput + } + + function assignmentcheck(item){ + let log = HTMLcheck(item.description) + if (log) + addToReport(`

${assignment} ${item.name}

${log}`) + } + function discussioncheck(item){ + let log = HTMLcheck(item.message) + if (log) + addToReport(`

${discussion} ${item.title}

${log}`) + } + function pagecheck(item){ + if (!item._id) item._id = item.page_id + if (!item.body) + item = Get(`courses/${ENV.COURSE_ID}/pages/${item._id}`) + if (!item.body) return + console.log(item.body) + let log = HTMLcheck(item.body) + if (log){ + addToReport(`

${item.title}

${log}`) + } + } + function UUsjekk(){ + myReport.innerHTML = '' + addToReport(`

${title} ${content.data.course.name}

`) + let modules = content.data.course.modulesConnection.nodes + if (modules.length){ + //Course with modules + Get(`courses/${ENV.COURSE_ID}`) + .then( coursedata => { + if (coursedata.default_view == 'wiki'){ + //has front page which might not show up in modules + let pages = Get(`/courses/${ENV.COURSE_ID}/pages?per_page=100`) + for (const page of pages){ + if (page.front_page){ + addToReport(`

${frontpage}:

`) + console.log ("frontpage") + pagecheck(page) + break + } + } + } + for (const module of modules){ + addToReport(`

${moduleword} ${module.name}

`) + for (const item of module.moduleItems){ + if (!item.content._id) continue + if (item.content.description) { assignmentcheck(item.content); continue} + if (item.content.message) { discussioncheck(item.content); continue} + pagecheck(item.content) + } + } + }) + addToReport(summary.use(errorcount,warningcount)) + }else{ + //Course without modules + console.log('kurs uten moduler') + Get(`/courses/${ENV.COURSE_ID}/pages?per_page=100`) + .then(pages => { + console.log (pages.length) + if (pages.length){ + for (const page of pages){ + pagecheck(page) + } + addToReport(summary.use(errorcount,warningcount)) + }else{ + addToReport(`

${nothing}

`) + } + }) + } + + + } + return { + addUUButton: function (){ + graphql(`query MyQuery {course(id: "${ENV.COURSE_ID}") {name modulesConnection {nodes {name moduleItems {content {... on Page {_id} ... on Assignment {_id name description state} ... on Discussion {_id message title}}}}}}}`) + .then(res => res.json()) + .then(res => { + let a = document.createElement('a'); + document.querySelector("#right-side table.summary").before(a); + a.outerHTML = ` ${buttonname}`; + content = res + document.getElementById('miniuusjekk').onclick = UUsjekk + + } + ) + } + } +})();