├── .bowerrc ├── .editorconfig ├── .eslintrc.js ├── .gitattributes ├── .github └── workflows │ └── run-tests.yml ├── .gitignore ├── .nvmrc ├── CODE_OF_CONDUCT.md ├── Gruntfile.js ├── LICENSE ├── README.md ├── app ├── .buildignore ├── dummy.html ├── images │ ├── copy.png │ ├── fail.png │ ├── pass.png │ ├── w3c.svg │ ├── wai.svg │ └── wip.png ├── index.html ├── locale │ ├── EN │ │ ├── audit.json │ │ ├── common.json │ │ ├── download.json │ │ ├── earl.json │ │ ├── error.json │ │ ├── explore.json │ │ ├── html_report.json │ │ ├── import.json │ │ ├── nav.json │ │ ├── open.json │ │ ├── report.json │ │ ├── sample.json │ │ ├── save.json │ │ ├── scope.json │ │ └── start.json │ └── NL │ │ ├── audit.json │ │ ├── common.json │ │ ├── download.json │ │ ├── earl.json │ │ ├── error.json │ │ ├── explore.json │ │ ├── html_report.json │ │ ├── nav.json │ │ ├── open.json │ │ ├── report.json │ │ ├── sample.json │ │ ├── save.json │ │ ├── scope.json │ │ └── start.json ├── scripts │ ├── app.js │ ├── app.language.js │ ├── app.run.js │ ├── controllers │ │ ├── evaluation │ │ │ ├── audit.js │ │ │ ├── audit │ │ │ │ ├── criteria.js │ │ │ │ └── samplePages.js │ │ │ ├── explore.js │ │ │ ├── report.js │ │ │ ├── sample.js │ │ │ └── scope.js │ │ ├── footer.js │ │ ├── import.js │ │ ├── navigation.js │ │ ├── open.js │ │ ├── report │ │ │ ├── findings.js │ │ │ └── score.js │ │ ├── save.js │ │ ├── start.js │ │ ├── stepButtons.js │ │ └── viewReport.js │ ├── directives │ │ ├── autoResize.js │ │ ├── buttonCollapse.js │ │ ├── collapse.js │ │ ├── criterion │ │ │ ├── criterionBody.js │ │ │ ├── earlAssert.js │ │ │ ├── macroResults.js │ │ │ ├── pageResults.js │ │ │ ├── pageSelect.js │ │ │ └── resultDescription.js │ │ ├── dropdownToggle.js │ │ ├── evaluate │ │ │ ├── iconButton.js │ │ │ ├── infoButton.js │ │ │ ├── infoField.js │ │ │ ├── inputPages.js │ │ │ └── techSelect.js │ │ ├── fullReport.js │ │ ├── shyPlaceholder.js │ │ └── successCriterion.js │ ├── filters │ │ ├── getUrl.js │ │ ├── rdfToLabel.js │ │ ├── selectedCasesOnly.js │ │ └── txtToHtml.js │ ├── libs │ │ ├── jsonld.js │ │ └── promise-1.0.0.js │ ├── models │ │ ├── AppState.js │ │ ├── class │ │ │ ├── CriterionAssert.js │ │ │ ├── Page.js │ │ │ └── TestCaseAssert.js │ │ ├── evaluation.js │ │ ├── evaluation │ │ │ ├── audit.js │ │ │ ├── currentUser.js │ │ │ ├── explore.js │ │ │ ├── report.js │ │ │ ├── sample.js │ │ │ └── scope.js │ │ ├── export.js │ │ ├── import.js │ │ ├── import │ │ │ └── importV1.js │ │ └── wcag2spec.js │ ├── services │ │ ├── changeLanguage.js │ │ ├── context │ │ │ ├── evalContextV1.js │ │ │ ├── evalContextV2.js │ │ │ └── evalContextV3.js │ │ ├── directivePlugin.js │ │ ├── evalLoader.js │ │ ├── evalWindow.js │ │ ├── fileReader.js │ │ ├── helpers │ │ │ └── isObjectLiteral.js │ │ ├── knownTechnologies.js │ │ ├── pkgData.js │ │ ├── reportStorage.js │ │ ├── showSave.js │ │ ├── toggleCriterionText.js │ │ ├── types.js │ │ └── wcagSpecIdMap.js │ └── templates.js ├── styles │ ├── animation.scss │ ├── bootstrap-extend.scss │ ├── evaluate.scss │ ├── hint.scss │ ├── main.scss │ ├── report.scss │ └── wizard.scss ├── views │ ├── directives │ │ ├── buttonCollapse.html │ │ ├── criterion │ │ │ ├── criterionBody.html │ │ │ ├── earlAssert.html │ │ │ ├── macroResults.html │ │ │ ├── pageResults.html │ │ │ ├── pageSelect.html │ │ │ └── resultDescription.html │ │ ├── evaluate │ │ │ ├── iconButton.html │ │ │ ├── infoButton.html │ │ │ ├── infoField.html │ │ │ ├── inputPages.html │ │ │ └── techSelect.html │ │ ├── fullReport.html │ │ └── successCriterion.html │ ├── error.html │ ├── evaluation │ │ ├── audit.html │ │ ├── audit │ │ │ ├── criteria-tools.html │ │ │ ├── criteria.html │ │ │ └── samplePages.html │ │ ├── explore.html │ │ ├── report.html │ │ ├── sample.html │ │ ├── scope.html │ │ └── stepbar.html │ ├── footer.html │ ├── import.html │ ├── messages.html │ ├── navigation.html │ ├── open.html │ ├── report │ │ ├── findings.html │ │ ├── sample.html │ │ ├── scope.html │ │ └── score.html │ ├── save.html │ ├── start.html │ ├── step-buttons.html │ └── viewReport.html └── wcag2spec │ ├── wcag2-en.json │ └── wcag2-nl.json ├── bower.json ├── changelog.md ├── docs ├── EARL+JSON-LD.md ├── contribute.md ├── developer-docs.md ├── examples │ ├── example_export_v1.ld.json │ ├── example_export_v2.ld.json │ ├── example_export_v3.ld.json │ └── importable-json │ │ ├── axe-earl-report-example.json │ │ └── example_simple_import.ld.json └── translation.md ├── karma-e2e.conf.js ├── karma.conf.js ├── package-lock.json ├── package.json ├── plugin-guide.md ├── structure redesign ├── stylelint.config.js ├── test ├── .eslintrc.js ├── dummyData │ ├── v1-data.js │ ├── v2-data.js │ └── v3-data.js ├── runner.html ├── setup.js └── spec │ ├── controllers │ └── evaluation │ │ ├── audit │ │ ├── criteria.js │ │ └── samplePages.js │ │ ├── explore.js │ │ ├── report.js │ │ ├── sample.js │ │ └── scope.js │ ├── models │ ├── export.js │ ├── import.js │ └── wcag2spec.js │ ├── services │ └── evalContext.js │ └── v2-data.js └── w3c.json /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "app/bower_components" 3 | } 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | 8 | [*] 9 | 10 | # Change these settings to your own preference 11 | indent_style = space 12 | indent_size = 2 13 | 14 | [*.json] 15 | indent_size = 4 16 | 17 | # We recommend you to keep these unchanged 18 | end_of_line = lf 19 | charset = utf-8 20 | trim_trailing_whitespace = true 21 | insert_final_newline = true 22 | 23 | [*.md] 24 | trim_trailing_whitespace = false 25 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ESlint configuration for WCAG-EM Reporting tool 3 | * --- 4 | * Intended to increase readability of code with rules adding 5 | * whitespace, empty lines and newlines to the code. 6 | * 7 | * @type {Object} 8 | */ 9 | module.exports = { 10 | env: { 11 | browser: true, 12 | es6: true, 13 | jquery: true 14 | }, 15 | extends: 'standard', 16 | globals: { 17 | Atomics: 'readonly', 18 | SharedArrayBuffer: 'readonly', 19 | angular: 'readonly' 20 | }, 21 | parserOptions: { 22 | ecmaVersion: 2018 23 | }, 24 | rules: { 25 | 26 | /* 27 | ** Array notation: 28 | ** [1] or 29 | ** [ 30 | ** 1, 31 | ** 2 32 | ** ] 33 | */ 34 | 'array-bracket-newline': [ 35 | 'error', 36 | { 37 | multiline: true, 38 | minItems: 2 39 | } 40 | ], 41 | 'array-element-newline': [ 42 | 'error', 43 | 'always' 44 | ], 45 | 46 | /** 47 | * Function notation: 48 | * 49 | * fn(a, b) {…} 50 | * 51 | * or 52 | * 53 | * fn( 54 | * a, 55 | * b, 56 | * c 57 | * ) {…} 58 | */ 59 | 'function-paren-newline': [ 60 | 'error', 61 | 'multiline-arguments' 62 | ], 63 | 64 | /** 65 | * Chained call notation like: 66 | * 67 | * object.method(); 68 | * 69 | * or 70 | * 71 | * object 72 | * .method() 73 | * .method(); 74 | */ 75 | 'newline-per-chained-call': [ 76 | 'error', 77 | { 78 | ignoreChainWithDepth: 1 79 | } 80 | ], 81 | 82 | /** 83 | * One statement at a time like: 84 | * 85 | * var a; 86 | * var b; 87 | * 88 | * not 89 | * 90 | * var a; var b; 91 | */ 92 | 'max-statements-per-line': [ 93 | 'error', 94 | { 95 | max: 1 96 | } 97 | ], 98 | 99 | /** 100 | * Semicolon usage always add after statement endings like: 101 | * 102 | * execute(); 103 | */ 104 | semi: [ 105 | 'error', 106 | 'always' 107 | ] 108 | } 109 | }; 110 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto -------------------------------------------------------------------------------- /.github/workflows/run-tests.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | pull_request: {} 5 | push: 6 | branches: [master] 7 | 8 | jobs: 9 | build: 10 | 11 | runs-on: ubuntu-latest 12 | 13 | strategy: 14 | matrix: 15 | node-version: [16.3.0] 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | - name: Build 20 | uses: actions/setup-node@v1 21 | with: 22 | node-version: ${{ matrix.node-version }} 23 | - run: sudo chmod -R a+w /var/lib/gems # makes writable by all 24 | - run: sudo chmod -R a+w /usr/local/bin # makes writable by all 25 | - run: npm ci 26 | - run: npm install -g bower grunt-cli 27 | - run: bower install 28 | - run: npm test 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .tmp 3 | .sass-cache 4 | app/bower_components 5 | app/styles/bootstrap 6 | dist/ 7 | .sublime-project 8 | .sublime-workspace 9 | .dropbox 10 | desktop.ini 11 | Thumbs.db 12 | /.project 13 | npm-debug.log 14 | .DS_Store 15 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | lts/* 2 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | All documentation, code and communication under this repository are covered by the [W3C Code of Ethics and Professional Conduct](https://www.w3.org/Consortium/cepc/). 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The W3C SOFTWARE NOTICE AND LICENSE (W3C) 2 | 3 | https://www.w3.org/Consortium/Legal/copyright-software 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | _Note: this tool is replaced by_ [WCAG-EM Report Tool, version 3.0.0](https://w3.org/WAI/eval/report-tool) (the code lives in the [wai-wcag-em-report-tool](https://github.com/w3c/wai-wcag-em-report-tool/) repository) 2 | 3 | WCAG-EM Report tool is an assistant that takes the user 4 | through the process of evaluating the accessibility of a 5 | website, using the WCAG-EM Evaluation Methodology. The Report 6 | Tool runs entirely on the client and so it can be used offline 7 | and in any server configuration available to you. 8 | 9 | The Report Tool does not save files to a server or in local 10 | storage. Rather, load and save functions are available for 11 | storing an evaluation to your local file system. 12 | 13 | Important references: 14 | 15 | - 16 | - 17 | - 18 | 19 | The official released version of the Report Tool can be found at . An example of the latest (unapproved by EO) version is available at . 20 | 21 | See [Change log](changelog.md) for details about the latest version of the WCAG-EM Report Tool. 22 | 23 | 24 | # Requirements 25 | 26 | Before you can install the WCAG-EM Report Tool you will need 27 | to install a few components: 28 | 29 | - NodeJS https://nodejs.org/en/ (or [NodeJS with Node Version Manager installed](https://github.com/creationix/nvm)) 30 | 31 | Minimum NodeJS version "lts/carbon" (Long term support) 32 | 33 | - Ruby https://www.ruby-lang.org/en/documentation/installation/ 34 | 35 | Latest stable version 36 | 37 | 38 | # Install 39 | 40 | Install the _wcag em report tool_ by running: 41 | 42 | ```bash 43 | # Choose a root folder to install this project then: 44 | 45 | # 1 46 | git clone https://github.com/w3c/wcag-em-report-tool.git 47 | 48 | # 2 49 | cd wcag-em-report-tool 50 | 51 | # (Optional) if node installed with nvm 52 | nvm install 53 | 54 | # 3 55 | npm install 56 | ``` 57 | 58 | This will fetch the project, install all node packages, bower components and compass. See `scripts: install` in `package.json` for detailed installation info. 59 | 60 | 61 | # Usage 62 | You can launch a development version by running: 63 | 64 | npm start 65 | 66 | To create a build in the /dist folder run: 67 | 68 | npm run build 69 | 70 | The build version can be hosted in on any server that available 71 | on http(s). WCAG-EM Report Tool runs in your local browser, so it only loads static files from the server. 72 | 73 | 74 | # Translations 75 | The WCAG-EM Report Tool aims to be available for a wide audience. 76 | Much effort has been put into making translations as easy as 77 | possible. To learn about how to create your own translations 78 | read the [translation documentation](docs/translation.md) 79 | 80 | 81 | # Get Involved 82 | Did you find a bug, or are you interested in working with us to 83 | create new features for the Report Tool, then 84 | [get involved with the project](docs/contribute.md)! 85 | 86 | # Data Format 87 | Data in the WCAG-EM Report Tool is saved and can again be loaded 88 | in a JSON format. The data format is 89 | [JSON Linked Data](http://json-ld.org/), and uses 90 | [EARL](http://www.w3.org/TR/EARL10-Schema/) to store the test 91 | results. 92 | 93 | Custom fields are based on WCAG-EM and are documented in 94 | [EARL+JSON-LD format definition](docs/EARL+JSON-LD.md). 95 | -------------------------------------------------------------------------------- /app/.buildignore: -------------------------------------------------------------------------------- 1 | *.coffee -------------------------------------------------------------------------------- /app/images/copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c/wcag-em-report-tool/7a6dbd2089fcfd76b9b6c49400acc18d9097324e/app/images/copy.png -------------------------------------------------------------------------------- /app/images/fail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c/wcag-em-report-tool/7a6dbd2089fcfd76b9b6c49400acc18d9097324e/app/images/fail.png -------------------------------------------------------------------------------- /app/images/pass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c/wcag-em-report-tool/7a6dbd2089fcfd76b9b6c49400acc18d9097324e/app/images/pass.png -------------------------------------------------------------------------------- /app/images/wip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c/wcag-em-report-tool/7a6dbd2089fcfd76b9b6c49400acc18d9097324e/app/images/wip.png -------------------------------------------------------------------------------- /app/locale/EN/audit.json: -------------------------------------------------------------------------------- 1 | { 2 | "ASSERTION_RESULT_DESCRIPTION_LABEL": "Observations", 3 | "ASSERTION_RESULT_DESCRIPTION_PLACEHOLDER": "Observations made during evaluation", 4 | "BTN_COLLAPSE_PAGES": "Hide web pages to enter individual results", 5 | "BTN_COMPLETE_SELECTED": "Set selected to complete", 6 | "BTN_EXPAND_PAGES": "Show web pages to enter individual results", 7 | "BTN_OPEN_SELECTED": "Open selected pages", 8 | "BTN_SHOW_TEXT": "Show criterion text", 9 | "BTN_UNCOMPLETE_SELECTED": "Set selected to incomplete", 10 | "CLICK_TO_DELETE": "Click to delete", 11 | "FILTER_LEVEL_LEGEND": "Show conformance level", 12 | "FILTER_NEW_IN_WCAG21": "Added in WCAG 2.1", 13 | "FILTER_VERSION_LEGEND": "Show version", 14 | "FILTER": "Show", 15 | "HD_CRITERIA": "Success Criteria to Evaluate", 16 | "HD_SAMPLE_SELECT": "Sample to Evaluate", 17 | "HOW_TO": "How to meet", 18 | "INF_AUDIT_CRITERIA": "This section lists the WCAG 2 success criteria. Use the filter to show or hide success criteria of different levels (A, AA and AAA). You can select results as: 'Not checked', 'Passed', 'Failed', 'Not present', and 'Cannot tell'; and you can provide details, comments, or other observations made during evaluation in the accompanying text box.", 19 | "INF_AUDIT_SAMPLE": "This section lists the web pages you selected in the previous step. The web pages that are checked in this section are listed when 'Show web pages to enter individual results' is activated in the 'Success Criteria to Evaluate' section. You can show an individual web page that you are evaluating, or show several web pages at the same time.
The chainlink icon opens the web page in a separate browser window.", 20 | "INTRO": "Record the outcome from evaluating the web pages selected in the previous step. Compare the results between the structured page and randomly selected pages, and if needed, adjust the selected sample in the previous step. More guidance on this step is provided in WCAG-EM Step 4: Audit the Selected Sample.
Note: For each WCAG 2 success criteria, you can enter 'Results for the entire sample' and you can enter results for individual web pages. You can choose to enter either or both. To enter individual results, select the web page(s) under 'Sample to Evaluate' (in the left column); then under the specific success criteria, select 'Show web pages to enter individual results'", 21 | "LABEL_OUTCOME": "Outcome", 22 | "LABEL_PAGE_HANDLE": "Short page name", 23 | "NO_PAGE_SELECTED": "No pages selected under Sample to Evaluate", 24 | "NO_SAMPLE": "No sample available. Create a sample in step 2 and step 3.", 25 | "NOTE": "Note", 26 | "PRINCIPLE": "Principle", 27 | "RESULTS_FOR": "Results for", 28 | "SAMPLE_FINDINGS": "Results for the entire sample", 29 | "SELECT_ALL": "Select all web pages", 30 | "TESTED": "Tested", 31 | "TITLE": "Step 4: Audit the Selected Sample", 32 | "UNDERSTAND": "Understanding", 33 | "UNTESTED": "{{critCount}} untested" 34 | } 35 | -------------------------------------------------------------------------------- /app/locale/EN/common.json: -------------------------------------------------------------------------------- 1 | { 2 | "BROWSER_NOT_SUPPORTED": "The web browser you are using does not support some functionality, such as saving and loading reports. You can continue to use the Report Tool with limited functionality. Update or use a different web browser to make use of all functionality of this report tool.", 3 | "WARNING_BEFORE_UNLOAD": "The data you entered is not automatically saved. It will be lost if you close this web browser window. Use the 'Save' link (Ctrl + S or ⌘ S) that is at the top of all pages to save your data in a file locally on your computer, and reload it later to continue working on it.", 4 | "MORE_INFO": "For more information, see {{name}}.", 5 | "HIDE_MESSAGE": "Hide message", 6 | "BTN_INFO": "Info expand", 7 | "BTN_CLOSE_INFO": "Close info", 8 | "YES": "Yes", 9 | "NO": "No", 10 | "CLICK_EXPAND": "Click to show section", 11 | "CLICK_COLLAPSE": "Click to hide section", 12 | "TO_TOP": "Back to top", 13 | "ACTIVE": "Active" 14 | } -------------------------------------------------------------------------------- /app/locale/EN/download.json: -------------------------------------------------------------------------------- 1 | { 2 | "TITLE": "Website Accessibility Evaluation Report", 3 | "INTRO": "Below is the evaluation report based on the input that you provided in previous steps. You can go back to previous steps now and change any of this information. You can download the evaluation data so that you can work on it later. (This is the same as the 'Save' functionality.)
This report is intended to be downloaded. You can download the Evaluation Report HTML and CSS files below. You can then change the report content and visual design to meet your needs.", 4 | "DOWNLOAD_REPORT": "Download and customize this report", 5 | "BTN_SAVE_HTML": "Download the evaluation report (HTML)", 6 | "BTN_SAVE_CSS": "Download the report stylesheet (CSS)", 7 | "BTN_SAVE_JSON": "Save the evaluation data (JSON)" 8 | } -------------------------------------------------------------------------------- /app/locale/EN/earl.json: -------------------------------------------------------------------------------- 1 | { 2 | "PASSED": "Passed", 3 | "FAILED": "Failed", 4 | "CANT_TELL": "Cannot tell", 5 | "NOT_PRESENT": "Not present", 6 | "NOT_CHECKED": "Not checked", 7 | "LEVEL_A": "Level A", 8 | "LEVEL_AA": "Level AA", 9 | "LEVEL_AAA": "Level AAA" 10 | } -------------------------------------------------------------------------------- /app/locale/EN/error.json: -------------------------------------------------------------------------------- 1 | { 2 | "TITLE": "Oops! Something went wrong", 3 | "INTRO": "This is not the page you are looking for. Try one of these solutions to solve the problem.", 4 | "SUGGESTION1": "If you typed the URL, make sure it is exactly what it should be.", 5 | "SUGGESTION2": "Go back to the previous page and try again.", 6 | "SUGGESTION3": "Make sure the files you are working from follow the wcag-em format.", 7 | "BUG_REPORT": "To report any bugs or feature suggestions, leave an issue on our Github project page." 8 | } -------------------------------------------------------------------------------- /app/locale/EN/explore.json: -------------------------------------------------------------------------------- 1 | { 2 | "TITLE": "Step 2: Explore the Target Website", 3 | "INTRO": "Explore the website to understand its purpose, functionality, and use. This step helps you determine which web pages to use for the evaluation in the next steps. Identify the web technologies used to provide the website and, if you want, take notes on other aspects of the website. Usually it is best to get input from the website owners and developers for this step. More guidance on this step is provided in WCAG-EM Step 2: Explore the Target Website.", 4 | "HD_RELIEDUP_TECH": "Web Technologies Relied Upon", 5 | "INF_RELIEDUP_TECH": "Identify the web technologies relied upon according to WCAG 2 to provide the website. For more information, see WCAG-EM Step 2.d: Identify Web Technologies Relied Upon.
Note: To add other technologies, select 'Others' and use the 'Web Technology' and 'Specification Address (URL)' field. The 'Specification Address (URL)' field should identify the web technology specification.", 6 | "LABEL_TECH": "Web Technology", 7 | "LABEL_TECH_SPEC": "Specification Address (URL)", 8 | "PLH_TECH": "E.g. HTML5, CSS, DOM", 9 | "PLH_TECH_SPEC": "Address (URL) or description for the web technology specification", 10 | "BTN_REMOVE_TECH": "Remove technology", 11 | "BTN_ADD_TECH": "Add web technology", 12 | "HD_NOTE_TAKING": "Optional Exploration Notes", 13 | "INF_NOTE_TAKING": "This section lets you record information during your website exploration. These notes are provided in the next step, to help you select a sample of web pages for evaluation. These notes are not included in the final report. They are saved when you save the file, and available when you later reload the file", 14 | "LABEL_ESSENT_FUNC": "Essential functionality of the website", 15 | "INF_ESSENT_FUNC": "You can use this field to take notes about essential functionality of the website. Examples of essential functionality include:
'selecting and purchasing a product from the shop area of the website'
'completing and submitting a form provided on the website'
'registering for an account on the website'
For more information, see WCAG-EM Step 2.b: Identify Essential Functionality of the Website.", 16 | "LABEL_VARIETY_PAGE_TYPES": "Variety of web page types", 17 | "INF_VARIETY_PAGE_TYPES": "You can use this field to take notes about the types (as opposed to instances) of web pages that you find on the web site. This includes notes about different styles, layouts, structures, and functionality provided on the website. For more information, see WCAG-EM Step 2.c: Identify the Variety of Web Page Types.
Note: 'Web pages' include different 'web page states'; see definition of web page states.", 18 | "LABEL_OTHER": "Others..." 19 | } 20 | -------------------------------------------------------------------------------- /app/locale/EN/html_report.json: -------------------------------------------------------------------------------- 1 | { 2 | "BY" : "Report Creator:", 3 | "COMMISION_BY": "Evaluation Commissioner:", 4 | "HD_SUMMARY": "Summary of the evaluation findings", 5 | "HD_SCOPE": "Scope of the evaluation", 6 | "LABEL_SITE_NAME": "Website name", 7 | "LABEL_SITE_SCOPE": "Scope of the website", 8 | "LABEL_CONFORMANCE_TGT": "Conformance target", 9 | "LABEL_EXTRA_REQUIREMENTS": "Additional evaluation requirements", 10 | "LABEL_SUPPORT_BASE": "Accessibility support baseline", 11 | "LABEL_RELIEDUP_TECH": "Relied upon technologies", 12 | "HD_SCORE": "Overview of audit results", 13 | "RESULTS_OF": "Results of", 14 | "PRINCIPLE": "Principle", 15 | "TOTAL_SCORE": "Total", 16 | "HD_CRITERIA_REPORT": "Detailed audit results", 17 | "LABEL_DESCR": "Findings", 18 | "HD_SAMPLE": "Sample of audited web pages", 19 | "HD_SPECIFICS": "Recording of evaluation specifics", 20 | "HD_DOCS": "Related WCAG 2 resources" 21 | } 22 | -------------------------------------------------------------------------------- /app/locale/EN/import.json: -------------------------------------------------------------------------------- 1 | { 2 | "TITLE": "Import a WCAG EARL report", 3 | "INTRO": "If you have used another application to generate a WCAG EARL-report that falls into the scope of this evaluation, you may be able to import these and add them to the evaluation audit result. The file itself should be: JSON-LD parseable, consist of objects in EARL format and evaluation tests should be related to WCAG.", 4 | "LABEL_SELECT_FILE": "Select a JSON-LD file" 5 | } 6 | -------------------------------------------------------------------------------- /app/locale/EN/nav.json: -------------------------------------------------------------------------------- 1 | { 2 | "MENU": "Menu", 3 | "MENU_IMPORT": "Import", 4 | "MENU_IMPORT_TITLE": "Start EARL report import wizzard", 5 | "MENU_NEW": "New Report", 6 | "MENU_OPEN": "Open", 7 | "MENU_SAVE": "Save", 8 | "MENU_SAVE_TITLE": "Ctrl + S or ⌘ S", 9 | "MENU_RESOURCES": "Key Resources", 10 | "MENU_LANGUAGE": "Language", 11 | "WZRD_LABEL": "Evaluation steps", 12 | "WZRD_START": "Start", 13 | "WZRD_SCOPE": "1. Define Scope", 14 | "WZRD_EXPLORE": "2. Explore Website", 15 | "WZRD_SAMPLE": "3. Select Sample", 16 | "WZRD_AUDIT": "4. Audit Sample", 17 | "WZRD_REPORT": "5. Report Findings", 18 | "WZRD_ACTIVE": "Active", 19 | "WZRD_VIEWREPORT": "View Report", 20 | "PREV_STEP": "Previous step", 21 | "NEXT_STEP": "Next step", 22 | "STEP_START": "Start", 23 | "STEP_SCOPE": "Define Scope", 24 | "STEP_EXPLORE": "Explore Website", 25 | "STEP_SAMPLE": "Select Sample", 26 | "STEP_AUDIT": "Audit Sample", 27 | "STEP_REPORT": "Report Findings", 28 | "STEP_VIEWREPORT": "View Report", 29 | "BTN_BACK_TO_EVAL": "Back" 30 | } 31 | -------------------------------------------------------------------------------- /app/locale/EN/open.json: -------------------------------------------------------------------------------- 1 | { 2 | "TITLE": "Open Evaluation Report", 3 | "INTRO": "To reload a saved file, click the 'Find and select the data file' button and locate the JSON file that you previously saved.", 4 | "LABEL_SELECT_FILE": "Find and select the data file", 5 | "MSG_LOADING": "Loading the evaluation, please wait...", 6 | "BTN_LOAD_FILE": "Load data from selected file" 7 | } -------------------------------------------------------------------------------- /app/locale/EN/report.json: -------------------------------------------------------------------------------- 1 | { 2 | "TITLE": "Step 5: Report the Evaluation Findings", 3 | "INTRO": "Provide additional information about the evaluation that you want included in the report. The evaluation findings that you entered in the previous step are included below under 'Detailed audit results' for review and to help you write the executive summary. More guidance on this step is provided in WCAG-EM Step 5: Report the Evaluation Findings.", 4 | "LABEL_TITLE": "Report title", 5 | "TITLE_PREFIX": "Report for", 6 | "INF_TITLE": "Provide a title for the website accessibility evaluation report. For example:
'Evaluation Report for Example Organization'
'Webshop Accessibility Analysis and Repair Suggestions'", 7 | "LABEL_COMMISSIONER": "Evaluation commissioner", 8 | "INF_COMMISSIONER": "The person, team of people, organization, in-house department, or other entity that commissioned the evaluation.", 9 | "LABEL_CREATOR": "Evaluator", 10 | "INF_CREATOR": "The person, team of people, organization, in-house department, or other entity responsible for carrying out the evaluation.", 11 | "LABEL_DATE": "Evaluation date", 12 | "INF_DATE": "Provide the completion date or duration dates of this evaluation. You can use any date format.", 13 | "LABEL_SUMMARY": "Executive summary", 14 | "INF_SUMMARY": "Provide a brief summary of the evaluation findings to give an overview on the results. For example, describe the overall accessibility of the website and key observations you made during the evaluation, such as frequently occurring issues and patterns.", 15 | "LABEL_SPECIFICS": "Record of evaluation specifics (optional)", 16 | "INF_SPECIFICS": "WCAG-EM suggests that you archive the web pages audited. For more information, see WCAG-EM Step 5.b: Record the Evaluation Specifics. You can use this text field to record the evaluation tools, web browsers, assistive technologies, other software, and methods used for the evaluation. What you enter here will be included in the generated report. After you download the report, you could delete or edit this information in the HTML file before submitting the report.", 17 | "HD_CRITERIA_REPORT": "Detailed audit results" 18 | } -------------------------------------------------------------------------------- /app/locale/EN/sample.json: -------------------------------------------------------------------------------- 1 | { 2 | "TITLE": "Step 3: Select a Representative Sample", 3 | "INTRO": "Select web pages for evaluation. The notes that you took during exploration in the previous step are provided here, to help you select the web pages. Ensure that the web pages selected are representative of the target website. More guidance on this step is provided in WCAG-EM Step 3: Select a Representative Sample.", 4 | "HD_STRUCT_SAMPLE": "Structured Sample", 5 | "HD_ESSENT_FUNC": "Essential functionality (optional notes from previous step)", 6 | "HD_VARIETY_PAGE_TYPES": "Variety of web page types (optional notes from previous step)", 7 | "HD_STRUCT_SAMPLE_SUB": "Structured Sample Web Pages", 8 | "INF_STRUCT_SAMPLE": "Select web pages that reflect all identified (1) common web pages, (2) essential functionality, (3) types of web pages, (4) web technologies relied upon, and (5) other relevant web pages. For more information, see WCAG-EM Step 3.a: Include a Structured Sample.
Note: 'Web pages' include different 'web page states'; see definition of web page states.", 9 | "HD_RANDOM_SAMPLE": "Randomly Selected Sample", 10 | "INF_RAND_SAMPLE": "Randomly select sample web pages; select 10% of the structured sample selected above. For more information, see WCAG-EM Step 3.b: Include a Randomly Selected Sample.
Note: 'Web pages' include different 'web page states'; see definition of web page states.", 11 | "RAND_SAMPLE_LENGTH": "Based on your structured sample of {{total}} web pages, choose at least {{count}} randomly selected web pages (to meet the 10% requirement in WCAG-EM).", 12 | "LABEL_HANDLE": "Short name", 13 | "LABEL_PAGE": "Address (URL) or description", 14 | "NO_PAGES_DEFINED": "No pages defined for this list", 15 | "ITEM": "Web page", 16 | "PLH_TITLE": "Identifier for the web page", 17 | "PLH_PAGE_URL": "Address (URL) or description of how to get there", 18 | "BTN_ADD_PAGE": "Add web page", 19 | "BTN_REMOVE_PAGE": "Remove page", 20 | "STRUCTURED_PAGE": "Structured page", 21 | "RANDOM_PAGE": "Random page", 22 | "SAMPLE_PAGE": "Sample page" 23 | } 24 | -------------------------------------------------------------------------------- /app/locale/EN/save.json: -------------------------------------------------------------------------------- 1 | { 2 | "TITLE": "Save Evaluation Report", 3 | "INTRO": "Use the link below to save the evaluation report information that you have entered in a JSON data file locally on your computer.", 4 | "BTN_DOWNLOAD_DATA_FILE": "Save data file locally to your computer", 5 | "TIPS": "You can save partially-complete reports (and notes) and work on them later. You can open them from any web browser and you can transfer the data file to another computer.
You can Save periodically as you work to avoid losing data if your web browser closes. You can use Windows shortcut keys Ctrl+S or Mac shortcut keys ⌘S to open the Save dialog (or automatically save it in your downloads folder depending on your web browser settings).
When you are done entering your evaluation report information, you can download an HTML file of the completed report from the View Report page." 6 | } -------------------------------------------------------------------------------- /app/locale/EN/scope.json: -------------------------------------------------------------------------------- 1 | { 2 | "TITLE": "Step 1: Define the Evaluation Scope", 3 | "INTRO": "Define the overall parameters and scope of the evaluation. Ideally, this is done with the person who commissioned the evaluation (who may or may not be the website owner), to ensure common expectations about the scope of the evaluation. More guidance on this step is provided in WCAG-EM Step 1: Define the Evaluation Scope.", 4 | "LABEL_SITE_NAME": "Website name", 5 | "INF_SITE_NAME": "Provide a name for the website that you would like to evaluate. For example:
'Public Website of Example Organization'
'Webshop of Example Company'
'Intranet of Example University'", 6 | "LABEL_SITE_SCOPE": "Scope of the website", 7 | "INF_SITE_SCOPE_0": "Define the scope of the website, so it is clear which web pages are included in the evaluation. For example:", 8 | "INF_SITE_SCOPE_LI0": "'All web content of the public website of Example Org. located at http://www.example.org'", 9 | "INF_SITE_SCOPE_LI1": "'All web content of the online shop of Example Org. located at http://www.example.org/shop/'", 10 | "INF_SITE_SCOPE_LI2": "'All web content of the mobile version of the public website of Example Org. located at http://m.example.org'", 11 | "INF_SITE_SCOPE_1": "WCAG-EM Step 1.a: Define the Scope of the Website", 12 | "LABEL_WCAG_VERSION": "WCAG Version", 13 | "INFO_WCAG_VERSION": "Select the WCAG version to use. Version 2.1 (default) or 2.0", 14 | "WCAG21": "WCAG 2.1", 15 | "WCAG20": "WCAG 2.0", 16 | "LABEL_CONFORMANCE_TGT": "Conformance target", 17 | "INF_CONF_TGT": "Select a target WCAG 2 conformance level ('A', 'AA', or 'AAA') for the evaluation. For more information, see WCAG-EM Step 1.b: Define the Conformance Target. This selection determines which conformance level filters are active by default in 'step 4: Audit the Sample'.", 18 | "LABEL_SUPPORT_BASE": "Accessibility support baseline", 19 | "INF_SUPPORT_BASE": "Define the web browsers, assistive technologies, and other user agents that will be accessibility supported by the website. For example, 'Internet Explorer (IE) with JAWS', 'FireFox with NVDA', and 'Apple with VoiceOver' could be basic definitions. For more information, see WCAG-EM Step 1.c: Define an Accessibility Support Baseline.", 20 | "LABEL_EXTRA_REQUIREMENTS": "Additional evaluation requirements", 21 | "INF_EXTRA_REQUIREMENTS_0": "Define any additional evaluation requirements. For example:", 22 | "INF_EXTRA_REQUIREMENTS_LI0": "'The report will include a list of all errors identified by the evaluator, rather than examples only'", 23 | "INF_EXTRA_REQUIREMENTS_LI1": "'The report will include a description of the problem and repair suggestions for any errors listed'", 24 | "INF_EXTRA_REQUIREMENTS_LI2": "'The evaluation will cover all web pages and web content of the website, rather than a selected sample only'", 25 | "INF_EXTRA_REQUIREMENTS_1": "WCAG-EM Step 1.d: Define Additional Evaluation Requirements" 26 | } 27 | -------------------------------------------------------------------------------- /app/locale/EN/start.json: -------------------------------------------------------------------------------- 1 | { 2 | "TITLE": "WCAG-EM Report Tool", 3 | "SUBTITLE": "Website Accessibility Evaluation Report Generator", 4 | "INTRO_HD": "What this tool does", 5 | "INTRO_1": "This tool helps you generate a report according to the Website Accessibility Conformance Evaluation Methodology (WCAG-EM). It does not perform any accessibility checks. It helps you follow the steps of WCAG-EM, to generate a structured report from the input that you provide. It is designed for experienced evaluators who know Web Content Accessibility Guidelines (WCAG) 2 and are somewhat familiar with WCAG-EM. For an introduction to WCAG-EM, see the WCAG-EM Overview.", 6 | "INTRO_2": "Note: This tool does not automatically save the information that you enter. To save your data in a file locally on your computer, use Windows shortcut keys Ctrl+S or Mac shortcut keys {{mac}} to open the Save dialog. (Or the 'Save' link at the top of the page will open the Save Evaluation Report page and from there the 'Save data file locally to your computer' link will open the Save dialog.)", 7 | "USAGE_HD": "How this tool works", 8 | "USAGE_LI1": "All functionality provided by this tool is now loaded and running locally in your web browser. You don't need an Internet connection beyond this point. When you close your web browser window, any unsaved data is lost.", 9 | "USAGE_LI2": "All input that you provide through this tool is recorded as JSON data in the background (in your web browser, not on any server). You can Save periodically as you work to avoid losing data if your web browser closes.", 10 | "USAGE_LI3": "You can save partially-complete reports and work on them later. To reload a saved file, use the 'Open' link at the top and find the file that you previously saved.", 11 | "USAGE_LI4": "Links that are not part of the navigation or functionality (links to external resources) open in a new web browser windows.", 12 | "TIPS_HD": "Tips for using this tool", 13 | "TIPS_LI1": "You can go back and forth between the steps in any order. None of the fields are required.", 14 | "TIPS_LI2": "To get more information about a field, select the {{info}} icon next to the field label.", 15 | "TIPS_LI3": "The tool provides your report as HTML and CSS files. You can download these files from the 'View Report' page. You can then change the report content and visual design.", 16 | "TIPS_LI4": "You can include in your report WCAG 2 success criteria beyond the conformance target. For example, the website is only required to meet Level AA, yet you want to also include Level AAA success criteria in the report. In step 4, use the level filter to show higher level criteria. Any criteria with a result will always be included in the report." 17 | } 18 | -------------------------------------------------------------------------------- /app/locale/NL/audit.json: -------------------------------------------------------------------------------- 1 | { 2 | "ASSERTION_RESULT_DESCRIPTION_LABEL": "Bevindingen", 3 | "ASSERTION_RESULT_DESCRIPTION_PLACEHOLDER": "Bevindingen uit de evaluatie", 4 | "BTN_COLLAPSE_PAGES": "Invoer voor per-pagina-resultaten verbergen", 5 | "BTN_COMPLETE_SELECTED": "Markeer selectie als voltooid", 6 | "BTN_EXPAND_PAGES": "Invoer voor per-pagina-resultaten weergeven", 7 | "BTN_OPEN_SELECTED": "Open geselecteerde pagina's", 8 | "BTN_SHOW_TEXT": "criteriumtekst weergeven", 9 | "BTN_UNCOMPLETE_SELECTED": "Markeer selectie als onvoltooid", 10 | "CLICK_TO_DELETE": "Klik om te verwijderen", 11 | "FILTER_LEVEL_LEGEND": "Toon conformiteitsniveau", 12 | "FILTER_NEW_IN_WCAG21": "Added in WCAG 2.1", 13 | "FILTER_VERSION_LEGEND": "Toon versie", 14 | "FILTER": "Toon", 15 | "HD_CRITERIA": "Succescriteria om te evalueren", 16 | "HD_SAMPLE_SELECT": "Te evalueren sample", 17 | "HOW_TO": "Hoe te voldoen", 18 | "INF_AUDIT_CRITERIA": "In dit onderdeel vindt u de WCAG 2.0 succescriteria. Gebruik de filter om succescriteria van niveaus (A, AA en AAA) te tonen of verbergen. Kies 'Voldoende', 'Onvoldoende', 'Niet van toepassing', en 'Onbekend' als resultaat. U kunt bevindingen en andere opmerkingen uit de evaluatie in het tekstveld invullen.", 19 | "INF_AUDIT_SAMPLE": "In dit onderdeel vindt u de webpagina's uit de vorige stap. De webpagina's die in dit onderdeel geselecteerd worden zullen onder 'Invoer voor per-pagina-resultaten weergeven' worden weergegeven wanneer deze uitgeklapt is in het onderdeel 'Succescriteria om te evalueren'. U kunt per pagina, of meerdere webpagina's tegelijk weergeven. Met het linkicoon kunt u pagina's in een nieuw venster openen.", 20 | "INTRO": "Beschrijf de resultaten uit de evaluatie van de webpagina's geselecteerd in de vorige stap. Vergelijk de resultaten tussen de geordende pagina's en de willekeurig gekozen pagina's, en waar nodig pas de geselecteerde sample in de vorige stap aan. Meer informatie over deze stap is te vinden in WCAG-EM Stap 4: Toets de sample.
Opmerking: Voor elk WCAG 2.0 succescriterium, kunt u resultaten voor de volledige sample invullen, evenals resultaten voor specifieke pagina's. Om individuele resultaten in te vullen, selecteer pagina's onder 'Te evalueren sample' (in de linker kolom); vervolgens onder de succescriteria, kies 'Invoer voor per-pagina-resultaten weergeven'", 21 | "LABEL_OUTCOME": "Uitkomst", 22 | "LABEL_PAGE_HANDLE": "Korte paginatitel", 23 | "NO_PAGE_SELECTED": "Geen pagina geselecteerd onder 'Te evalueren sample'", 24 | "NO_SAMPLE": "Geen sample beschikbaar. Maak een sample in stap 2 en stap 3.", 25 | "NOTE": "Opmerking", 26 | "PRINCIPLE": "Principe", 27 | "RESULTS_FOR": "Uitkomst voor", 28 | "SAMPLE_FINDINGS": "Resultaat van de hele sample", 29 | "SELECT_ALL": "Selecteer alle pagina's", 30 | "TESTED": "Getest", 31 | "TITLE": "Stap 4: Toets de sample", 32 | "UNDERSTAND": "Toelichting", 33 | "UNTESTED": "{{critCount}} niet getest" 34 | } 35 | -------------------------------------------------------------------------------- /app/locale/NL/common.json: -------------------------------------------------------------------------------- 1 | { 2 | "BROWSER_NOT_SUPPORTED": "Enkele functionaliteiten zijn niet door uw webbrowser ondersteund, zoals het opslaan en openen van rapporten. Je kunt de rapport tool met beperkte functionaliteit gebruiken. Update of gebruik een andere webbrowser om van alle functionaliteiten in de Report Tool gebruik te kunnen maken.", 3 | "WARNING_BEFORE_UNLOAD": "Uw data worden niet automatisch opgeslagen. Wanneer het venster van uw web browser sluit is de data verloren. Gebruik de 'Opslaan' link (Ctrl + S of ⌘ S) bovenaan iedere pagina om uw data in een bestand op uw locale computer te bewaren en open deze later om door te werken.", 4 | "MORE_INFO": "Voor meer informatie, zie {{name}}.", 5 | "HIDE_MESSAGE": "Verberg bericht", 6 | "BTN_INFO": "Info uitklappen", 7 | "BTN_CLOSE_INFO": "Sluit info", 8 | "YES": "Ja", 9 | "NO": "Nee", 10 | "CLICK_EXPAND": "Klik om sectie te tonen", 11 | "CLICK_COLLAPSE": "Klik om sectie te verbergen", 12 | "TO_TOP": "Naar boven" 13 | } -------------------------------------------------------------------------------- /app/locale/NL/download.json: -------------------------------------------------------------------------------- 1 | { 2 | "TITLE": "Website Toegankelijkheid Evaluatie Rapport", 3 | "INTRO": "Hieronder vindt u het evaluatierapport gebaseerd op de gegevens die u in vorige stappen heeft ingevuld. U kunt teruggaan naar vorige stappen voor verdere aanpassingen. U kunt de evaluatiedata downloaden zodat u hier later aan door kunt werken. (Hetzelfde als bij 'Opslaan'.)
Dit rapport is bedoeld als download. U kunt de HTML en CSS bestanden van het rapport hieronder downloaden. Daarna kunt u de presentatie en de inhoud van het rapport verder bewerken.", 4 | "DOWNLOAD_REPORT": "Download het rapport", 5 | "BTN_SAVE_HTML": "Download het evaluatierapport (HTML)", 6 | "BTN_SAVE_CSS": "Download de stylesheet van het rapport (CSS)", 7 | "BTN_SAVE_JSON": "Bewaar de evaluatiedata (JSON)" 8 | } -------------------------------------------------------------------------------- /app/locale/NL/earl.json: -------------------------------------------------------------------------------- 1 | { 2 | "PASSED": "Voldoende", 3 | "FAILED": "Onvoldoende", 4 | "CANT_TELL": "Onbekend", 5 | "NOT_PRESENT": "Niet van toepassing", 6 | "NOT_CHECKED": "Niet getoetst", 7 | "LEVEL_A": "Niveau A", 8 | "LEVEL_AA": "Niveau AA", 9 | "LEVEL_AAA": "Niveau AAA" 10 | } -------------------------------------------------------------------------------- /app/locale/NL/error.json: -------------------------------------------------------------------------------- 1 | { 2 | "TITLE": "Oeps! Er ging iets mis", 3 | "INTRO": "U bent op de verkeerde plek beland. Probeer een van de volgende oplossingen om het probleem op te lossen.", 4 | "SUGGESTION1": "Als u de URL heeft getypet, controleer of deze juist is.", 5 | "SUGGESTION2": "Ga terug naar de vorige pagina en probeer het nog eens.", 6 | "SUGGESTION3": "Zorg dat de bestanden waarmee u werkt het wcag-em format volgen.", 7 | "BUG_REPORT": "Om een bug of suggestie voor nieuwe functionaliteit te rapporteren laat een issue achter op onze Github-projectpagina." 8 | } -------------------------------------------------------------------------------- /app/locale/NL/explore.json: -------------------------------------------------------------------------------- 1 | { 2 | "TITLE": "Stap 2: Verken de te onderzoeken website", 3 | "INTRO": "Verken de website om zo het doel en de functie van de website te achterhalen. Deze stap helpt u te bepalen welke webpagina's te bekijken in de volgende stappen. Achterhaal welke webtechnologieën in de website zijn gebruikt, en als u wilt, neem notities over belangrijke aspecten van de website. Het is gebruikelijk om voor deze stap input van de eigenaar en ontwikkelaars van de website mee te nemen. Meer informatie over deze stap vindt u in WCAG-EM Stap 2: Verken de te onderzoeken website.", 4 | "HD_RELIEDUP_TECH": "technologieën waarop gesteund wordt", 5 | "INF_RELIEDUP_TECH": "Bepaal op welke webtechnologieën de website steund volgens WCAG 2.0. Voor meer informatie, zie WCAG-EM Stap 2.d: Identificeer technologieën waarop gesteund wordt.
Merk op: om andere technologieën toe te voegen, kies 'Anders' and gebruik de velden 'Webtechnologie' en 'Specificatie adres (URL)'. In het veld 'Specificatie adres (URL)' dient te verwijzen naar de specificatie van de technologie.", 6 | "LABEL_TECH": "Webtechnologie", 7 | "LABEL_TECH_SPEC": "Specificatie adres (URL)", 8 | "PLH_TECH": "Bv. HTML5, CSS, DOM", 9 | "PLH_TECH_SPEC": "Locatie (URL) of instructie naar de specificatie", 10 | "BTN_REMOVE_TECH": "Webtechnologie verwijderen", 11 | "BTN_ADD_TECH": "Webtechnologie toevoegen", 12 | "HD_NOTE_TAKING": "Eventuele aantekeningen uit verkenning", 13 | "INF_NOTE_TAKING": "In dit onderdeel kunt u aantekeningen zetten die u maakt bij het verkennen van de website. Deze aantekeningen kunt u in de volgende stap gebruiken om webpagina's voor de sample te selecteren voor de evaluatie. Deze notities komen niet in het eindrapport. Wel worden ze bewaard wanneer u het onderzoek opslaat en het bestand later opent.", 14 | "LABEL_ESSENT_FUNC": "Functionaliteiten essentieel voor de website", 15 | "INF_ESSENT_FUNC": "Gebruik dit veld om essentiële functionaliteiten van de website te noteren. Voorbeelden van essentiële functionaliteiten zijn:
'Selecteer en bestel een product uit de webwinkel van de website'
'Afronden en versturen van een formulier op de website'
'Een account op de website registreren'
Meer informatie vindt u in WCAG-EM Stap 2.b: Identificeer essentiële functionaliteiten van de website", 16 | "LABEL_VARIETY_PAGE_TYPES": "Diverse paginatypes", 17 | "INF_VARIETY_PAGE_TYPES": "Gebruik dit veld om bij te houden welke diverse typen webpagina's u op de website heeft gevonden. Het gaat hier bijvoorbeeld om verschillende (opmaak)stijlen, layouts, indelingen en functionaliteiten op de website. Meer informatie vindt u in WCAG-EM Stap 2.c: Identificeer diverse paginatypes.
Merk op: Een 'webpagina' kan in verschillende 'webpagina-toestanden' bestaan; zie de definitie webpagina-toestanden.", 18 | "LABEL_OTHER": "Anders..." 19 | } -------------------------------------------------------------------------------- /app/locale/NL/html_report.json: -------------------------------------------------------------------------------- 1 | { 2 | "BY" : "Rapport auteur", 3 | "COMMISION_BY": "Evaluatie opdrachtgever", 4 | "HD_SUMMARY": "Samenvatting Evaluatieresultaten", 5 | "HD_SCOPE": "Scope van de evaluatie", 6 | "LABEL_SITE_NAME": "Website naam", 7 | "LABEL_SITE_SCOPE": "Scope van de website", 8 | "LABEL_CONFORMANCE_TGT": "Conformiteitsdoel", 9 | "LABEL_EXTRA_REQUIREMENTS": "Verdere evaluatievereisten", 10 | "LABEL_SUPPORT_BASE": "Basisniveau van toegankelijkheid ondersteund", 11 | "LABEL_RELIEDUP_TECH": "technologieën waarop gesteund wordt", 12 | "HD_SCORE": "Overzicht toetsresultaten", 13 | "RESULTS_OF": "Resultaat voor", 14 | "PRINCIPLE": "Principe", 15 | "TOTAL_SCORE": "Totaal", 16 | "HD_CRITERIA_REPORT": "Uitgebreide toetsresultaten", 17 | "LABEL_DESCR": "Bevindingen", 18 | "HD_SAMPLE": "Sample met getoetste webpagina's", 19 | "HD_SPECIFICS": "Onderbouwing van de evaluatie", 20 | "HD_DOCS": "Informatie over WCAG 2.0" 21 | } -------------------------------------------------------------------------------- /app/locale/NL/nav.json: -------------------------------------------------------------------------------- 1 | { 2 | "MENU": "Menu", 3 | "MENU_RESOURCES": "Relevante links", 4 | "MENU_NEW": "Nieuw rapport", 5 | "MENU_OPEN": "Open", 6 | "MENU_SAVE": "Opslaan", 7 | "MENU_SAVE_TITLE": "Ctrl + S of ⌘ S", 8 | "MENU_LANGUAGE": "Taalkeuze", 9 | "WZRD_LABEL": "Evaluatiestappen", 10 | "WZRD_START": "Start", 11 | "WZRD_SCOPE": "1. Bepaal Scope", 12 | "WZRD_EXPLORE": "2. Verken Website", 13 | "WZRD_SAMPLE": "3. Selecteer Sample", 14 | "WZRD_AUDIT": "4. Toets Sample", 15 | "WZRD_REPORT": "5. Rapporteer Resultaat", 16 | "WZRD_ACTIVE": "Actief", 17 | "WZRD_VIEWREPORT": "Bekijk Rapport", 18 | "PREV_STEP": "Vorige stap", 19 | "NEXT_STEP": "Volgende stap", 20 | "STEP_START": "Start", 21 | "STEP_SCOPE": "Bepaal scope", 22 | "STEP_EXPLORE": "Verken website", 23 | "STEP_SAMPLE": "Selecteer Sample", 24 | "STEP_AUDIT": "Toets Sample", 25 | "STEP_REPORT": "Rapporteer Resultaat", 26 | "STEP_VIEWREPORT": "Bekijk Rapport", 27 | "BTN_BACK_TO_EVAL": "Terug" 28 | } -------------------------------------------------------------------------------- /app/locale/NL/open.json: -------------------------------------------------------------------------------- 1 | { 2 | "TITLE": "Open Evaluatierapport", 3 | "INTRO": "Om een opgeslagen bestand opnieuw te openen, klik op 'Selecteer het evaluatie-databestand', en zoek het JSON bestand op dat u voorheen hebt opgeslagen.", 4 | "LABEL_SELECT_FILE": "Selecteer het evaluatie-databestand", 5 | "MSG_LOADING": "De evaluatie wordt geladen, even geduld a.u.b.", 6 | "BTN_LOAD_FILE": "Open data uit geselecteerd bestand" 7 | } -------------------------------------------------------------------------------- /app/locale/NL/report.json: -------------------------------------------------------------------------------- 1 | { 2 | "TITLE": "Stap 5: Evaluatiebevindingen rapporteren", 3 | "INTRO": "Benoem verdere bevindingen uit de evaluatie die u in het rapport wilt hebben. De toetsresultaten uit de vorige stap vindt u onder 'Uitgebreide toetsresultaten' ter review en om u te helpen bij het schrijven van de samenvatting. Meer informatie over deze stap vindt u in WCAG-EM Stap 5: Evaluatiebevindingen rapporteren.", 4 | "LABEL_TITLE": "Rapporttitel", 5 | "TITLE_PREFIX": "Rapportage van", 6 | "INF_TITLE": "Vul hier de titel in van het evaluatierapport van de toegankelijkheid van de website. Bijvoorbeeld:
'Evaluatierapport voor Voorbeeldorganisatie'
'Webshop Toegankelijkheidsanalyse en verbetersuggesties'", 7 | "LABEL_COMMISSIONER": "Evaluatieopdrachtgever", 8 | "INF_COMMISSIONER": "De persoon, het team, de organisatie, het departement of andere entiteit die opdracht voor de evaluatie gaf.", 9 | "LABEL_CREATOR": "Evaluator", 10 | "INF_CREATOR": "De persoon, het team, de organisatie, het departement of andere entiteit verantwoordelijk voor het uitvoeren van de evaluatie.", 11 | "LABEL_DATE": "Evaluatiedatum", 12 | "INF_DATE": "Vul hier de datum in waarop de evaluatie werd afgerond, of de datums waarop de evaluatie plaats vond. U kunt elk datumformaat gebruiken.", 13 | "LABEL_SUMMARY": "Managementsamenvatting", 14 | "INF_SUMMARY": "Geef een korte samenvatting van de bevindingen uit de evaluatie om zo een overzicht van de resultaten te krijgen. Benoem bijvoorbeeld de algehele toegankelijkheid van de website, met enkele concrete voorbeelden uit het onderzoek, zoals de frequentie van bepaalde verbeterpunten.", 15 | "LABEL_SPECIFICS": "Benoem de onderbouwing van de evaluatie (optioneel)", 16 | "INF_SPECIFICS": "WCAG-EM raadt aan dat u de getoetste webpagina's bewaart. Meer informatie hierover vindt u in WCAG-EM Stap 5.b: Benoem de onderbouwing van de evaluatie. Gebruik dit tekstveld tevens om de gebruikte evaluatietools, webbrowsers, hulptechnologieën, andere software en toetsmethodes vast te leggen. Dit zal tevens in het eindrapport staan. U kunt deze informatie na het downloaden van het rapport als HTML-bestand nog bijwerken.", 17 | "HD_CRITERIA_REPORT": "Uitgebreide toetsresultaten" 18 | } -------------------------------------------------------------------------------- /app/locale/NL/sample.json: -------------------------------------------------------------------------------- 1 | { 2 | "TITLE": "Stap 3: Selecteer een representatieve sample", 3 | "INTRO": "Selecteer webpagina's voor de evaluatie. U vindt hier uw aantekeningen uit de vorige stap, om u te helpen webpagina's voor de sample te selecteren. Zorg ervoor dat de gekozen webpagina's representatief zijn voor de te toetsen website. Meer informatie over deze stap vindt u in WCAG-EM Stap 3: Selecteer een representatieve sample.", 4 | "HD_STRUCT_SAMPLE": "Geordende sample", 5 | "HD_ESSENT_FUNC": "Essentiële functionaliteiten (optionele notities uit vorige stap)", 6 | "HD_VARIETY_PAGE_TYPES": "Diverse paginatypes (optionele notities uit vorige stap)", 7 | "HD_STRUCT_SAMPLE_SUB": "Geordende samplepagina's", 8 | "INF_STRUCT_SAMPLE": "Selecteer webpagina's representatief voor alle (1) veelgebruikte webpagina's, (2) essentiële functionaliteiten, (3) typen pagina's, (4) webtechnologieën waarop gesteund wordt, en (5) overige relevante pagina's. Meer informatie vindt u in WCAG-EM Stap 3.a: Gebruik een geordende sample.
Opmerking: 'webpagina's' kunnen in verschillende 'toestanden' (states) bestaan; zie de definitie van webpagina-toestand", 9 | "HD_RANDOM_SAMPLE": "Willekeurige sample", 10 | "INF_RAND_SAMPLE": "Selecteer willekeurig samplepagina's; gebruik 10% van de grootte van de geordende sample. Meer informatie vindt u in WCAG-EM Stap 3.b: Gebruik een willekeurige sample.
Opmerking: 'webpagina's' kunnen in verschillende 'toestanden' (states) bestaan; zie de definitie van webpagina toestand", 11 | "RAND_SAMPLE_LENGTH": "Op basis van de geordende sample van {{total}} webpagina's, selecteer tenminste {{count}} willekeurige webpagina's (om te voldoen aan de 10% eis uit WCAG-EM).", 12 | "LABEL_HANDLE": "korte titel", 13 | "LABEL_PAGE": "Locatie (URL) of instructie", 14 | "NO_PAGES_DEFINED": "Er is geen pagina in deze lijst", 15 | "ITEM": "Webpagina", 16 | "PLH_TITLE": "Identificerende naam voor de webpagina", 17 | "PLH_PAGE_URL": "Locatie (URL) of instructie van het te volgen pad", 18 | "BTN_ADD_PAGE": "Pagina toevoegen", 19 | "BTN_REMOVE_PAGE": "Pagina verwijderen", 20 | "STRUCTURED_PAGE": "Geordende pagina", 21 | "RANDOM_PAGE": "Willekeurige pagina", 22 | "SAMPLE_PAGE": "Samplepagina" 23 | } -------------------------------------------------------------------------------- /app/locale/NL/save.json: -------------------------------------------------------------------------------- 1 | { 2 | "TITLE": "Evaluatierapport opslaan", 3 | "INTRO": "Gebruik onderstaande link om de door u ingevoerde gegevens van het evaluatierapport als JSON databestand lokaal op uw computer te bewaren.", 4 | "BTN_DOWNLOAD_DATA_FILE": "Bewaar databestand lokaal op uw computer", 5 | "TIPS": "U kunt onvoltooide rapporten (en aantekeningen) bewaren en hier later aan verder werken. U kunt deze openen in iedere webbrowser en het databestand naar een andere computer sturen.
U dient uw werk regelmatig op te slaan om te voorkomen dat u werk verliest, mocht de webbrowser sluiten. U kunt de sneltoets Ctrl+S voor windows of ⌘S voor Mac gebruiken om het opslaan-scherm te starten (of om automatisch naar uw downloads folder te plaatsen, afhankelijk van uw browserinstellingen).
Wanneer u het evaluatierapport heeft afgerond, kunt u een HTML-bestand met het volledige rapport downloaden de 'Bekijk rapport'-pagina." 6 | } -------------------------------------------------------------------------------- /app/locale/NL/scope.json: -------------------------------------------------------------------------------- 1 | { 2 | "TITLE": "Stap 1: Bepaal de scope van de evaluatie", 3 | "INTRO": "Bepaal de basiseisen en scope van de evaluatie. Dit wordt bij voorkeur gedaan door de opdrachtgever van de evaluatie (dit kan, maar hoeft niet de eigenaar van de website te zijn), om ervoor te zorgen dat de verwachtingen op de opdracht aansluiten. Meer informatie over deze stap vindt u in WCAG-EM Stap 1: Bepaal de scope van de evaluatie.", 4 | "LABEL_SITE_NAME": "Website naam", 5 | "INF_SITE_NAME": "Vul een naam in van de te evalueren website. Bijvoorbeeld:
'Publieke website van Voorbeeld Organisatie'
'Webshop van Voorbeeld Bedrijf'
'Intranet van Voorbeeld Universiteit'", 6 | "LABEL_SITE_SCOPE": "Scope van de website", 7 | "INF_SITE_SCOPE_0": "Leg de scope van de website vast, zodat duidelijk is welke webpagina's binnen de evaluatie vallen. Bijvoorbeeld:", 8 | "INF_SITE_SCOPE_LI0": "'Alle webcontent van de publieke website van Voorbeeld Org. op http://www.example.org'", 9 | "INF_SITE_SCOPE_LI1": "'Alle webcontent van de webwinkel van Voorbeeld Org. op http://www.example.org/shop/'", 10 | "INF_SITE_SCOPE_LI2": "'Alle webcontent op de mobiele versie van de publieke website van Voorbeeld Org. op http://m.example.org'", 11 | "INF_SITE_SCOPE_1": "WCAG-EM Stap 1.a: Definieer de scope van de website", 12 | "LABEL_CONFORMANCE_TGT": "Conformiteitsdoel", 13 | "INF_CONF_TGT": "Bepaal het te behalen WCAG 2.0 conformiteitsniveau ('A', 'AA' of 'AAA') voor de evaluatie. Voor meer informatie, zie WCAG-EM Stap 1.b: Bepaal het conformiteitsdoel. Deze keuze bepaald welke niveaufilters in stap 4 standaard aan zullen staan.", 14 | "LABEL_SUPPORT_BASE": "Basisniveau van toegankelijkheid-ondersteuning", 15 | "INF_SUPPORT_BASE": "Bepaal welke webbrowser, hulptechnologieën en andere user agents door toegankelijkheid ondersteund zijn door de website. Bijvoorbeeld: 'Internet Explorer (IE) met JAWS', 'Firefox met NVDA', en 'iOS met VoiceOver' zou het basisniveau kunnen zijn. Voor meer informatie, zie WCAG-EM Stap 1.c: Bepaal het Basisniveau van toegankelijkheid-ondersteuning.", 16 | "LABEL_EXTRA_REQUIREMENTS": "Verdere onderzoeksvereisten", 17 | "INF_EXTRA_REQUIREMENTS_0": "Bepaal overige onderzoeksvereisten. Bijvoorbeeld:", 18 | "INF_EXTRA_REQUIREMENTS_LI0": "'In het rapport wordt een volledige lijst van de gevonden problemen opgenomen, in plaats van slechts enkele voorbeelden'", 19 | "INF_EXTRA_REQUIREMENTS_LI1": "'In het rapport zal een omschrijving van de problemen gegeven worden, samen met suggesties voor het oplossen van de problemen'", 20 | "INF_EXTRA_REQUIREMENTS_LI2": "'Alle webpagina's en webcontent van de website zullen in de evaluatie getest worden, in plaats van enkel de steekproef", 21 | "INF_EXTRA_REQUIREMENTS_1": "WCAG-EM Stap 1.d: Bepaal verdere onderzoeksvereisten", 22 | "WCAG21": "WCAG 2.1", 23 | "WCAG20": "WCAG 2.0" 24 | } 25 | -------------------------------------------------------------------------------- /app/locale/NL/start.json: -------------------------------------------------------------------------------- 1 | { 2 | "TITLE": "WCAG-EM Report Tool", 3 | "SUBTITLE": "Website Toegankelijkheid Evaluatie Rapport Generator", 4 | "INTRO_HD": "Wat de tool doet", 5 | "INTRO_1": "Deze tool helpt u bij het maken van rapporten volgens de Website Accessibility Conformance Evaluation Methodology (WCAG-EM). Het voert geen toegankelijkheidstests voor u uit. Het begeleidt je door de stappen van WCAG-EM, om een gestructureerd rapport te genereren op basis van de gegevens die u invult. De tool is ontworpen voor ervaren inspecteurs bekend met Richtlijnen voor Toegankelijkheid van Webcontent (WCAG) 2.0 en met enige kennis van WCAG-EM. U kunt een WCAG-EM introductie vinden in het WCAG-EM Overzicht.", 6 | "INTRO_2": "Let op: Deze tool bewaart niet automatisch uw werk. U kunt uw gegevens lokaal op uw computer bewaren met de sneltoets Ctrl+S in windows, of {{mac}} op Mac. Dit start het opslaan scherm. (U kunt dit ook doen door de 'Opslaan' link bovenaan de pagina te klikken, en vervolgens op de link 'Bewaar databestand lokaal op uw computer' te klikken.)", 7 | "USAGE_HD": "Hoe deze tool werkt", 8 | "USAGE_LI1": "Alle functionaliteit is direct in uw webbrowser beschikbaar. U heeft geen internetverbinding nodig vanaf dit punt. Wanneer u het venster van de webbrowser sluit, raken gegevens die u niet heeft bewaard verloren.", 9 | "USAGE_LI2": "Alle gegevens die u invult worden als JSON data op de achtergrond bewaard (in uw webbrowser, niet op een server). U kunt periodiek opslaan terwijl u werkt, om te voorkomen dat u data verliest mocht uw webbrowser sluiten.", 10 | "USAGE_LI3": "U kunt tussentijdse rapporten bewaren en er later aan verder werken. Klik op de 'Open' link bovenin de pagina en laad daar het bestand dat u eerder hebt opgeslagen.", 11 | "USAGE_LI4": "Links naar externe pagina's (buiten de tool) openen in een nieuw browser venster.", 12 | "TIPS_HD": "Tips om de tool te gebruiken", 13 | "TIPS_LI1": "U kunt heen en weer tussen de stappen schakelen. Geen van de velden is verplicht.", 14 | "TIPS_LI2": "Voor meer informatie over een veld, klik op het {{info}} icoon naast het veld.", 15 | "TIPS_LI3": "De tool creëert uw rapport als HTML en CSS bestanden. U kunt deze bestanden downloaden op de 'Bekijk rapport'-pagina. Daarna kunt u de presentatie en de inhoud van het rapport verder bewerken.", 16 | "TIPS_LI4": "U kunt succescriteria aan uw WCAG 2.0 rapport toevoegen die hoger zijn dan het conformiteitsdoel. Bijvoorbeeld, de website dient aan niveau AA te voldoen, maar u wilt ook enkele AAA criteria in het rapport benoemen. In stap 4 kunt u de niveaufilter gebruiken om succescriteria van een hoger niveau te tonen. Criteria met een ingevuld resultaat zullen altijd in het rapport komen." 17 | } -------------------------------------------------------------------------------- /app/scripts/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | angular.module('wcagReporter', [ 3 | 'ngResource', 4 | 'ngSanitize', 5 | 'ngRoute', 6 | 'ngAnimate', 7 | 'pascalprecht.translate', 8 | 'wert-templates' 9 | ]) 10 | .config(function ($routeProvider, $compileProvider) { 11 | $compileProvider 12 | .aHrefSanitizationWhitelist(/^\s*(https?|data|blob):/); 13 | 14 | $routeProvider 15 | .when('/', { 16 | templateUrl: 'views/start.html', 17 | controller: 'StartCtrl' 18 | }) 19 | .when('/evaluation/scope', { 20 | templateUrl: 'views/evaluation/scope.html', 21 | controller: 'EvalScopeCtrl' 22 | }) 23 | .when('/evaluation/explore', { 24 | templateUrl: 'views/evaluation/explore.html', 25 | controller: 'EvalExploreCtrl' 26 | }) 27 | .when('/evaluation/sample', { 28 | templateUrl: 'views/evaluation/sample.html', 29 | controller: 'EvalSampleCtrl' 30 | }) 31 | .when('/evaluation/audit', { 32 | templateUrl: 'views/evaluation/audit.html', 33 | controller: 'EvalAuditCtrl' 34 | }) 35 | .when('/evaluation/report', { 36 | templateUrl: 'views/evaluation/report.html', 37 | controller: 'EvalReportCtrl' 38 | }) 39 | .when('/view_report', { 40 | templateUrl: 'views/viewReport.html', 41 | controller: 'ViewReportCtrl' 42 | }) 43 | .when('/open', { 44 | templateUrl: 'views/open.html', 45 | controller: 'OpenCtrl' 46 | }) 47 | .when('/save', { 48 | templateUrl: 'views/save.html', 49 | controller: 'SaveCtrl' 50 | }) 51 | .when('/error', { 52 | templateUrl: 'views/error.html' 53 | }) 54 | .when('/import', { 55 | templateUrl: 'views/import.html', 56 | controller: 'ImportCtrl' 57 | }) 58 | .otherwise({ 59 | redirectTo: '/error' 60 | }); 61 | }); 62 | -------------------------------------------------------------------------------- /app/scripts/app.language.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('wcagReporter') 4 | .value('supportedLanguages', [ 5 | { 6 | code: 'en', 7 | localName: 'English' 8 | }, 9 | { 10 | code: 'nl', 11 | localName: 'Nederlands' 12 | } 13 | ]) 14 | .config(function ($translateProvider, wcag2specProvider) { 15 | var lang; 16 | function createCookie (name, value) { 17 | document.cookie = name + '=' + value + '; path=/'; 18 | } 19 | 20 | function readCookie (name) { 21 | var nameEQ = name + '='; 22 | var ca = document.cookie.split(';'); 23 | for (var i = 0; i < ca.length; i++) { 24 | var c = ca[i]; 25 | while (c.charAt(0) == ' ') c = c.substring(1, c.length); 26 | if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length); 27 | } 28 | return null; 29 | } 30 | 31 | try { 32 | lang = readCookie('wcagReporter-lang'); 33 | if (!lang) { 34 | lang = jQuery('*[ng-app="wcagReporter"]') 35 | .attr('lang') || 'en'; 36 | lang = lang.substr(0, 2); 37 | createCookie('wcagReporter-lang', lang); 38 | } 39 | } catch (e) { 40 | lang = 'en'; 41 | } 42 | 43 | $translateProvider.useSanitizeValueStrategy(null); 44 | $translateProvider.useStaticFilesLoader({ 45 | prefix: 'locale/', 46 | suffix: '.json' 47 | }); 48 | 49 | wcag2specProvider.setSpecPath('wcag2spec/wcag2-${lang}.json'); 50 | wcag2specProvider.loadLanguage(lang); 51 | $translateProvider.preferredLanguage(lang); 52 | }) 53 | .run(function ($rootScope, $rootElement, translateFilter) { 54 | $rootScope.translate = translateFilter; 55 | 56 | $rootElement.addClass('app-loading'); 57 | $rootScope.$on('$translateChangeSuccess', function (e, change) { 58 | // Update the lang data 59 | $rootElement.attr('lang', change.language); 60 | $rootScope.lang = change.language; 61 | $rootElement.removeClass('app-loading'); 62 | }); 63 | }); 64 | -------------------------------------------------------------------------------- /app/scripts/controllers/evaluation/audit.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('wcagReporter') 4 | .controller('EvalAuditCtrl', function ($scope, appState) { 5 | $scope.state = appState.moveToState('audit'); 6 | }); 7 | -------------------------------------------------------------------------------- /app/scripts/controllers/evaluation/audit/samplePages.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('wcagReporter') 4 | .controller( 5 | 'AuditSamplePagesCtrl', 6 | function ($scope, evalSampleModel, Page, $rootScope) { 7 | var getSelected = evalSampleModel.getSelectedPages; 8 | var getPages = evalSampleModel.getPages; 9 | 10 | $scope.structuredSample = evalSampleModel.structuredSample; 11 | $scope.randomSample = evalSampleModel.randomSample; 12 | 13 | $scope.filledPages = function () { 14 | return evalSampleModel.getFilledPages(); 15 | }; 16 | 17 | $scope.auditSize = getSelected.length; 18 | $scope.anySelect = $scope.auditSize !== 0; 19 | 20 | $scope.openSelected = function () { 21 | getSelected() 22 | .forEach(function (page) { 23 | Page.openInWindow(page); 24 | }); 25 | }; 26 | 27 | $scope.openPage = Page.openInWindow; 28 | 29 | $scope.changeAll = function () { 30 | var pages = getPages(); 31 | pages.forEach(function (page) { 32 | page.selected = $scope.anySelect; 33 | }); 34 | $scope.sampleChange(); 35 | }; 36 | 37 | var previousSelection; 38 | $scope.multiSelect = function (index, event) { 39 | if (event.toElement.nodeName.toLowerCase() !== 'input') { 40 | return; 41 | } 42 | 43 | if (typeof previousSelection !== 'undefined' && event.shiftKey) { 44 | var pages = evalSampleModel.getFilledPages(); 45 | var start = Math.min(previousSelection, index); 46 | var end = Math.max(previousSelection, index); 47 | var state = pages[index].selected; 48 | 49 | for (var i = start; i <= end; i++) { 50 | pages[i].selected = state; 51 | } 52 | $scope.sampleChange(); 53 | } 54 | previousSelection = index; 55 | }; 56 | 57 | $scope.sampleChange = function () { 58 | var selected = getSelected().length; 59 | $scope.auditSize = selected; 60 | $scope.anySelect = selected > 0; 61 | $rootScope.$broadcast('audit:sample-change'); 62 | }; 63 | 64 | $scope.completePages = function () { 65 | getSelected() 66 | .forEach(function (page) { 67 | page.tested = true; 68 | }); 69 | }; 70 | 71 | $scope.uncompletePages = function () { 72 | getSelected() 73 | .forEach(function (page) { 74 | page.tested = false; 75 | }); 76 | }; 77 | } 78 | ); 79 | -------------------------------------------------------------------------------- /app/scripts/controllers/evaluation/report.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('wcagReporter') 4 | .controller( 5 | 'EvalReportCtrl', 6 | function ($scope, appState, evalReportModel) { 7 | $scope.state = appState.moveToState('report'); 8 | $scope.reportModel = evalReportModel; 9 | } 10 | ); 11 | -------------------------------------------------------------------------------- /app/scripts/controllers/evaluation/sample.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('wcagReporter') 4 | .controller( 5 | 'EvalSampleCtrl', 6 | function ( 7 | $scope, 8 | appState, 9 | evalExploreModel, 10 | evalSampleModel, 11 | evalAuditModel 12 | ) { 13 | $scope.state = appState.moveToState('sample'); 14 | 15 | $scope.structuredSample = evalSampleModel.structuredSample; 16 | $scope.randomSample = evalSampleModel.randomSample; 17 | 18 | $scope.exploreModel = evalExploreModel; 19 | 20 | if ($scope.structuredSample && 21 | $scope.structuredSample.webpage.length === 0) { 22 | var strPage = evalSampleModel.addNewStructuredPage(); 23 | evalAuditModel.addPageForAsserts(strPage); 24 | 25 | if ($scope.randomSample && 26 | $scope.randomSample.webpage.length === 0) { 27 | var rndPage = evalSampleModel.addNewRandomPage(); 28 | evalAuditModel.addPageForAsserts(rndPage); 29 | } 30 | } 31 | 32 | $scope.getPageAdder = function (sample) { 33 | return function () { 34 | var strPage = evalSampleModel.addNewPage(sample); 35 | evalAuditModel.addPageForAsserts(strPage); 36 | var strSize = $scope.structuredSample.webpage.length; 37 | 38 | // Add a random page if it's one off 39 | var randomSampleSize = Math.ceil(strSize / 10); 40 | if ($scope.randomSample.webpage.length + 1 === randomSampleSize && 41 | strSize % 10 === 1) { 42 | var rndPage = evalSampleModel 43 | .addNewPage($scope.randomSample); 44 | evalAuditModel.addPageForAsserts(rndPage); 45 | } 46 | 47 | return strPage; 48 | }; 49 | }; 50 | 51 | $scope.getPageRemover = function (sample) { 52 | return function (index) { 53 | var page = evalSampleModel.removePage(sample, index); 54 | evalAuditModel.removePageFromAsserts(page); 55 | }; 56 | }; 57 | 58 | $scope.randPageCount = function () { 59 | return Math 60 | .ceil($scope.structuredSample.webpage.length / 10); 61 | }; 62 | } 63 | ); 64 | -------------------------------------------------------------------------------- /app/scripts/controllers/evaluation/scope.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('wcagReporter') 4 | .controller( 5 | 'EvalScopeCtrl', 6 | function ( 7 | $scope, 8 | appState, 9 | evalScopeModel, 10 | evalReportModel, 11 | $filter 12 | ) { 13 | $scope.state = appState.moveToState('scope'); 14 | $scope.scopeModel = evalScopeModel; 15 | 16 | $scope.wcagVersionOptions = evalScopeModel.wcagVersionOptions 17 | .reduce(function (versions, version) { 18 | var translateKey = 'SCOPE.' + version; 19 | 20 | versions[version] = $filter('translate')(translateKey); 21 | 22 | return versions; 23 | }, {}); 24 | 25 | $scope.conformanceOptions = evalScopeModel.conformanceOptions 26 | .reduce(function (tgt, lvl) { 27 | tgt[lvl] = $filter('rdfToLabel')(lvl); 28 | return tgt; 29 | }, {}); 30 | 31 | // Give the report a default title 32 | // (won't if one is already set) 33 | $scope.$on('$routeChangeStart', function () { 34 | if (evalScopeModel.website.siteName) { 35 | var translate = $filter('translate'); 36 | var siteName = translate('REPORT.TITLE_PREFIX') + ' ' + 37 | evalScopeModel.website.siteName; 38 | evalReportModel.setDefaultTitle(siteName); 39 | } 40 | }); 41 | } 42 | ); 43 | -------------------------------------------------------------------------------- /app/scripts/controllers/footer.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('wcagReporter') 4 | .controller( 5 | 'FooterCtrl', 6 | function ($scope, pkgData) { 7 | $scope.pkg = pkgData; 8 | } 9 | ); 10 | -------------------------------------------------------------------------------- /app/scripts/controllers/navigation.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('wcagReporter') 4 | .controller( 5 | 'NavigationCtrl', 6 | function ($scope, $rootScope, supportedLanguages, changeLanguage) { 7 | $scope.languages = supportedLanguages; 8 | $scope.currentLang = $rootScope.lang; 9 | 10 | $rootScope.$on('$translateChangeSuccess', function (e, change) { 11 | $scope.currentLang = change.language.toLowerCase(); 12 | }); 13 | 14 | $scope.changeLanguage = changeLanguage; 15 | } 16 | ); 17 | -------------------------------------------------------------------------------- /app/scripts/controllers/open.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('wcagReporter') 4 | .controller('OpenCtrl', function ($scope, reportStorage, evalLoader, $rootScope) { 5 | $scope.postSettings = reportStorage.settings; 6 | $scope.fileFeedback = { 7 | posted: false, failures: false 8 | }; 9 | $scope.evalFile = ''; 10 | 11 | $scope.urlFeedback = { 12 | posted: false, failures: false 13 | }; 14 | 15 | function handleLoad (defer, feedback) { 16 | feedback.posted = true; 17 | feedback.failure = false; 18 | 19 | defer.then(function success () { 20 | feedback.posted = false; 21 | $rootScope.setEvalLocation(); 22 | }, function error (e) { 23 | feedback.posted = false; 24 | if (e.message) { 25 | feedback.failure = e.message; 26 | } else { 27 | feedback.failure = e; 28 | } 29 | }); 30 | } 31 | 32 | $scope.loadFile = function (filePath) { 33 | var uploadResponse = evalLoader.openFromFile(filePath); 34 | handleLoad(uploadResponse, $scope.fileFeedback); 35 | }; 36 | 37 | $scope.loadUrl = function () { 38 | handleLoad(evalLoader.openFromUrl($scope.postSettings.url), $scope.urlFeedback); 39 | }; 40 | 41 | $scope.updateSettings = function () { 42 | reportStorage.updateSettings(); 43 | }; 44 | }); 45 | -------------------------------------------------------------------------------- /app/scripts/controllers/report/findings.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('wcagReporter') 4 | .controller( 5 | 'ReportFindingsCtrl', 6 | function ($scope, wcag2spec, evalAuditModel, evalScopeModel, CriterionAssert) { 7 | if (wcag2spec.isLoaded()) { 8 | $scope.principles = wcag2spec.getPrinciples(); 9 | } else { 10 | $scope.principles = []; 11 | wcag2spec.onLangChange(function () { 12 | $scope.principles = wcag2spec.getPrinciples(); 13 | }); 14 | } 15 | 16 | $scope.auditModel = evalAuditModel; 17 | $scope.critOpt = { 18 | editable: false, 19 | collapsed: false, 20 | showallpages: false, 21 | hideCollapseBtn: true 22 | }; 23 | 24 | $scope.getCritAssert = evalAuditModel.getCritAssert; 25 | $scope.shouldCritRender = function (critSpec) { 26 | if (evalScopeModel.matchConformTarget(critSpec.level)) { 27 | return true; 28 | } else { 29 | var critAssert = $scope.getCritAssert(critSpec.id); 30 | return CriterionAssert.isDefined(critAssert); 31 | } 32 | }; 33 | } 34 | ); 35 | -------------------------------------------------------------------------------- /app/scripts/controllers/report/score.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('wcagReporter') 4 | .controller('ReportScoreCtrl', function ($scope, wcag2spec, evalAuditModel) { 5 | $scope.principles = wcag2spec.getPrinciples(); 6 | var totals = { 7 | 'earl:passed': 0, 8 | 'earl:failed': 0, 9 | 'earl:inapplicable': 0, 10 | 'earl:untested': 0, 11 | 'earl:cantTell': 0, 12 | level_a: { pass: 0, total: 0 }, 13 | level_aa: { pass: 0, total: 0 }, 14 | level_aaa: { pass: 0, total: 0 } 15 | }; 16 | $scope.totals = totals; 17 | 18 | $scope.getScores = function () { 19 | return wcag2spec.getPrinciples() 20 | .map(function (p) { 21 | var result = { 22 | name: p.num + '. ' + p.handle, 23 | 'earl:passed': 0, 24 | 'earl:failed': 0, 25 | 'earl:inapplicable': 0, 26 | 'earl:untested': 0, 27 | 'earl:cantTell': 0, 28 | tested: 0, 29 | level_a: { pass: 0, total: 0 }, 30 | level_aa: { pass: 0, total: 0 }, 31 | level_aaa: { pass: 0, total: 0 } 32 | }; 33 | 34 | // Get all criteria of this principle: 35 | p.guidelines.reduce(function (list, guide) { 36 | list.push.apply(list, guide.successcriteria); 37 | return list; 38 | }, []) 39 | .forEach(function (crit) { 40 | // For each, set the result 41 | var critResult = evalAuditModel.getCritAssert(crit.id); 42 | if (critResult) { 43 | var outcome = critResult.result.outcome; 44 | 45 | var level = crit.level 46 | .replace('wai:WCAG2', '') 47 | .replace('-Conformance', '') 48 | .toLowerCase(); 49 | 50 | result[outcome] += 1; 51 | $scope.totals[outcome] += 1; 52 | if (outcome === 'earl:passed' || 53 | outcome === 'earl:inapplicable') { 54 | result['level_' + level].pass += 1; 55 | totals['level_' + level].pass += 1; 56 | } 57 | if (outcome !== 'earl:untested') { 58 | result.tested += 1; 59 | result['level_' + level].total += 1; 60 | totals['level_' + level].total += 1; 61 | } 62 | } 63 | }); 64 | return result; 65 | }); 66 | }; 67 | 68 | $scope.scores = $scope.getScores(); 69 | // Update the score name when the language changes 70 | $scope.$on('wcag2spec:langChange', function () { 71 | $scope.scores = $scope.getScores(); 72 | }); 73 | }); 74 | -------------------------------------------------------------------------------- /app/scripts/controllers/save.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('wcagReporter') 4 | .controller('SaveCtrl', function ($scope, wcagReporterExport, appState) { 5 | $scope.exportUrl = wcagReporterExport.getBlobUrl(); 6 | $scope.exportFile = wcagReporterExport.getFileName(); 7 | $scope.postSettings = wcagReporterExport.storage.settings; 8 | $scope.posted = false; 9 | $scope.failure = false; 10 | $scope.success = false; 11 | 12 | $scope.postJson = function () { 13 | $scope.posted = true; 14 | $scope.failure = false; 15 | 16 | wcagReporterExport.saveToUrl() 17 | .then(function () { 18 | $scope.success = true; 19 | $scope.posted = false; 20 | }, function (data) { 21 | $scope.failure = (data || true); 22 | $scope.posted = false; 23 | }); 24 | }; 25 | 26 | $scope.downloadStart = function () { 27 | wcagReporterExport.saveBlobIE(); 28 | appState.setPrestineState(); 29 | }; 30 | 31 | $scope.updateSettings = function () { 32 | wcagReporterExport.storage.updateSettings(); 33 | }; 34 | }); 35 | -------------------------------------------------------------------------------- /app/scripts/controllers/start.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('wcagReporter') 4 | .controller( 5 | 'StartCtrl', 6 | function ($scope, $location, appState, $timeout, $rootScope) { 7 | $scope.state = appState.moveToState('start'); 8 | 9 | if (typeof $rootScope.rootHide.start1 === 'undefined') { 10 | $scope.initial = 'hidden'; 11 | $timeout(function () { 12 | $scope.initial = ''; 13 | }, 500); 14 | $timeout(function () { 15 | $rootScope.rootHide.start1 = false; 16 | }, 700); 17 | } 18 | 19 | $scope.nextStep = function () { 20 | $location.path('/evaluation/scope'); 21 | }; 22 | 23 | $scope.nextStepName = 'STEP_SCOPE'; 24 | } 25 | ); 26 | -------------------------------------------------------------------------------- /app/scripts/controllers/stepButtons.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('wcagReporter') 4 | .controller( 5 | 'StepButtonsCtrl', 6 | function ($scope, $location, appState) { 7 | var previous = appState.getPreviousState(); 8 | var next = appState.getNextState(); 9 | 10 | if (next) { 11 | $scope.nextStep = function () { 12 | $location.path(next.route); 13 | }; 14 | $scope.nextStepName = 'STEP_' + (next.name).toUpperCase(); 15 | } 16 | 17 | if (previous) { 18 | $scope.previousStep = function () { 19 | $location.path(previous.route); 20 | }; 21 | $scope.previousStepName = 'STEP_' + (previous.name).toUpperCase(); 22 | } 23 | } 24 | ); 25 | -------------------------------------------------------------------------------- /app/scripts/controllers/viewReport.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('wcagReporter') 4 | .controller('ViewReportCtrl', function ( 5 | $scope, 6 | $document, 7 | wcag2spec, 8 | evalModel, 9 | appState, 10 | wcagReporterExport, 11 | toggleCriterionText 12 | ) { 13 | var htmlBlob; 14 | 15 | $scope.state = appState.moveToState('viewReport'); 16 | $scope.scope = evalModel.scopeModel; 17 | $scope.explore = evalModel.exploreModel; 18 | 19 | $scope.filledPages = function () { 20 | return evalModel.sampleModel.getFilledPages(); 21 | }; 22 | 23 | $scope.wcag2specReady = wcag2spec.isLoaded(); 24 | $scope.$on('wcag2spec:langChange', function () { 25 | $scope.wcag2specReady = true; 26 | }); 27 | 28 | $scope.report = evalModel.reportModel; 29 | var tpl = [ 30 | '' + 31 | '' + 32 | '' + evalModel.reportModel.title + '' + 33 | '' + 35 | '' + 36 | '' + 37 | '
', 38 | '
' 39 | ]; 40 | 41 | $scope.$on('reportReady', function (e, data) { 42 | var html = tpl[0] + data.html() + tpl[1]; 43 | 44 | htmlBlob = wcagReporterExport.getBlob(html, 'text/html;charset=utf-8'); 45 | $document.find('#html_download_link') 46 | .attr( 47 | 'href', 48 | wcagReporterExport.getBlobUrl(htmlBlob) 49 | ); 50 | }); 51 | 52 | $scope.downloadJsonStart = function () { 53 | wcagReporterExport.saveBlobIE(); 54 | appState.setPrestineState(); 55 | }; 56 | 57 | $scope.saveHtmlBlobIE = function () { 58 | if (htmlBlob) { 59 | wcagReporterExport.saveBlobIE(htmlBlob, $scope.exportHtmlFile); 60 | } 61 | }; 62 | 63 | $scope.exportHtmlFile = wcagReporterExport.getFileName('html'); 64 | $scope.exportJsonUrl = wcagReporterExport.getBlobUrl(); 65 | $scope.exportJsonFile = wcagReporterExport.getFileName(); 66 | }); 67 | -------------------------------------------------------------------------------- /app/scripts/directives/autoResize.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | angular.module('wcagReporter') 3 | .directive('autoResize', function (directivePlugin) { 4 | return directivePlugin({ 5 | restrict: 'A', 6 | link: function (scope, element) { 7 | scope.$evalAsync(function () { 8 | angular.element(element) 9 | .textareaAutoSize(); 10 | }); 11 | } 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /app/scripts/directives/buttonCollapse.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | angular.module('wcagReporter') 3 | .directive('buttonCollapse', function (directivePlugin) { 4 | return directivePlugin({ 5 | restrict: 'E', 6 | replace: true, 7 | transclude: true, 8 | scope: { 9 | obj: '=target', 10 | prop: '@property' 11 | }, 12 | link: function (scope, elm, attr) { 13 | // If collapsed and the property is not defined, set the default to collapse 14 | if (attr.collapsed !== undefined && scope.obj[scope.prop] === undefined) { 15 | scope.obj[scope.prop] = true; 16 | } 17 | }, 18 | templateUrl: 'views/directives/buttonCollapse.html' 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /app/scripts/directives/collapse.js: -------------------------------------------------------------------------------- 1 | // Based on the work from the great guys at bootstrap UI. 2 | 'use strict'; 3 | angular.module('wcagReporter') 4 | .directive('collapse', [ 5 | '$animate', 6 | function ($animate) { 7 | return { 8 | link: function (scope, element, attrs) { 9 | var initialAnimSkip = true; 10 | var currentTransition; 11 | 12 | function doTransition (change) { 13 | var fromState = {}; 14 | Object.keys(change) 15 | .forEach(function (cssProp) { 16 | fromState[cssProp] = element.css(cssProp); 17 | }); 18 | 19 | var newTransition = $animate.animate(element, fromState, change); 20 | if (currentTransition) { 21 | $animate.cancel(currentTransition); 22 | } 23 | 24 | currentTransition = newTransition; 25 | newTransition.then(newTransitionDone, newTransitionDone); 26 | return newTransition; 27 | 28 | function newTransitionDone () { 29 | // Make sure it's this transition, otherwise, leave it alone. 30 | if (currentTransition === newTransition) { 31 | currentTransition = undefined; 32 | } 33 | } 34 | } 35 | 36 | function expand () { 37 | if (initialAnimSkip) { 38 | initialAnimSkip = false; 39 | expandDone(); 40 | } else { 41 | element.removeClass('collapse') 42 | .addClass('collapsing'); 43 | doTransition({ height: element[0].scrollHeight + 'px' }) 44 | .then(expandDone); 45 | } 46 | } 47 | 48 | function expandDone () { 49 | element.removeClass('collapsing'); 50 | element.addClass('collapse in'); 51 | element.css({ height: 'auto' }); 52 | } 53 | 54 | function collapse () { 55 | if (initialAnimSkip) { 56 | initialAnimSkip = false; 57 | collapseDone(); 58 | element.css({ height: 0 }); 59 | } else { 60 | // CSS transitions don't work with height: auto, so we have to manually change the height to a specific value 61 | element.css({ height: element[0].scrollHeight + 'px' }); 62 | // trigger reflow so a browser realizes that height was updated from auto to a specific value 63 | var x = element[0].offsetWidth; 64 | 65 | element.removeClass('collapse in') 66 | .addClass('collapsing'); 67 | 68 | doTransition({ height: 0 }) 69 | .then(collapseDone); 70 | } 71 | } 72 | 73 | function collapseDone () { 74 | element.removeClass('collapsing'); 75 | element.addClass('collapse'); 76 | } 77 | 78 | scope.$watch(attrs.collapse, function (shouldCollapse) { 79 | if (shouldCollapse) { 80 | collapse(); 81 | } else { 82 | expand(); 83 | } 84 | }); 85 | } 86 | }; 87 | } 88 | ]); 89 | -------------------------------------------------------------------------------- /app/scripts/directives/criterion/criterionBody.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | angular.module('wcagReporter') 3 | .directive('criterionBody', function (directivePlugin, evalSampleModel, selectedCasesOnlyFilter) { 4 | function singlePageAssert (scope) { 5 | var pages = evalSampleModel.getFilledPages(); 6 | var asserts = scope.criterion.getSinglePageAsserts(); 7 | 8 | if (scope.opt.editable) { 9 | return selectedCasesOnlyFilter(asserts) 10 | .sort(function (assertA, assertB) { 11 | return pages.indexOf(assertA.subject[0]) - pages.indexOf(assertB.subject[0]); 12 | }); 13 | } else { 14 | return asserts.filter(function (assert) { 15 | return assert.isDefined(); 16 | }) 17 | .sort(function (assertA, assertB) { 18 | return pages.indexOf(assertA.subject[0]) - pages.indexOf(assertB.subject[0]); 19 | }); 20 | } 21 | } 22 | 23 | return directivePlugin({ 24 | restrict: 'E', 25 | replace: true, 26 | transclude: true, 27 | scope: { 28 | criterion: '=assert', 29 | opt: '=options' 30 | }, 31 | 32 | controller: [ 33 | '$scope', 34 | function ($scope) { 35 | if ($scope.opt.editable) { 36 | $scope.criterion.setCaseForEachPage(); 37 | } 38 | 39 | $scope.$on('audit:sample-change', function () { 40 | $scope.multiPageAsserts = $scope.criterion.getMultiPageAsserts(); 41 | $scope.singlePageAsserts = singlePageAssert($scope); 42 | }); 43 | } 44 | ], 45 | 46 | link: function (scope) { 47 | scope.showBody = function () { 48 | return scope.multiPageAsserts.length > 0 || 49 | scope.singlePageAsserts.length > 0 || 50 | scope.opt.editable; 51 | }; 52 | 53 | scope.multiPageAsserts = scope.criterion.getMultiPageAsserts(); 54 | scope.singlePageAsserts = singlePageAssert(scope); 55 | 56 | scope.hasMultipage = false; 57 | scope.addMultiPage = function () { 58 | scope.criterion.addTestCaseAssertion({ 59 | multiPage: true, 60 | subject: evalSampleModel.getSelectedPages() 61 | }); 62 | scope.multiPageAsserts = scope.criterion.getMultiPageAsserts(); 63 | }; 64 | }, 65 | templateUrl: 'views/directives/criterion/criterionBody.html' 66 | }); 67 | }); 68 | -------------------------------------------------------------------------------- /app/scripts/directives/criterion/earlAssert.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | angular.module('wcagReporter') 3 | .directive( 4 | 'earlAssert', 5 | function ($filter, directivePlugin, CriterionAssert, $rootScope) { 6 | function getOutcomes () { 7 | return [ 8 | 'earl:untested', 9 | 'earl:passed', 10 | 'earl:failed', 11 | 'earl:inapplicable', 12 | 'earl:cantTell' 13 | ] 14 | .map(function (rdfId) { 15 | return { 16 | id: rdfId, 17 | name: $filter('rdfToLabel')(rdfId) 18 | }; 19 | }); 20 | } 21 | 22 | return directivePlugin({ 23 | restrict: 'E', 24 | replace: true, 25 | transclude: true, 26 | scope: { 27 | opt: '=options', 28 | assert: '=' 29 | }, 30 | link: function (scope) { 31 | scope.result = scope.assert.result; 32 | scope.outcomes = getOutcomes(); 33 | scope.updateMetadata = function () { 34 | CriterionAssert.updateMetadata(scope.assert); 35 | }; 36 | 37 | scope.getStaticHtmlResult = function (text) { 38 | text = ('' + text).trim() || '–'; 39 | return '

' + $filter('translate')('HTML_REPORT.LABEL_DESCR') + ': ' + 40 | $filter('txtToHtml')(text) 41 | .substr(3); 42 | }; 43 | scope.htmlResult = scope.getStaticHtmlResult(scope.result.description); 44 | }, 45 | templateUrl: 'views/directives/criterion/earlAssert.html' 46 | }); 47 | } 48 | ); 49 | -------------------------------------------------------------------------------- /app/scripts/directives/criterion/macroResults.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | angular.module('wcagReporter') 3 | .directive('macroResults', function (directivePlugin) { 4 | return directivePlugin({ 5 | restrict: 'E', 6 | replace: true, 7 | scope: { 8 | criterion: '=value', 9 | asserts: '=', 10 | opt: '=options' 11 | }, 12 | 13 | link: function (scope) { 14 | scope.removeAssert = function (assert) { 15 | var index = scope.criterion.hasPart.indexOf(assert); 16 | if (index >= 0) { 17 | scope.criterion.hasPart.splice(index, 1); 18 | } 19 | index = scope.asserts.indexOf(assert); 20 | if (index >= 0) { 21 | scope.asserts.splice(index, 1); 22 | } 23 | }; 24 | 25 | scope.transferMacroData = function (macroAssert) { 26 | // Get all single page asserts where a tag is part of this macro assert 27 | scope.criterion.transferMacroData(macroAssert); 28 | scope.removeAssert(macroAssert); 29 | }; 30 | 31 | scope.getAllTitles = function (assert) { 32 | return assert.subject.map(function (page) { 33 | return page.displayTitle(); 34 | }) 35 | .join(', '); 36 | }; 37 | }, 38 | templateUrl: 'views/directives/criterion/macroResults.html' 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /app/scripts/directives/criterion/pageResults.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | angular.module('wcagReporter') 3 | .directive('pageResults', function (directivePlugin) { 4 | return directivePlugin({ 5 | restrict: 'E', 6 | replace: true, 7 | scope: { 8 | criterion: '=value', 9 | asserts: '=', 10 | opt: '=options' 11 | }, 12 | link: function (scope) { 13 | scope.createMacro = function (assert) { 14 | scope.criterion.addTestCaseAssertion({ 15 | result: { 16 | description: assert.result.description, 17 | outcome: assert.result.outcome 18 | }, 19 | multiPage: true 20 | }); 21 | }; 22 | }, 23 | templateUrl: 'views/directives/criterion/pageResults.html' 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /app/scripts/directives/criterion/pageSelect.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | angular.module('wcagReporter') 3 | .directive('pageSelect', function (directivePlugin, evalSampleModel) { 4 | var sample; 5 | return directivePlugin({ 6 | restrict: 'E', 7 | replace: true, 8 | scope: { 9 | pages: '=' 10 | }, 11 | controller: [ 12 | '$scope', 13 | function ($scope) { 14 | $scope.updateSampleList = function () { 15 | $scope.unselectedPages = sample.filter(function (page) { 16 | return $scope.pages.indexOf(page) === -1; 17 | }); 18 | }; 19 | 20 | $scope.removePage = function (page) { 21 | var index = $scope.pages.indexOf(page); 22 | if (index >= 0) { 23 | $scope.pages.splice(index, 1); 24 | $scope.updateSampleList(); 25 | } 26 | }; 27 | 28 | $scope.addPageToAssert = function () { 29 | var page = evalSampleModel.getPageByTitle($scope.newPage); 30 | 31 | if (page && $scope.pages.indexOf(page) === -1) { 32 | $scope.unselectedPages.splice($scope.unselectedPages.indexOf(page), 1); 33 | $scope.pages.push(page); 34 | $scope.newPage = ''; 35 | } 36 | }; 37 | 38 | sample = evalSampleModel.getPages(); 39 | $scope.updateSampleList(); 40 | } 41 | ], 42 | templateUrl: 'views/directives/criterion/pageSelect.html' 43 | }); 44 | }); 45 | -------------------------------------------------------------------------------- /app/scripts/directives/criterion/resultDescription.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | angular.module('wcagReporter') 3 | .directive('resultDescription', function (directivePlugin) { 4 | return directivePlugin({ 5 | restrict: 'E', 6 | replace: true, 7 | scope: { 8 | value: '=', 9 | updateMetadata: '=' 10 | }, 11 | templateUrl: 'views/directives/criterion/resultDescription.html' 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /app/scripts/directives/evaluate/iconButton.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('wcagReporter') 4 | .directive('iconButton', function (directivePlugin) { 5 | return directivePlugin({ 6 | restrict: 'E', 7 | replace: true, 8 | scope: { 9 | label: '=', 10 | icon: '=', 11 | click: '&' 12 | }, 13 | templateUrl: 'views/directives/evaluate/iconButton.html' 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /app/scripts/directives/evaluate/infoButton.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | angular.module('wcagReporter') 3 | .directive('infoButton', function (directivePlugin) { 4 | return directivePlugin({ 5 | restrict: 'E', 6 | scope: { 7 | label: '@', 8 | target: '@' 9 | }, 10 | link: function (scope, elm) { 11 | var tgt; 12 | 13 | elm.on('click', function () { 14 | if (!tgt) { 15 | if (typeof scope.target === 'undefined') { 16 | tgt = elm.next(); 17 | } else { 18 | tgt = angular.element('#' + scope.target); 19 | } 20 | tgt.find('.close') 21 | .on( 22 | 'click', 23 | elm.attr.bind(elm, 'aria-expanded', false) 24 | ); 25 | } 26 | tgt.toggle(200, function () { 27 | tgt.focus(); 28 | elm.attr('aria-expanded', tgt.is(':visible')); 29 | }); 30 | }); 31 | }, 32 | replace: true, 33 | templateUrl: 'views/directives/evaluate/infoButton.html' 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /app/scripts/directives/evaluate/infoField.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | angular.module('wcagReporter') 3 | .directive('infoField', function (directivePlugin, $document) { 4 | /** 5 | * Get the next visible element that can receive focus outside the .alert-info 6 | */ 7 | function getNextFocusElement (elm) { 8 | var selector = ':input:visible, a[href]:visible'; 9 | var focusable = $document.find(selector); 10 | 11 | elm = angular.element(elm) 12 | .closest('.alert-info') 13 | .find(selector) 14 | .last(); 15 | return focusable[focusable.index(elm) + 1]; 16 | } 17 | 18 | return directivePlugin({ 19 | restrict: 'E', 20 | scope: { 21 | ref: '@', 22 | button: '@', 23 | exitto: '@' 24 | }, 25 | link: function (scope, elm) { 26 | elm.hide(0); 27 | scope.close = function ($event) { 28 | var nextElm; 29 | 30 | if ($event.type === 'keyup' && 31 | ($event.keyCode !== 13 && $event.keyCode !== 27)) { 32 | return; 33 | } 34 | if (scope.exitto) { 35 | nextElm = angular.element('#' + scope.exitto); 36 | } 37 | if (!nextElm || nextElm.length === 0) { 38 | nextElm = getNextFocusElement($event.target); 39 | } 40 | nextElm.focus(); 41 | elm.hide(200); 42 | }; 43 | }, 44 | replace: true, 45 | transclude: true, 46 | templateUrl: 'views/directives/evaluate/infoField.html' 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /app/scripts/directives/evaluate/inputPages.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | angular.module('wcagReporter') 3 | .directive('inputPages', function (directivePlugin, $timeout, Page) { 4 | return directivePlugin({ 5 | restrict: 'E', 6 | replace: true, 7 | scope: { 8 | pages: '=', 9 | addPage: '&', 10 | removePage: '&' 11 | }, 12 | link: function (scope) { 13 | var addPageFunc = scope.addPage(); 14 | var removePageFunc = scope.removePage(); 15 | scope.addPage = function ($event) { 16 | var button = angular.element($event.delegateTarget); 17 | addPageFunc(); 18 | 19 | $timeout(function () { 20 | var inputs = button.prev() 21 | .find('input'); 22 | inputs[inputs.length - 2].select(); 23 | }, 100); 24 | }; 25 | 26 | scope.processPage = function (page) { 27 | Page.prependProtocol(page); 28 | Page.updateSource(page); 29 | }; 30 | 31 | scope.removePage = function ($index, $event) { 32 | removePageFunc($index); 33 | // We need this timeout to prevent Angular UI from throwing an error 34 | $timeout(function () { 35 | angular.element($event.delegateTarget) 36 | .closest('fieldset') 37 | .parent() 38 | .children() 39 | .last() 40 | .focus(); 41 | }); 42 | }; 43 | }, 44 | templateUrl: 'views/directives/evaluate/inputPages.html' 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /app/scripts/directives/evaluate/techSelect.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('wcagReporter') 4 | .directive('techSelect', function () { 5 | var knownTechnologies = [ 6 | { title: 'HTML5', specs: 'http://www.w3.org/TR/html5/' }, 7 | { title: 'CSS', specs: 'http://www.w3.org/Style/CSS/specs/' }, 8 | { title: 'HTML 4.01', specs: 'http://www.w3.org/TR/html401/' } 9 | ]; 10 | 11 | function updateTech (reliedUponTech, prop1, prop2) { 12 | knownTechnologies.forEach(function (tech) { 13 | if (reliedUponTech[prop1] === tech[prop1]) { 14 | reliedUponTech[prop2] = tech[prop2]; 15 | } 16 | }); 17 | } 18 | 19 | return { 20 | restrict: 'E', 21 | replace: true, 22 | scope: { selected: '=' }, 23 | link: function (scope) { 24 | scope.technolgies = knownTechnologies; 25 | scope.updateTitle = function (select) { 26 | updateTech(select, 'specs', 'title'); 27 | }; 28 | scope.updateSpec = function (select) { 29 | updateTech(select, 'title', 'specs'); 30 | }; 31 | }, 32 | templateUrl: 'views/directives/evaluate/techSelect.html' 33 | }; 34 | }); 35 | -------------------------------------------------------------------------------- /app/scripts/directives/fullReport.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | angular.module('wcagReporter') 3 | .directive('fullReport', function (directivePlugin, $interval) { 4 | function testFilter (element) { 5 | return function (query) { 6 | return element.find(query).length === 0; 7 | }; 8 | } 9 | 10 | return directivePlugin({ 11 | restrict: 'E', 12 | replace: true, 13 | link: function (scope, element) { 14 | var tests = [ 15 | '.panel-heading', 16 | '.sample_narrow', 17 | '.score-total' 18 | ]; 19 | var stop = $interval(function () { 20 | tests = tests.filter(testFilter(element)); 21 | if (tests.length === 0) { 22 | scope.$emit('reportReady', element); 23 | $interval.cancel(stop); 24 | } 25 | }, 200); 26 | }, 27 | templateUrl: 'views/directives/fullReport.html' 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /app/scripts/directives/shyPlaceholder.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | angular.module('wcagReporter') 3 | .directive('shyPlaceholder', function (directivePlugin) { 4 | var ph = 'placeholder'; 5 | 6 | return directivePlugin({ 7 | restrict: 'A', 8 | scope: { 9 | shyPlaceholder: '=' 10 | }, 11 | compile: function (elm, attrs) { 12 | return function (scope, elm) { 13 | var phValue = scope.$eval(attrs.shyPlaceholder); 14 | 15 | elm.attr(ph, phValue) 16 | .bind({ 17 | focus: elm.attr.bind(elm, ph, ''), 18 | blur: elm.attr.bind(elm, ph, phValue) 19 | }); 20 | }; 21 | } 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /app/scripts/directives/successCriterion.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('wcagReporter') 4 | .directive('successCriterion', function (directivePlugin, $rootScope, toggleCriterionText) { 5 | var className = { 6 | 'earl:untested': 'untested', 7 | 'earl:passed': 'passed', 8 | 'earl:failed': 'failed', 9 | 'earl:inapplicable': 'inapplicable', 10 | 'earl:cantTell': 'canttell' 11 | }; 12 | 13 | return directivePlugin({ 14 | restrict: 'E', 15 | replace: true, 16 | scope: { 17 | assert: '=assertion', 18 | spec: '=requirement', 19 | opt: '=options' 20 | }, 21 | link: function (scope) { 22 | window.toggleCriterionText = toggleCriterionText; 23 | // scope.outcomes = outcomes; 24 | scope.rootHide = $rootScope.rootHide; 25 | scope.critHide = scope.spec.id + '-cb'; 26 | scope.getClassName = function (state) { 27 | return className[state]; 28 | }; 29 | }, 30 | toggleCriterionText: toggleCriterionText, 31 | templateUrl: 'views/directives/successCriterion.html' 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /app/scripts/filters/getUrl.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | angular.module('wcagReporter') 3 | .filter('getUrl', function () { 4 | var linkReg = /((https?):\/\/)([\da-z\.-]+)\.([a-z\.]{2,6})([\-\w\d@:%_\+.~#?,&\/\/=]+)/g; 5 | 6 | return function (text) { 7 | var match; 8 | if (typeof text === 'string') { 9 | match = text.match(linkReg); 10 | } 11 | if (match) { 12 | return match[0]; 13 | } else { 14 | return false; 15 | } 16 | }; 17 | }); 18 | -------------------------------------------------------------------------------- /app/scripts/filters/rdfToLabel.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('wcagReporter') 4 | .filter('rdfToLabel', function ($filter) { 5 | var rdfToLabel; 6 | var keymap = { 7 | 'earl:passed': 'PASSED', 8 | 'earl:failed': 'FAILED', 9 | 'earl:cantTell': 'CANT_TELL', 10 | 'earl:inapplicable': 'NOT_PRESENT', 11 | 'earl:untested': 'NOT_CHECKED', 12 | A: 'LEVEL_A', 13 | AA: 'LEVEL_AA', 14 | AAA: 'LEVEL_AAA', 15 | 'wai:WCAG2A-Conformance': 'LEVEL_A', 16 | 'wai:WCAG2AA-Conformance': 'LEVEL_AA', 17 | 'wai:WCAG2AAA-Conformance': 'LEVEL_AAA' 18 | }; 19 | 20 | rdfToLabel = function (earl) { 21 | return $filter('translate')('EARL.' + keymap[earl]); 22 | }; 23 | rdfToLabel.keymap = keymap; 24 | rdfToLabel.$stateful = true; 25 | 26 | return rdfToLabel; 27 | }); 28 | -------------------------------------------------------------------------------- /app/scripts/filters/selectedCasesOnly.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('wcagReporter') 4 | .filter('selectedCasesOnly', function () { 5 | function critHasSelectedPages (criterion) { 6 | for (var i = 0; i < criterion.subject.length; i++) { 7 | var page = criterion.subject[i]; 8 | if (page.selected && (page.title || page.description)) { 9 | return true; 10 | } 11 | } 12 | return false; 13 | } 14 | 15 | return function (criterion) { 16 | if (criterion) { 17 | return criterion.filter(critHasSelectedPages); 18 | } 19 | }; 20 | }); 21 | -------------------------------------------------------------------------------- /app/scripts/filters/txtToHtml.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('wcagReporter') 4 | .filter('txtToHtml', function ($filter) { 5 | return function (text) { 6 | if (typeof text !== 'string') { 7 | return ''; 8 | } 9 | return text.split('\n') 10 | .reduce(function (cur, line) { 11 | if (line.trim() === '') { 12 | return cur + '

'; 13 | } else { 14 | line = $filter('linky')(line, '_blank'); 15 | return cur + (cur.substr(-3) === '

' ? '' : '
') + line; 16 | } 17 | }, '

') + '

'; 18 | }; 19 | }); 20 | -------------------------------------------------------------------------------- /app/scripts/models/class/Page.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('wcagReporter') 4 | .service('Page', function ($filter) { 5 | var translateFilter = $filter('translate'); 6 | 7 | function Page () { 8 | this.type = [ 9 | 'TestSubject', 10 | 'WebPage' 11 | ]; 12 | } 13 | 14 | Page.updateSource = function (page) { 15 | var source = $filter('getUrl')(page.description); 16 | if (source) { 17 | page.source = source; 18 | } else { 19 | delete page.source; 20 | } 21 | return source; 22 | }; 23 | 24 | Page.prependProtocol = function (page) { 25 | if (page.description && page.description.match(/^([\da-z\.-]+)\.([a-z\.]{2,6})/)) { 26 | page.description = 'http://' + page.description; 27 | } 28 | }; 29 | 30 | Page.openInWindow = function (page, target) { 31 | target = target || '_blank'; 32 | if (page.source) { 33 | window.open(page.source, target); 34 | } 35 | }; 36 | 37 | Page.prototype = { 38 | type: [ 39 | 'TestSubject', 40 | 'WebPage' 41 | ], 42 | id: '', 43 | description: undefined, 44 | title: '', 45 | tested: false, 46 | selected: false, 47 | displayTitle: function () { 48 | var num = 0; 49 | if (this.title.trim()) { 50 | return this.title; 51 | } else if (this.id.substr(0, 9) === '_:struct_') { 52 | num = +this.id.substr(9); 53 | return translateFilter('SAMPLE.STRUCTURED_PAGE') + ' ' + (num + 1); 54 | } else if (this.id.substr(0, 7) === '_:rand_') { 55 | num = +this.id.substr(7); 56 | return translateFilter('SAMPLE.RANDOM_PAGE') + ' ' + (num + 1); 57 | } else { 58 | return translateFilter('SAMPLE.SAMPLE_PAGE'); 59 | } 60 | } 61 | }; 62 | 63 | return Page; 64 | }); 65 | -------------------------------------------------------------------------------- /app/scripts/models/class/TestCaseAssert.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular 4 | .module('wcagReporter') 5 | .service('TestCaseAssert', function ( 6 | types, 7 | evalSampleModel, 8 | currentUser 9 | ) { 10 | var protoResult = { 11 | type: types.EARL.RESULT.class, 12 | description: '', 13 | outcome: types.EARL.OUTCOME.UNTESTED 14 | }; 15 | 16 | function TestCaseAssert () { 17 | // Copy prototype onto the object - prevents problems with JSON.stringify() 18 | for (var key in TestCaseAssert.prototype) { 19 | if (!this.hasOwnProperty(key)) { 20 | this[key] = TestCaseAssert.prototype[key]; 21 | } 22 | } 23 | 24 | this.subject = []; 25 | this.result = angular.copy(protoResult); 26 | } 27 | 28 | TestCaseAssert.isDefined = function (tc) { 29 | var hasPage = false; 30 | tc.subject.forEach(function (page) { 31 | hasPage = (hasPage || page.title || page.description); 32 | }); 33 | return ((tc.result.description || tc.result.outcome !== protoResult.outcome) && hasPage); 34 | }; 35 | 36 | TestCaseAssert.prototype = { 37 | type: 'Assertion', 38 | assertedBy: currentUser.id, 39 | subject: undefined, 40 | testCase: undefined, 41 | result: undefined, 42 | multiPage: false, 43 | mode: types.EARL.MODE.MANUAL, 44 | isDefined: function () { 45 | return TestCaseAssert.isDefined(this); 46 | }, 47 | 48 | addNewPage: function (page) { 49 | this.subject.push(page); 50 | }, 51 | 52 | removePage: function (i) { 53 | this.subject.splice(i, 1); 54 | }, 55 | 56 | setSubject: function (pages) { 57 | var subject = []; 58 | this.subject = subject; 59 | if (pages && !angular.isArray(pages)) { 60 | pages = [pages]; 61 | } 62 | pages.forEach(function (page) { 63 | if (typeof page === 'string') { 64 | page = evalSampleModel.getPageById(page); 65 | } 66 | if (typeof page === 'object') { 67 | subject.push(page); 68 | } 69 | }); 70 | } 71 | }; 72 | 73 | return TestCaseAssert; 74 | }); 75 | -------------------------------------------------------------------------------- /app/scripts/models/evaluation.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular 4 | .module('wcagReporter') 5 | .factory('evalModel', function ( 6 | evalScopeModel, 7 | evalExploreModel, 8 | evalSampleModel, 9 | evalAuditModel, 10 | evalReportModel, 11 | evalContextV3, 12 | currentUser 13 | ) { 14 | var evalModel = { 15 | id: undefined, 16 | type: 'Evaluation', 17 | context: evalContextV3, 18 | scopeModel: evalScopeModel, 19 | exploreModel: evalExploreModel, 20 | sampleModel: evalSampleModel, 21 | auditModel: evalAuditModel, 22 | reportModel: evalReportModel, 23 | // This array collects data that is outside the evaluation 24 | // For example the author and external rdf data 25 | otherData: [currentUser] 26 | }; 27 | 28 | return evalModel; 29 | }); 30 | -------------------------------------------------------------------------------- /app/scripts/models/evaluation/currentUser.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('wcagReporter') 4 | .service('currentUser', function () { 5 | return { 6 | '@context': { 7 | '@vocab': 'http://xmlns.com/foaf/0.1/', 8 | id: '@id', 9 | type: '@type' 10 | }, 11 | id: '_:evaluator', 12 | type: 'Person', 13 | name: '' 14 | }; 15 | }); 16 | -------------------------------------------------------------------------------- /app/scripts/models/evaluation/explore.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular 4 | .module('wcagReporter') 5 | .service('evalExploreModel', function ( 6 | knownTech, 7 | evalSampleModel 8 | ) { 9 | var exploreModel = { 10 | knownTech: knownTech 11 | }; 12 | var basicProps = [ 13 | 'reliedUponTechnology', 14 | 'essentialFunctionality', 15 | 'pageTypeVariety', 16 | 'commonPages', 17 | 'otherRelevantPages' 18 | ]; 19 | 20 | // add all properties to this 21 | basicProps 22 | .forEach(function (prop) { 23 | exploreModel[prop] = undefined; 24 | }); 25 | 26 | exploreModel.reliedUponTechnology = []; 27 | 28 | exploreModel.importData = function (evalData) { 29 | if (!angular.isArray(evalData.reliedUponTechnology)) { 30 | evalData.reliedUponTechnology = [evalData.reliedUponTechnology]; 31 | } 32 | 33 | basicProps 34 | .forEach(function (prop) { 35 | if (evalData[prop]) { 36 | exploreModel[prop] = evalData[prop]; 37 | } 38 | }); 39 | }; 40 | 41 | exploreModel.exportData = function () { 42 | var exportData = {}; 43 | 44 | basicProps 45 | .forEach(function (prop) { 46 | exportData[prop] = exploreModel[prop]; 47 | }); 48 | 49 | return exportData; 50 | }; 51 | 52 | /** 53 | * Returns an array of errors indicating which (if any) properties are invalid 54 | */ 55 | exploreModel.validate = function () { 56 | return []; 57 | }; 58 | 59 | // Lock up the object, for a little more dev security 60 | Object.preventExtensions(exploreModel); 61 | 62 | return exploreModel; 63 | }); 64 | -------------------------------------------------------------------------------- /app/scripts/models/evaluation/report.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('wcagReporter') 4 | .service('evalReportModel', function ($filter, currentUser) { 5 | var protoModel = { 6 | creator: currentUser, 7 | title: '', 8 | summary: '', 9 | specifics: '', 10 | commissioner: '' 11 | }; 12 | var reportModel = Object.create(protoModel); 13 | protoModel.date = $filter('date')(new Date(), 'longDate'); 14 | 15 | reportModel.exportData = function () { 16 | var res = angular.copy(reportModel); 17 | res.creator = res.creator.id; 18 | return res; 19 | }; 20 | 21 | reportModel.importData = function (evalData) { 22 | Object.keys(protoModel) 23 | .forEach(function (key) { 24 | if (angular.isDefined(evalData[key])) { 25 | reportModel[key] = evalData[key]; 26 | } 27 | }); 28 | }; 29 | 30 | reportModel.setDefaultTitle = function (title) { 31 | if (!reportModel.title) { 32 | reportModel.title = title; 33 | } 34 | }; 35 | 36 | return reportModel; 37 | }); 38 | -------------------------------------------------------------------------------- /app/scripts/models/evaluation/scope.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('wcagReporter') 4 | .service('evalScopeModel', function () { 5 | var scopeModel = { 6 | type: 'EvaluationScope', 7 | wcagVersion: 'WCAG21', 8 | conformanceTarget: 'wai:WCAG2AA-Conformance', 9 | additionalEvalRequirement: '', 10 | website: { 11 | type: [ 12 | 'TestSubject', 13 | 'WebSite' 14 | ], 15 | id: '_:website', 16 | siteName: '', 17 | siteScope: '' 18 | }, 19 | accessibilitySupportBaseline: '' 20 | }; 21 | 22 | scopeModel.exportData = function () { 23 | return { 24 | type: scopeModel.type, 25 | conformanceTarget: scopeModel.conformanceTarget, 26 | additionalEvalRequirement: scopeModel.additionalEvalRequirement, 27 | website: { 28 | type: scopeModel.website.type, 29 | id: scopeModel.website.id, 30 | siteName: scopeModel.website.siteName, 31 | siteScope: scopeModel.website.siteScope 32 | }, 33 | accessibilitySupportBaseline: scopeModel.accessibilitySupportBaseline 34 | }; 35 | }; 36 | 37 | scopeModel.wcagVersionOptions = [ 38 | 'WCAG21', 39 | 'WCAG20' 40 | ]; 41 | 42 | scopeModel.conformanceOptions = [ 43 | 'wai:WCAG2A-Conformance', 44 | 'wai:WCAG2AA-Conformance', 45 | 'wai:WCAG2AAA-Conformance' 46 | ]; 47 | 48 | /** 49 | * Returns an array of errors indicating which (if any) properties are invalid 50 | */ 51 | scopeModel.validate = function () { 52 | return []; 53 | }; 54 | 55 | scopeModel.matchConformTarget = function (level) { 56 | return scopeModel.conformanceTarget.length >= level.length; 57 | }; 58 | 59 | // Lock up the object, for a little more dev security 60 | Object.preventExtensions(scopeModel.website); 61 | Object.preventExtensions(scopeModel); 62 | 63 | return scopeModel; 64 | }); 65 | -------------------------------------------------------------------------------- /app/scripts/models/export.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * 4 | */ 5 | angular.module('wcagReporter') 6 | .factory('wcagReporterExport', function (evalModel, reportStorage, pkgData, $rootScope) { 7 | function getJsonLd () { 8 | var jsonLd = { 9 | '@context': evalModel.context, 10 | type: evalModel.type, 11 | id: evalModel.id, 12 | publisher: 'reporter:releases/tag/' + pkgData.version, 13 | lang: $rootScope.lang 14 | }; 15 | 16 | jsonLd.evaluationScope = evalModel.scopeModel.exportData(); 17 | jsonLd.auditResult = evalModel.auditModel.exportData(); 18 | 19 | angular.extend( 20 | jsonLd, 21 | evalModel.reportModel.exportData(), 22 | evalModel.sampleModel.exportData(), 23 | evalModel.exploreModel.exportData() 24 | ); 25 | 26 | return jsonLd; 27 | } 28 | 29 | var exportModel = { 30 | 31 | storage: reportStorage, 32 | 33 | saveToUrl: function () { 34 | return reportStorage.post(exportModel.getJson()); 35 | }, 36 | 37 | getJson: function () { 38 | return { 39 | '@graph': [getJsonLd()].concat(evalModel.otherData) 40 | }; 41 | }, 42 | 43 | getString: function () { 44 | return angular.toJson(exportModel.getJson(), true); 45 | }, 46 | 47 | getBlobUrl: function (blob) { 48 | try { 49 | blob = blob || exportModel.getBlob(); 50 | return (window.URL || window.webkitURL).createObjectURL(blob); 51 | } catch (e) { 52 | console.error(e); 53 | } 54 | }, 55 | 56 | saveBlobIE: function (blob, filename) { 57 | blob = blob || exportModel.getBlob(); 58 | filename = filename || exportModel.getFileName(); 59 | 60 | if (window.navigator.msSaveOrOpenBlob) { 61 | window.navigator.msSaveBlob(blob, filename); 62 | } 63 | }, 64 | 65 | getBlob: function (data, type) { 66 | data = data || exportModel.getString(); 67 | type = type || 'application/json;charset=utf-8'; 68 | return new Blob([data], { type: type }); 69 | }, 70 | 71 | getFileName: function (ext) { 72 | var title = (evalModel.scopeModel.website.siteName + 73 | ' evaluation report'); 74 | ext = ext || 'json'; 75 | title = title.trim(); 76 | 77 | return title.replace(/(^\-+|[^a-zA-Z0-9\/_| -]+|\-+$)/g, '') 78 | .toLowerCase() 79 | .replace(/[\/_| -]+/g, '-') + '.' + ext; 80 | } 81 | }; 82 | 83 | reportStorage.exportModel = exportModel; 84 | 85 | return exportModel; 86 | }); 87 | -------------------------------------------------------------------------------- /app/scripts/services/changeLanguage.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('wcagReporter') 4 | .service('changeLanguage', function ($translate, wcag2spec, $rootScope) { 5 | function createCookie (name, value) { 6 | document.cookie = name + '=' + value + '; path=/'; 7 | } 8 | 9 | return function changeLanguage (lang) { 10 | if ($rootScope.lang === lang) { 11 | return; 12 | } 13 | 14 | if (document) { 15 | createCookie('wcagReporter-lang', lang); 16 | } 17 | $translate.use(lang); 18 | wcag2spec.loadLanguage(lang); 19 | }; 20 | }); 21 | -------------------------------------------------------------------------------- /app/scripts/services/context/evalContextV1.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('wcagReporter') 4 | .constant('evalContextV1', { 5 | '@vocab': 'http://www.w3.org/TR/WCAG-EM/#', 6 | wcag20: 'http://www.w3.org/TR/WCAG20/#', 7 | earl: 'http://www.w3.org/ns/earl#', 8 | dct: 'http://purl.org/dc/terms/', 9 | reporter: 'https://github.com/w3c/wcag-em-report-tool/blob/master/dataformat.md#', 10 | conformanceTarget: { id: 'step1b', type: 'id' }, 11 | evaluationScope: { id: 'step1' }, 12 | accessibilitySupportBaseline: { id: 'step1c' }, 13 | additionalEvalRequirement: { id: 'step1d' }, 14 | siteScope: { id: 'step1a' }, 15 | commonPages: { id: 'step2a' }, 16 | essentialFunctionality: { id: 'step2b' }, 17 | pageTypeVariety: { id: 'step2c' }, 18 | otherRelevantPages: { id: 'step2e' }, 19 | structuredSample: { id: 'step3a' }, 20 | randomSample: { id: 'step3b' }, 21 | specifics: { id: 'step5b' }, 22 | auditResult: { id: 'step4' }, 23 | outcome: { type: 'id' }, 24 | subject: { type: 'id' }, 25 | assertedBy: { type: 'id' }, 26 | testRequirement: { type: 'id' }, 27 | creator: { type: 'id' }, 28 | handle: 'reporter:handle', 29 | description: 'reporter:description', 30 | tested: 'reporter:tested', 31 | id: '@id', 32 | type: '@type', 33 | title: 'dct:title', 34 | hasPart: 'dct:hasPart', 35 | specs: '@id', 36 | reliedUponTechnology: 'wcag20:reliedupondef' 37 | }); 38 | -------------------------------------------------------------------------------- /app/scripts/services/context/evalContextV3.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular 4 | .module('wcagReporter') 5 | .constant('evalContextV3', { 6 | // Current namespace 7 | '@vocab': 'http://www.w3.org/TR/WCAG-EM/#', 8 | 9 | // Namespaces 10 | reporter: 'https://github.com/w3c/wcag-em-report-tool/', 11 | wcagem: 'http://www.w3.org/TR/WCAG-EM/#', 12 | WCAG2: 'http://www.w3.org/TR/WCAG21/#', 13 | earl: 'http://www.w3.org/ns/earl#', 14 | dct: 'http://purl.org/dc/terms/', 15 | wai: 'http://www.w3.org/WAI/', 16 | sch: 'http://schema.org/', 17 | 18 | // Classes 19 | Evaluation: 'wcagem:Evaluation', 20 | EvaluationScope: 'wcagem:EvaluationScope', 21 | TestSubject: 'earl:TestSubject', 22 | WebSite: 'sch:WebSite', 23 | Sample: 'wcagem:Sample', 24 | WebPage: 'sch:WebPage', 25 | Technology: 'WCAG2:dfn-technologies', 26 | Assertion: 'earl:Assertion', 27 | Assertor: 'earl:Assertor', 28 | TestResult: 'earl:TestResult', 29 | 30 | // Evaluation class properties 31 | title: 'dct:title', 32 | summary: 'dct:summary', 33 | creator: { 34 | '@id': 'dct:creator', 35 | '@type': '@id' 36 | }, 37 | date: 'dct:date', 38 | commissioner: 'wcagem:commissioner', 39 | reliedUponTechnology: 'WCAG2:dfn-relied-upon', 40 | evaluationScope: 'step1', 41 | commonPages: 'step2a', 42 | essentialFunctionality: 'step2b', 43 | pageTypeVariety: 'step2c', 44 | otherRelevantPages: 'step2e', 45 | structuredSample: 'step3a', 46 | randomSample: 'step3b', 47 | auditResult: 'step4', 48 | specifics: 'step5b', 49 | publisher: { 50 | '@id': 'dct:publisher', 51 | '@type': '@id' 52 | }, 53 | 54 | // EvaluationScope class properties 55 | conformanceTarget: { 56 | '@id': 'step1b', 57 | '@type': '@id' 58 | }, 59 | accessibilitySupportBaseline: 'step1c', 60 | additionalEvalRequirement: 'step1d', 61 | website: 'WCAG2:dfn-set-of-web-pages', 62 | 63 | // sch:WebSite class properties 64 | siteScope: 'step1a', 65 | siteName: 'sch:name', 66 | 67 | // Sample class properties 68 | // sch:WebPage class properties 69 | webpage: 'WCAG2:dfn-web-page-s', 70 | description: 'dct:description', 71 | source: { 72 | '@id': 'dct:source', 73 | '@type': '@id' 74 | }, 75 | tested: 'reporter:blob/master/docs/EARL%2BJSON-LD.md#tested', 76 | 77 | // earl:Assertion class properties 78 | test: { 79 | '@id': 'earl:test', 80 | '@type': '@id' 81 | }, 82 | assertedBy: { 83 | '@id': 'earl:assertedBy', 84 | '@type': '@id' 85 | }, 86 | subject: { 87 | '@id': 'earl:subject', 88 | '@type': '@id' 89 | }, 90 | result: 'earl:result', 91 | mode: { 92 | '@id': 'earl:mode', 93 | '@type': '@id' 94 | }, 95 | hasPart: 'dct:hasPart', 96 | 97 | // earl:TestResult class properties 98 | outcome: { 99 | '@id': 'earl:outcome', 100 | '@type': '@id' 101 | }, 102 | 103 | // shorthand, because @ can't be used in dot notation 104 | id: '@id', 105 | type: '@type', 106 | lang: '@language' 107 | }); 108 | -------------------------------------------------------------------------------- /app/scripts/services/directivePlugin.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Allow developers to create plugins for a directive 5 | * 6 | * Fow now, only additional link functions are supported 7 | */ 8 | angular.module('wcagReporter') 9 | .factory('directivePlugin', function () { 10 | var func = function (directive) { 11 | var link = directive.link || function () {}; 12 | 13 | if (!directive.plugins) { 14 | directive.plugins = []; 15 | } 16 | 17 | directive.link = function () { 18 | var args = arguments; 19 | link.apply(undefined, args); 20 | 21 | directive.plugins.forEach(function (plugin) { 22 | if (plugin.link) { 23 | plugin.link.apply(undefined, args); 24 | } 25 | }); 26 | }; 27 | 28 | return directive; 29 | }; 30 | return func; 31 | }); 32 | -------------------------------------------------------------------------------- /app/scripts/services/evalLoader.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('wcagReporter') 4 | .service('evalLoader', function (evalWindow, appState, fileReader, wcagReporterImport, $q) { 5 | function loadFactory (promiseGen) { 6 | var importTarget; 7 | 8 | return function () { 9 | var promise = promiseGen.apply(null, arguments); 10 | var defer = $q.defer(); 11 | 12 | function reject (e) { 13 | defer.reject(e); 14 | if (importTarget) { 15 | importTarget.abort(); 16 | } 17 | } 18 | 19 | if (!appState.empty) { 20 | try { 21 | importTarget = evalWindow.openEmptyWindow(); 22 | } catch (e) { 23 | reject('Popup blocker detected. Please allow popups so the evaluation can open in a new window.'); 24 | } 25 | } else { 26 | importTarget = evalWindow; 27 | } 28 | 29 | promise.then(function (data) { 30 | try { 31 | importTarget.loadJson(data); 32 | appState.setDirtyState(); 33 | defer.resolve(); 34 | } catch (e) { 35 | reject(e); 36 | } 37 | }, reject); 38 | 39 | return defer.promise; 40 | }; 41 | } 42 | 43 | return { 44 | openFromFile: loadFactory(function (file) { 45 | return fileReader.readAsText(file); 46 | }), 47 | 48 | openFromUrl: loadFactory(function () { 49 | return wcagReporterImport.getFromUrl(); 50 | }) 51 | }; 52 | }); 53 | -------------------------------------------------------------------------------- /app/scripts/services/evalWindow.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('wcagReporter') 4 | .service('evalWindow', function ($http, wcagReporterImport, $rootScope) { 5 | var curWindow; 6 | var waitingForEvaluation = 'waitingForEvaluation'; 7 | var loadEvaluationData = 'loadEvaluationData'; 8 | var evaluateDataWhenReady = 'evaluateDataWhenReady'; 9 | 10 | function EvalWindow () {} 11 | 12 | EvalWindow.prototype = { 13 | openEmptyWindow: function () { 14 | var newRunner = new EvalWindow(); 15 | var newWindow = window.open(window.location.href, '_blank'); 16 | 17 | newWindow[waitingForEvaluation] = true; 18 | 19 | // open a window 20 | newRunner.abort = function () { 21 | newWindow.close(); 22 | }; 23 | 24 | newRunner.loadJson = function (data) { 25 | if (newWindow[loadEvaluationData]) { 26 | newWindow[loadEvaluationData](data); 27 | } else { 28 | newWindow[evaluateDataWhenReady] = data; 29 | } 30 | // Tell the new window where to look 31 | }; 32 | 33 | return newRunner; 34 | }, 35 | 36 | loadJson: function (data) { 37 | wcagReporterImport.fromJson(data); 38 | }, 39 | 40 | abort: angular.noop 41 | }; 42 | 43 | function processPageData (data) { 44 | curWindow.loadJson(data); 45 | $rootScope.setEvalLocation(); 46 | } 47 | 48 | curWindow = new EvalWindow(); 49 | 50 | if (window[waitingForEvaluation]) { 51 | window[waitingForEvaluation] = undefined; 52 | 53 | if (window[evaluateDataWhenReady]) { 54 | processPageData(window[evaluateDataWhenReady]); 55 | } else { 56 | window[loadEvaluationData] = processPageData; 57 | } 58 | } 59 | 60 | return curWindow; 61 | }); 62 | -------------------------------------------------------------------------------- /app/scripts/services/fileReader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Original module by K. Scott Allen 3 | * http://odetocode.com/blogs/scott/archive/2013/07/03/building-a-filereader-service-for-angularjs-the-service.aspx 4 | */ 5 | (function (module) { 6 | 'use strict'; 7 | 8 | var fileReader = function ($q, $rootScope) { 9 | var onLoad = function (reader, deferred, scope) { 10 | return function () { 11 | scope.$apply(function () { 12 | deferred.resolve(reader.result); 13 | }); 14 | }; 15 | }; 16 | 17 | var onError = function (reader, deferred, scope) { 18 | return function () { 19 | scope.$apply(function () { 20 | deferred.reject(reader.result); 21 | }); 22 | }; 23 | }; 24 | 25 | var onProgress = function (reader, scope) { 26 | return function (event) { 27 | scope.$broadcast( 28 | 'fileProgress', 29 | { 30 | total: event.total, 31 | loaded: event.loaded 32 | } 33 | ); 34 | }; 35 | }; 36 | 37 | var getReader = function (deferred, scope) { 38 | var reader = new FileReader(); 39 | reader.onload = onLoad(reader, deferred, scope); 40 | reader.onerror = onError(reader, deferred, scope); 41 | reader.onprogress = onProgress(reader, scope); 42 | return reader; 43 | }; 44 | 45 | var readAsText = function (file, scope) { 46 | scope = scope || $rootScope; 47 | var deferred = $q.defer(); 48 | var reader = getReader(deferred, scope); 49 | 50 | scope.$evalAsync(function () { 51 | try { 52 | reader.readAsText(file); 53 | } catch (e) { 54 | deferred.reject(e); 55 | } 56 | }); 57 | 58 | return deferred.promise; 59 | }; 60 | 61 | var readAsDataURL = function (file, scope) { 62 | scope = scope || $rootScope; 63 | var deferred = $q.defer(); 64 | var reader = getReader(deferred, scope); 65 | 66 | scope.$evalAsync(function () { 67 | try { 68 | reader.readAsDataURL(file); 69 | } catch (e) { 70 | deferred.reject(e); 71 | } 72 | }); 73 | 74 | return deferred.promise; 75 | }; 76 | 77 | return { 78 | readAsDataUrl: readAsDataURL, 79 | readAsText: readAsText 80 | }; 81 | }; 82 | 83 | module.factory('fileReader', [ 84 | '$q', 85 | '$rootScope', 86 | fileReader 87 | ]); 88 | }(angular.module('wcagReporter'))); 89 | -------------------------------------------------------------------------------- /app/scripts/services/helpers/isObjectLiteral.js: -------------------------------------------------------------------------------- 1 | angular 2 | .module('wcagReporter') 3 | .service('isObjectLiteral', function () { 4 | /** 5 | * isObjectLiteral tests if parameter is an object literal like: 6 | * { 7 | * key1: value1, 8 | * …, 9 | * keyN: valueN 10 | * } 11 | * @param {any} test [parameter to test] 12 | * @return {Boolean} 13 | */ 14 | function isObjectLiteral (test) { 15 | if ( 16 | typeof test === 'object' && 17 | Object.prototype.toString.call(test) === '[object Object]' 18 | ) { 19 | return true; 20 | } 21 | 22 | return false; 23 | } 24 | 25 | return isObjectLiteral; 26 | }); 27 | -------------------------------------------------------------------------------- /app/scripts/services/knownTechnologies.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('wcagReporter') 4 | .constant('knownTech', [ 5 | { title: 'HTML5', id: 'http://www.w3.org/TR/html5/', type: 'Technology' }, 6 | { title: 'XHTML 1.0', id: 'http://www.w3.org/TR/xhtml1/', type: 'Technology' }, 7 | { title: 'HTML 4.01', id: 'http://www.w3.org/TR/html401/', type: 'Technology' }, 8 | { title: 'CSS', id: 'http://www.w3.org/Style/CSS/specs/', type: 'Technology' }, 9 | { title: 'WAI-ARIA', id: 'http://www.w3.org/TR/wai-aria/', type: 'Technology' }, 10 | { title: 'ECMAScript 3', id: 'http://www.ecma-international.org/publications/standards/Ecma-327.htm', type: 'Technology' }, 11 | { title: 'ECMAScript 5', id: 'http://www.ecma-international.org/publications/standards/Ecma-262.htm', type: 'Technology' }, 12 | { title: 'DOM', id: 'http://www.w3.org/DOM/', type: 'Technology' }, 13 | { title: 'Flash', id: 'http://get.adobe.com/nl/flashplayer/', type: 'Technology' }, 14 | { title: 'Silverlight', id: 'http://www.microsoft.com/silverlight/', type: 'Technology' }, 15 | { title: 'OOXML', id: 'http://www.ecma-international.org/publications/standards/Ecma-376.htm', type: 'Technology' }, 16 | { title: 'ODF 1.2', id: 'https://www.oasis-open.org/standards#opendocumentv1.2', type: 'Technology' }, 17 | { title: 'SVG', id: 'http://www.w3.org/TR/SVG/', type: 'Technology' } 18 | ]); 19 | -------------------------------------------------------------------------------- /app/scripts/services/pkgData.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('wcagReporter') 4 | .value('pkgData', { 5 | name: '<%= pkg.name =%>', 6 | version: '<%= pkg.version =%>', 7 | buildDate: '<%= pkg.buildDate =%>' 8 | }); 9 | -------------------------------------------------------------------------------- /app/scripts/services/reportStorage.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('wcagReporter') 4 | .service('reportStorage', function ($http, $rootScope, appState, $timeout) { 5 | var reportStorage; var autosave; var loading; 6 | var failedSaveAttempts = 0; 7 | var settings = { 8 | url: undefined, 9 | revisionId: undefined, 10 | autosave: false, 11 | saveDelay: 3000 12 | }; 13 | 14 | function startAutosave () { 15 | if (!settings.url) { 16 | settings.autosave = false; 17 | return; 18 | } 19 | autosave = $timeout(function autosaveFunc () { 20 | reportStorage.exportModel.saveToUrl() 21 | .then(function () { 22 | failedSaveAttempts = 0; 23 | }, function () { 24 | failedSaveAttempts += 1; 25 | if (settings.autosave) { 26 | autosave = $timeout( 27 | autosaveFunc, 28 | settings.saveDelay * failedSaveAttempts, 29 | 0, 30 | false 31 | ); 32 | } 33 | }); 34 | }, settings.saveDelay, 0, false); 35 | } 36 | 37 | $rootScope.$on('appstate:prestine', function () { 38 | if (autosave) { 39 | $timeout.cancel(autosave); 40 | autosave = undefined; 41 | } 42 | }); 43 | 44 | $rootScope.$on('appstate:dirty', function () { 45 | if (settings.autosave && autosave === undefined) { 46 | startAutosave(); 47 | } 48 | }); 49 | 50 | reportStorage = { 51 | settings: settings, 52 | 53 | exportModel: undefined, 54 | 55 | init: function (obj) { 56 | reportStorage.updateSettings(obj); 57 | }, 58 | 59 | updateSettings: function (obj) { 60 | if (obj) { 61 | angular.extend(settings, obj); 62 | } 63 | 64 | if (settings.autosave && loading) { 65 | loading.then(startAutosave); 66 | } else if (settings.autosave) { 67 | startAutosave(); 68 | } 69 | }, 70 | 71 | post: function (json) { 72 | if (settings.revisionId) { 73 | json._rev = settings.revisionId; 74 | } 75 | return $http.put(settings.url, json, {}, { 76 | withCredentials: true 77 | }) 78 | .then(function (response) { 79 | if (response && response.data && response.data.rev) { 80 | settings.revisionId = response.data.rev; 81 | } 82 | appState.setPrestineState(); 83 | return response.data; 84 | }); 85 | }, 86 | 87 | get: function () { 88 | $timeout.cancel(autosave); 89 | loading = $http.get(settings.url, {}, { 90 | withCredentials: true 91 | }) 92 | .then(function (response) { 93 | if (response.data._rev) { 94 | settings.revisionId = response.data._rev; 95 | } 96 | appState.setPrestineState(); 97 | return response.data; 98 | }); 99 | return loading; 100 | } 101 | }; 102 | 103 | return reportStorage; 104 | }); 105 | -------------------------------------------------------------------------------- /app/scripts/services/toggleCriterionText.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('wcagReporter') 4 | .value('toggleCriterionText', function toggleCriterionText (elm) { 5 | var expandState = [ 6 | true, 7 | 'true' 8 | ].indexOf(elm.getAttribute('aria-expanded')) !== -1; 9 | elm.setAttribute('aria-expanded', !expandState); 10 | 11 | var section = elm.parentNode.parentNode.nextSibling; 12 | section.classList.toggle('collapsed'); 13 | }); 14 | -------------------------------------------------------------------------------- /app/scripts/services/types.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular 4 | .module('wcagReporter') 5 | .constant('types', { 6 | EARL: { 7 | type: 'earl', 8 | MODE: { 9 | type: 'earl:TestMode', 10 | MANUAL: 'earl:manual' 11 | }, 12 | OUTCOME: { 13 | type: 'earl:OutcomeValue', 14 | CANNOT_TELL: 'earl:CannotTell', 15 | CANT_TELL: 'earl:cantTell', 16 | INAPPLICABLE: 'earl:inapplicable', 17 | FAIL: 'earl:Fail', 18 | FAILED: 'earl:failed', 19 | NOT_APPLICABLE: 'earl:NotApplicable', 20 | NOT_TESTED: 'earl:NotTested', 21 | PASS: 'earl:Pass', 22 | PASSED: 'earl:passed', 23 | UNTESTED: 'earl:untested' 24 | }, 25 | RESULT: { 26 | class: 'TestResult', 27 | type: 'earl:TestResult' 28 | } 29 | } 30 | }); 31 | -------------------------------------------------------------------------------- /app/scripts/templates.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This is a dummy script. When the app is build the module in this script 3 | * is replaced with a auto-generated compilation of all the templates. 4 | */ 5 | angular.module('wert-templates', []); 6 | -------------------------------------------------------------------------------- /app/styles/animation.scss: -------------------------------------------------------------------------------- 1 | @import "../bower_components/bootstrap-sass-official/assets/stylesheets/bootstrap/_mixins.scss"; 2 | @import "../bower_components/bootstrap-sass-official/assets/stylesheets/bootstrap/_variables.scss"; 3 | 4 | .appear, 5 | .appear-tall { 6 | 7 | &.ng-enter, 8 | &.ng-leave { 9 | @include transition(200ms linear all); 10 | 11 | position: relative; 12 | display: block; 13 | overflow: hidden; 14 | text-overflow: clip; 15 | white-space: nowrap; 16 | } 17 | } 18 | 19 | 20 | .reporter-view { 21 | 22 | &.ng-enter, 23 | &.ng-leave { 24 | @include transition(200ms linear opacity); 25 | } 26 | 27 | /* When leaving, put the element in the same place, but don't let it take 28 | up screen space. This is for the new view */ 29 | &.ng-leave {/* starting animations for enter */ 30 | position: absolute; 31 | left: 50%; 32 | 33 | @include translate(-50%, 0); 34 | } 35 | 36 | &.ng-leave, 37 | &.ng-enter.ng-enter-active { 38 | 39 | /* terminal animations for leave */ 40 | opacity: 1; 41 | } 42 | 43 | &.ng-enter, 44 | &.ng-leave.ng-leave-active { 45 | 46 | /* terminal animations for leave */ 47 | opacity: 0; 48 | } 49 | } 50 | 51 | .appear, 52 | .appear-tall { 53 | 54 | &.ng-enter, 55 | &.ng-leave.ng-leave-active { 56 | 57 | /* terminal animations for leave */ 58 | opacity: 0; 59 | max-height: 0; 60 | } 61 | } 62 | 63 | .appear.ng-leave, /* starting animations for leave */ 64 | .appear.ng-enter.ng-enter-active { 65 | 66 | /* terminal animations for enter */ 67 | opacity: 1; 68 | max-height: 60px; 69 | } 70 | 71 | .appear-tall.ng-leave, /* starting animations for leave */ 72 | .appear-tall.ng-enter.ng-enter-active { 73 | 74 | /* terminal animations for enter */ 75 | opacity: 1; 76 | max-height: 400px; 77 | } 78 | -------------------------------------------------------------------------------- /app/styles/bootstrap-extend.scss: -------------------------------------------------------------------------------- 1 | @import "../bower_components/bootstrap-sass-official/assets/stylesheets/bootstrap/_mixins.scss"; 2 | @import "../bower_components/bootstrap-sass-official/assets/stylesheets/bootstrap/_variables.scss"; 3 | 4 | $focus-color: #477ba5; 5 | 6 | 7 | .dropdown-menu.lang-menu > li > a { 8 | padding-left: 10px; 9 | } 10 | 11 | body { 12 | 13 | .form-horizontal .control-label { 14 | text-align: left; 15 | } 16 | 17 | .alert { 18 | margin-bottom: 10px; 19 | } 20 | 21 | .btn > button { 22 | border: none; 23 | background: transparent; 24 | margin: -1px -5px; 25 | padding: 1px 5px; 26 | } 27 | 28 | .btn-default { 29 | border-color: #888; 30 | background-color: $body-bg; 31 | } 32 | 33 | .btn-group > input { 34 | float: left; 35 | } 36 | 37 | .btn.btn-primary-invert { 38 | background-color: $body-bg; 39 | } 40 | 41 | .navbar-nav > li > a { 42 | text-decoration: none; 43 | } 44 | 45 | .key-value-group { 46 | text-indent: 0; 47 | } 48 | } 49 | 50 | .alert { 51 | position: relative; 52 | 53 | .floater { 54 | width: 30px; 55 | height: 30px; 56 | float: right; 57 | } 58 | 59 | .close { 60 | position: absolute; 61 | top: 15px; 62 | right: 15px; 63 | } 64 | } 65 | 66 | label { 67 | display: inline; 68 | 69 | &::after { 70 | content: "\200B"; 71 | display: inline-block; 72 | margin-bottom: 5px; 73 | } 74 | } 75 | 76 | .alert p:last-child { 77 | margin-bottom: 0; 78 | } 79 | 80 | * a:focus, 81 | * button:focus, 82 | * .dropdown-toggle:focus { 83 | outline: thin solid $focus-color; 84 | } 85 | 86 | .form-control:focus { 87 | border-color: $focus-color; 88 | } 89 | 90 | .active *:focus { 91 | outline-color: white; 92 | } 93 | 94 | .dropdown-menu a { 95 | text-decoration: none; 96 | } 97 | 98 | @media (min-width: $screen-sm-min) { 99 | 100 | .visible-xs-and-sr { 101 | position: absolute !important; 102 | top: -9999em; 103 | } 104 | 105 | body .navbar-nav > li > a { 106 | border-left: solid 1px #ccc; 107 | } 108 | } 109 | 110 | @media (max-width: $screen-sm-min) { 111 | 112 | body .visible-xs-and-sr { 113 | position: relative !important; 114 | clear: left; 115 | } 116 | 117 | body .navbar-nav { 118 | margin: 0; 119 | 120 | & > li > a { 121 | border-top: solid 1px #ccc; 122 | } 123 | 124 | .dropdown-menu { 125 | padding: 0; 126 | 127 | > li > a { 128 | border-top: solid 1px #ccc; 129 | } 130 | } 131 | } 132 | 133 | label { 134 | line-height: 1em; 135 | } 136 | 137 | .expanding { 138 | margin-top: 5px; 139 | } 140 | 141 | .form-block .form-control { 142 | margin-top: -5px; 143 | margin-bottom: 5px; 144 | } 145 | } 146 | 147 | .crit-detail-btn { 148 | padding: 2px; 149 | 150 | .btn { 151 | width: 100%; 152 | padding: 4px; 153 | } 154 | } 155 | 156 | .form-group .alert { 157 | margin-top: 1em; 158 | } 159 | -------------------------------------------------------------------------------- /app/styles/hint.scss: -------------------------------------------------------------------------------- 1 | @import "../bower_components/bootstrap-sass-official/assets/stylesheets/bootstrap/_variables.scss"; 2 | 3 | $hint-back: $text-color; 4 | $hint-color: white; 5 | $hint-arrow-size: 10px; 6 | $hint-font: sans-serif; 7 | $hint-overlap: 3px; 8 | $hint-border-radius: 4px; 9 | $hint-padding-h: 10px; 10 | $hint-padding-v: 7px; 11 | $hint-speed: 0.2s; 12 | $hint-delay: 0.2s; 13 | 14 | * > .hint { 15 | float: left; 16 | pointer-events: none; 17 | display: none; 18 | cursor: default; 19 | line-height: 1em; 20 | opacity: 0; 21 | transition: opacity $hint-speed; 22 | transition-delay: 0s; 23 | position: absolute; 24 | display: block; 25 | top: $hint-overlap - $hint-arrow-size; 26 | background: $hint-back; 27 | border-radius: $hint-border-radius; 28 | padding: $hint-padding-v $hint-padding-h; 29 | left: 50%; 30 | transform: translate(-50%, -100%); 31 | font-family: $hint-font; 32 | color: $hint-color; 33 | z-index: 100; 34 | 35 | &::before { 36 | content: " "; 37 | width: 100%; 38 | height: $hint-arrow-size - $hint-overlap; 39 | position: absolute; 40 | top: 100%; 41 | left: 0; 42 | } 43 | 44 | &::after { 45 | content: " "; 46 | width: 0; 47 | height: 0; 48 | border-left: 1+$hint-arrow-size solid transparent; 49 | border-right: 1+$hint-arrow-size solid transparent; 50 | border-top: 1+$hint-arrow-size solid $hint-back; 51 | position: absolute; 52 | bottom: 0 - $hint-arrow-size; 53 | left: 50%; 54 | transform: translateX(-50%); 55 | } 56 | } 57 | 58 | *:focus, 59 | *:hover { 60 | 61 | > .hint { 62 | pointer-events: auto; 63 | opacity: 1; 64 | transition-delay: $hint-delay; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /app/styles/wizard.scss: -------------------------------------------------------------------------------- 1 | @import "../bower_components/bootstrap-sass-official/assets/stylesheets/bootstrap/_mixins.scss"; 2 | @import "../bower_components/bootstrap-sass-official/assets/stylesheets/bootstrap/_variables.scss"; 3 | 4 | $wzrd-v-padding: 8px; 5 | $wzrd-h-padding: 5px; 6 | $wzrd-border-rad: 8px; 7 | $wzrd-gap: 5px; 8 | $wzrd-arrow-size: floor($wzrd-v-padding + ($font-size-base/2) + 3px); 9 | $wzrd-v-padding-outer: 12px; 10 | $wzrd-bg: #dfdfdf; 11 | $wzrd-indent: 1em; 12 | 13 | .wizard { 14 | margin: 0 0 0 $wzrd-indent; 15 | padding: 0; 16 | list-style: none; 17 | 18 | .wizard-step { 19 | padding: $wzrd-v-padding ($wzrd-h-padding + 1) $wzrd-v-padding $wzrd-h-padding; 20 | padding-left: $wzrd-arrow-size + $wzrd-h-padding; 21 | margin: ($wzrd-gap/2) 0 ($wzrd-gap/2) $wzrd-gap; 22 | background: $wzrd-bg; 23 | position: relative; 24 | display: inline-block; 25 | 26 | @include border-right-radius(3px); 27 | 28 | a { 29 | margin: (0-$wzrd-v-padding) (0-$wzrd-h-padding); 30 | padding: $wzrd-v-padding $wzrd-h-padding; 31 | display: block; 32 | color: $link-hover-color; 33 | } 34 | 35 | a:hover { 36 | color: black; 37 | } 38 | 39 | &::before, 40 | &::after { 41 | width: 0; 42 | height: 0; 43 | top: 0; 44 | position: absolute; 45 | content: ""; 46 | border-top: $wzrd-arrow-size inset transparent; 47 | border-bottom: $wzrd-arrow-size inset transparent; 48 | } 49 | 50 | &::before { 51 | border-left: $wzrd-arrow-size solid $body-bg; 52 | left: 0; 53 | } 54 | 55 | &::after { 56 | border-left: $wzrd-arrow-size solid $wzrd-bg; 57 | right: (1 - $wzrd-arrow-size); 58 | z-index: 2; 59 | } 60 | 61 | &:first-child::before, 62 | &:last-child::after { 63 | border: none; 64 | } 65 | 66 | &:first-child { 67 | @include border-left-radius($wzrd-border-rad); 68 | 69 | padding-left: $wzrd-v-padding-outer; 70 | margin-left: (0 - $wzrd-indent); 71 | } 72 | 73 | &:last-child { 74 | @include border-right-radius($wzrd-border-rad); 75 | 76 | padding-right: $wzrd-v-padding-outer; 77 | } 78 | 79 | &.active { 80 | background: $brand-primary; 81 | color: $btn-primary-color; 82 | 83 | a { 84 | color: $btn-primary-color; 85 | text-decoration: none; 86 | } 87 | 88 | &::after { 89 | border-left-color: $brand-primary; 90 | } 91 | } 92 | 93 | &.disabled a { 94 | font-style: italic; 95 | color: $btn-link-disabled-color; 96 | 97 | &:hover { 98 | text-decoration: none; 99 | } 100 | } 101 | } 102 | 103 | .badge { 104 | margin-right: 5px; 105 | position: relative; 106 | top: -1px; 107 | } 108 | 109 | .wizard-step:first-child .badge { 110 | margin-left: 0; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /app/views/directives/buttonCollapse.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/views/directives/criterion/criterionBody.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | 9 | 10 |
12 | {{ 'AUDIT.NO_PAGE_SELECTED' | translate}} 13 |
14 | 15 |
-------------------------------------------------------------------------------- /app/views/directives/criterion/earlAssert.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 |
6 | 7 | 11 |
12 | 13 |
14 | 16 |
17 |
18 | 19 | 20 |
21 |
22 | {{ 'AUDIT.LABEL_OUTCOME' | translate}}: {{ result.outcome | rdfToLabel }} 23 |
24 | 25 |
27 |
28 | 29 |
30 | -------------------------------------------------------------------------------- /app/views/directives/criterion/macroResults.html: -------------------------------------------------------------------------------- 1 |
2 | 4 | 5 |
{{ 'AUDIT.RESULTS_FOR' | translate }}:
6 | 7 |
8 | 9 |
10 | 11 | 15 |
16 | 17 |
18 |
19 | {{ 'AUDIT.CONFIRM_TRANSFER_MACRO_RESULT' | translate }} 20 | {{ 'COMMON.YES' | translate }} / 21 | {{ 'COMMON.NO' | translate }} 22 |
23 |
24 |
25 | 26 | 30 |
31 | 32 |
33 |
34 | {{ 'AUDIT.CONFIRM_REMOVE_RESULT' | translate }} 35 | {{ 'COMMON.YES' | translate }} / 36 | {{ 'COMMON.NO' | translate }} 37 |
38 |
39 |
40 | 41 |
42 | 43 |
44 | 45 |
46 | 47 |
48 | 49 |
50 |
-------------------------------------------------------------------------------- /app/views/directives/criterion/pageResults.html: -------------------------------------------------------------------------------- 1 |
2 | 4 | 5 |
6 | {{ 'AUDIT.RESULTS_FOR' | translate}}: 7 | 8 | 9 | ({{assert.subject[0].description}}) 10 | 11 |
12 | 13 |
14 |
-------------------------------------------------------------------------------- /app/views/directives/criterion/pageSelect.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 5 | 6 | 7 | 14 | 15 | 19 | 20 |
-------------------------------------------------------------------------------- /app/views/directives/criterion/resultDescription.html: -------------------------------------------------------------------------------- 1 |
2 | 6 | 17 |
18 | -------------------------------------------------------------------------------- /app/views/directives/evaluate/iconButton.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | -------------------------------------------------------------------------------- /app/views/directives/evaluate/infoButton.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/views/directives/evaluate/infoField.html: -------------------------------------------------------------------------------- 1 |
3 | 4 | 5 |
6 | 7 | 11 |
-------------------------------------------------------------------------------- /app/views/directives/evaluate/inputPages.html: -------------------------------------------------------------------------------- 1 |
7 | 8 | 15 | 16 |

17 | {{ 'SAMPLE.NO_PAGES_DEFINED' | translate}} 18 |

19 | 20 |
21 | 22 | {{ 'SAMPLE.ITEM' | translate }} {{$index+1}} 23 | 24 | 25 | 28 |
29 | 34 |
35 | 38 |
39 | 43 |
44 | 45 |
46 | 49 |
50 |
51 | 52 | 56 |
-------------------------------------------------------------------------------- /app/views/directives/evaluate/techSelect.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 11 | 13 |
14 |
-------------------------------------------------------------------------------- /app/views/directives/fullReport.html: -------------------------------------------------------------------------------- 1 |
2 |

{{report.title}}

3 |

4 | {{'HTML_REPORT.BY' | translate }} {{report.creator.name}}, 5 | {{report.date | date: shortDate}} 6 |

7 |

8 | {{'HTML_REPORT.COMMISION_BY' | translate }} {{report.commissioner}} 9 |

10 | 11 |

{{'HTML_REPORT.HD_SUMMARY'| translate}}

12 |
13 | 14 |

{{'HTML_REPORT.HD_SCOPE' | translate }}

15 |
16 | 17 |

{{'HTML_REPORT.HD_SCORE' | translate }}

18 |
19 | 20 |

{{ 'HTML_REPORT.HD_CRITERIA_REPORT' | translate }}

21 |
22 | 23 |

{{'HTML_REPORT.HD_SAMPLE' | translate }}

24 |
25 | 26 |
27 |

{{'HTML_REPORT.HD_SPECIFICS' | translate }}

28 |
29 |
30 | 31 |

{{'HTML_REPORT.HD_DOCS' | translate }}

32 | 46 |
47 | -------------------------------------------------------------------------------- /app/views/directives/successCriterion.html: -------------------------------------------------------------------------------- 1 |
3 | 4 | 5 | 6 |
7 | {{ spec.num}} {{ spec.handle}}: ({{spec.level | rdfToLabel}}) 8 | 9 | 14 | 15 | 16 |
52 |
{{ 'AUDIT.SAMPLE_FINDINGS' | translate }}:
53 | 54 |
55 | 56 |
57 | 70 |
71 | 72 | 74 |
75 | -------------------------------------------------------------------------------- /app/views/error.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |

{{ setTitle( translate('ERROR.TITLE') ) }}

5 | 6 |

{{ 'ERROR.INTRO' | translate }}

7 | 8 |
    9 |
  • {{ 'ERROR.SUGGESTION1' | translate }}
  • 10 |
  • 13 |
  • 16 |
17 | 18 |

21 | 22 |
23 | -------------------------------------------------------------------------------- /app/views/evaluation/audit.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 |

{{ setTitle( translate('AUDIT.TITLE') ) }}

6 |

9 | 10 |
11 |
13 | 14 |
16 |
17 |
18 | 19 | -------------------------------------------------------------------------------- /app/views/evaluation/audit/criteria-tools.html: -------------------------------------------------------------------------------- 1 |
2 | {{ 'AUDIT.FILTER' | translate }}: 3 | 4 |
5 | {{ 'AUDIT.FILTER_VERSION_LEGEND' | translate }} 6 | 7 | 17 | 18 | 28 | 29 | 39 |
40 | 41 |
42 | {{ 'AUDIT.FILTER_LEVEL_LEGEND' | translate }} 43 | 53 | 54 | 64 | 65 | 75 |
76 |
77 | -------------------------------------------------------------------------------- /app/views/evaluation/audit/criteria.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | {{ 'AUDIT.HD_CRITERIA' | translate}}  6 |

7 | 8 | 10 |

{{ 'AUDIT.INF_AUDIT_CRITERIA' | translate }}

11 |
12 | 13 |
14 | 15 |
17 |

18 | {{ 'AUDIT.PRINCIPLE' | translate}} 19 | {{p.num + ' ' + p.handle}} 20 |

21 | 22 |
25 |

26 | {{g.num}} {{g.handle}} 27 | 31 |

32 | 33 |
34 | 40 | 41 | 42 | 45 |
46 |
47 |
48 |
49 | -------------------------------------------------------------------------------- /app/views/evaluation/audit/samplePages.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | {{ 'AUDIT.HD_SAMPLE_SELECT' | translate}} > 6 |

7 | 8 | 10 |

11 |
12 | 13 |
14 |
15 | 17 |
18 | 19 |
20 | 22 | 24 |
25 | 26 |
27 | 29 |
30 |
31 | 32 |

{{ 'AUDIT.NO_SAMPLE' | translate }}

33 | 34 | 51 | 52 |
-------------------------------------------------------------------------------- /app/views/evaluation/sample.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 |

{{ setTitle( translate('SAMPLE.TITLE') ) }}

6 | 7 |

10 | 11 |
12 |

{{'SAMPLE.HD_STRUCT_SAMPLE' | translate }}

13 | 14 |

15 | {{ 'SAMPLE.HD_ESSENT_FUNC' | translate }} 16 |

17 | 18 |
19 | 23 |
24 | 25 |

26 | {{ 'SAMPLE.HD_VARIETY_PAGE_TYPES' | translate }} 27 |

28 | 29 |
30 | 34 |
35 | 36 | 37 |

{{ 'SAMPLE.HD_STRUCT_SAMPLE_SUB' | translate }} 

40 | 41 | 42 |

46 |
47 | 48 | 50 | 51 |

52 | {{'SAMPLE.HD_RANDOM_SAMPLE' | translate }}  55 |

56 | 57 | 58 |

62 |
63 | 64 |
65 | {{ "SAMPLE.RAND_SAMPLE_LENGTH" | translate: { 66 | total: structuredSample.webpage.length, 67 | count: randPageCount()} 68 | }} 69 |
70 | 71 | 74 | 75 |
76 |
77 | 78 | -------------------------------------------------------------------------------- /app/views/evaluation/stepbar.html: -------------------------------------------------------------------------------- 1 | 19 | -------------------------------------------------------------------------------- /app/views/footer.html: -------------------------------------------------------------------------------- 1 | 16 | -------------------------------------------------------------------------------- /app/views/import.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |

{{ setTitle( translate('IMPORT.TITLE') ) }}

5 | 6 |
7 |

{{ feedback.message }}

8 |
9 | 10 |
11 |

Step 1 - Select import file

12 |

{{ 'IMPORT.INTRO' | translate }}

13 |

14 | 17 | 18 |

19 |
20 | 21 |
22 |

Step 2 - Confirm import

23 |

File “{{importFile.name}}” is ready to be imported.

24 |

We have found 25 | {{ assertionImport.length }} 26 | asserertions that can be inserted into the evaluation audit results

27 | 28 |
29 | Do you wish to continue with the import? 30 | 31 | 32 |
33 |
34 | 35 |
36 |

Step 3 - Import summary

37 |

Imported 38 | {{ assertionImport.length }} 39 | asserertions and inserted to the audit results.

40 | 41 | 42 |
43 | 44 |

45 | {{'NAV.BTN_BACK_TO_EVAL' | translate}} 46 |

47 |
48 | -------------------------------------------------------------------------------- /app/views/messages.html: -------------------------------------------------------------------------------- 1 |
4 | 5 | 6 |

7 | 8 | 13 |
-------------------------------------------------------------------------------- /app/views/open.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |

{{ setTitle( translate('OPEN.TITLE') ) }}

5 | 6 |

{{ 'OPEN.INTRO' | translate }}

7 | 8 |
9 |

{{ 'OPEN.MSG_LOADING' | translate }}

10 |
11 |
12 |

{{fileFeedback.failure}}

13 |
14 | 15 |

19 | 20 | 24 | 25 |
26 |

{{ 'OPEN.' + showError | translate }} 27 |

28 | 29 |

{{'NAV.BTN_BACK_TO_EVAL' | translate}}

30 |
-------------------------------------------------------------------------------- /app/views/report/findings.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

{{ 'HTML_REPORT.PRINCIPLE'| translate }} 4 | {{p.num + ' ' + p.handle}}

5 | 6 |
7 |

{{g.num + ' ' + g.handle}}

8 | 13 | 14 |
15 | 16 |
17 |
-------------------------------------------------------------------------------- /app/views/report/sample.html: -------------------------------------------------------------------------------- 1 |
    2 |
  • 3 | 4 | 5 | {{ page.displayTitle()}}  6 | 7 | 9 | 10 |
  • 11 |
-------------------------------------------------------------------------------- /app/views/report/scope.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 31 | 32 | 33 |
{{'HTML_REPORT.LABEL_SITE_NAME' | translate}}{{scope.website.siteName}}
{{'HTML_REPORT.LABEL_SITE_SCOPE' | translate}}
{{ 'SCOPE.LABEL_WCAG_VERSION' | translate }}{{ 'SCOPE.' + scope.wcagVersion | translate }}
{{ 'HTML_REPORT.LABEL_CONFORMANCE_TGT' | translate }}{{scope.conformanceTarget | rdfToLabel}}
{{ 'HTML_REPORT.LABEL_EXTRA_REQUIREMENTS' | translate }}
{{ 'HTML_REPORT.LABEL_SUPPORT_BASE' | translate }}
{{ 'HTML_REPORT.LABEL_RELIEDUP_TECH' | translate }}
34 | -------------------------------------------------------------------------------- /app/views/report/score.html: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 15 | 18 | 19 | 20 | 21 | 22 | 26 | 30 | 34 | 35 | 36 | 37 | 41 | 45 | 49 | 50 | 51 |
3 | {{ 4 | 'HTML_REPORT.RESULTS_OF' | translate 5 | }} {{ 6 | scope.conformanceTarget | rdfToLabel 7 | }} 8 |
{{ 'HTML_REPORT.PRINCIPLE' | translate }}{{ 'EARL.LEVEL_A' | translate }}{{ 13 | 'EARL.LEVEL_AA' | translate 14 | }}{{ 16 | 'EARL.LEVEL_AAA' | translate 17 | }}
{{score.name}}{{ 23 | score['level_a'].pass + ' / ' + 24 | score['level_a'].total 25 | }}{{ 27 | score['level_aa'].pass + ' / ' + 28 | score['level_aa'].total 29 | }}{{ 31 | score['level_aaa'].pass + ' / ' + 32 | score['level_aaa'].total 33 | }}
{{ 'HTML_REPORT.TOTAL_SCORE' | translate }}{{ 38 | totals['level_a'].pass + ' / ' + 39 | totals['level_a'].total 40 | }}{{ 42 | totals['level_aa'].pass + ' / ' + 43 | totals['level_aa'].total 44 | }}{{ 46 | totals['level_aaa'].pass + ' / ' + 47 | totals['level_aaa'].total 48 | }}
-------------------------------------------------------------------------------- /app/views/save.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |

{{ setTitle( translate('SAVE.TITLE') ) }}

5 | 6 |

{{ 'SAVE.INTRO' | translate }}

7 | 8 |

11 | {{ 'SAVE.BTN_DOWNLOAD_DATA_FILE' | translate }} 12 |

13 | 14 |

17 | 18 |

{{'NAV.BTN_BACK_TO_EVAL' | translate }}

19 |
20 | -------------------------------------------------------------------------------- /app/views/start.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 |

{{ setTitle( translate('START.TITLE') ) }}

6 | 7 |

{{ 'START.SUBTITLE' | translate }}

8 |

9 | {{ 'START.INTRO_HD' | translate }} 10 |

11 | 12 |
13 |

19 | 20 |

21 |
22 | 23 |

24 | {{ 'START.USAGE_HD' | translate }} 25 |

26 |
27 |
    28 |
  • {{ 'START.USAGE_LI1' | translate }}
  • 29 |
  • {{ 'START.USAGE_LI2' | translate }}
  • 30 |
  • {{ 'START.USAGE_LI3' | translate }}
  • 31 |
  • {{ 'START.USAGE_LI4' | translate }}
  • 32 |
33 |
34 | 35 | 36 |

37 | {{ 'START.TIPS_HD' | translate }} 38 |

39 |
40 |
    41 |
  • {{ 'START.TIPS_LI1' | translate }}
  • 42 |
  • 46 |
  • 47 |
  • {{ 'START.TIPS_LI3' | translate }}
  • 48 |
  • {{ 'START.TIPS_LI4' | translate }}
  • 49 |
50 |
51 | 52 | 53 | -------------------------------------------------------------------------------- /app/views/step-buttons.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/views/viewReport.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 |

{{ setTitle( translate('DOWNLOAD.TITLE') ) }}

6 | 7 |

8 | 9 | 31 | 32 | 33 | 34 |
-------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "WCAG-EM-Report-Tool", 3 | "version": "2.0.1", 4 | "repository": { 5 | "type": "git", 6 | "url": "git://github.com/w3c/wcag-em-report-tool.git" 7 | }, 8 | "dependencies": { 9 | "textarea-autosize": "~0.4.1", 10 | "angular": "1.7.x", 11 | "angular-animate": "1.7.x", 12 | "angular-resource": "1.7.x", 13 | "angular-route": "1.7.x", 14 | "angular-sanitize": "1.7.x", 15 | "angular-translate": "2.x", 16 | "angular-translate-loader-static-files": "2.x", 17 | "bootstrap-sass-official": "~3.x", 18 | "angular-mocks": "~1.4.7", 19 | "angular-scenario": "~1.4.7" 20 | }, 21 | "devDependencies": { 22 | "angular-mocks": "~1.4.7", 23 | "angular-scenario": "~1.4.7", 24 | "axe-core": "~1.1.1" 25 | }, 26 | "resolutions": { 27 | "textarea-autosize": "~0.4.1", 28 | "angular": "1.7.x", 29 | "angular-animate": "1.7.x", 30 | "angular-resource": "1.7.x", 31 | "angular-route": "1.7.x", 32 | "angular-sanitize": "1.7.x", 33 | "angular-translate": "2.x", 34 | "bootstrap-sass-official": "~3.x", 35 | "angular-mocks": "~1.4.7", 36 | "angular-scenario": "~1.4.7" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | # Change log: WCAG-EM Report Tool 2 | 3 | ## Version 1.1 - 2015-12-30 4 | - Add support for multiple language 5 | - Update the data format 6 | - Make minor updates to the user interface 7 | - Provide a set of unit tests 8 | - Refactor the project for maintainability 9 | - Improve project documentation 10 | 11 | ## Version 1.0 12 | ### Version 1.0.3 - 2015-06-15 13 | - Fix: Resource menu wouldn't open properly 14 | 15 | ### Version 1.0.2 - 2015-04-03 16 | - Add change log 17 | - Add Repository to package.json 18 | - Pages without handle and description are no longer shown outside step 3 19 | - Fix: Creator data was sometimes duplicated 20 | - Fix: Static meta data wasn't exported 21 | 22 | ### Version 1.0.1 - 2015-03-23 23 | - Fix: Incorrect loading of single web technology 24 | - Fix: Incorrect loading of page handles -------------------------------------------------------------------------------- /docs/contribute.md: -------------------------------------------------------------------------------- 1 | # Get involved with the WCAG-EM Report Tool 2 | 3 | The WCAG-EM Report Tool is an open source project that came out of the [WAI-ACT project](http://www.w3.org/WAI/ACT/). It is currently maintained by volunteers for the W3C. And we would love to have you involved. 4 | 5 | There are multiple ways in which you can contribute to the project, here are a few: 6 | 7 | - Report issues 8 | - Create a translation 9 | - Contribute code 10 | 11 | 12 | ## Report Issues 13 | We work hard to keep the code quality at a high level. But we're human, so we make mistakes too. Found any of them? By all means let us know so we can correct them. You can do so by creating an issue on our [issues page](https://github.com/w3c/wcag-em-report-tool/issues). If you report an issue, please check if it isn't already reported. 14 | 15 | 16 | ## Create A Translation 17 | Do you feel the WCAG-EM Report Tool should be available in a different language? Well, we do too! Even better, if you have some time to contribute and share it with the community. For more information, read our [translation instructions](https://github.com/w3c/wcag-em-report-tool/blob/master/docs/translation.md) 18 | 19 | 20 | ## Contribute Code 21 | Have an idea for a feature and have some time to develop it? Let us know! We'll gladly have new contributors to the project. We'll help you figure out the best way to fit it into the project, and work with you so the changes you make fit into the overall project. 22 | 23 | For minor feature changes, [creating a pull request](https://github.com/w3c/wcag-em-report-tool/pulls) once it is finished is sufficient. But for larger changes, please create an issue first to discuss how to fit it into the larger project. 24 | 25 | For more detail on how the project is set up, read the [developer documentation](https://github.com/w3c/wcag-em-report-tool/blob/master/docs/developer-docs.md). 26 | -------------------------------------------------------------------------------- /docs/developer-docs.md: -------------------------------------------------------------------------------- 1 | # WCAG-EM Report Tool 2 | 3 | This document describes the architecture and concepts behind 4 | the WCAG-EM Report Tool. The WCAG-EM Report Tool is based on 5 | the structure outlined by Yeoman Angular Generator 6 | (https://github.com/yeoman/generator-angular). Details about 7 | the structure of this project are also available here. 8 | 9 | ## Task Runner 10 | 11 | Grunt is used as a task runner. To run the app from the app folder 12 | use `grunt serve`. To build the app to the dist folder, run 13 | `grunt build`. 14 | 15 | To run the tests defined in the project, use the `grunt test` command. 16 | 17 | ## Directory structure 18 | 19 | - `scripts/controllers/`: Connect the models to the views 20 | - `scripts/directives/`: Angular directives for the app 21 | - `scripts/filters/`: Filters used in the angular app 22 | - `scripts/locale/`: Localization files build from the `locale` folder 23 | - `scripts/models/`: Models for the data structure within the app 24 | - `scripts/services/`: Services used within the controllers 25 | - `views`: Contains the views / templates of the project 26 | - `styles`: Styles in the form of SCSS 27 | 28 | ## Localization 29 | 30 | There are currently two places from which the text of the app is 31 | pulled. The localization for the UI is placed in directories under 32 | `app/locale/xx/`. The texts used within WCAG are described in 33 | `app/wcag2spec/wcag2-xx.json`. 34 | 35 | More about translations, read [docs/translation.md] -------------------------------------------------------------------------------- /docs/examples/importable-json/example_simple_import.ld.json: -------------------------------------------------------------------------------- 1 | { 2 | "@context": 3 | { 4 | "WCAG21": "http://www.w3.org/TR/WCAG21/#", 5 | "earl": "http://www.w3.org/ns/earl#", 6 | "Assertion": "earl:Assertion", 7 | "TestResult": "earl:TestResult", 8 | "test": 9 | { 10 | "@id": "earl:test", 11 | "@type": "@id" 12 | }, 13 | "assertedBy": 14 | { 15 | "@id": "earl:assertedBy", 16 | "@type": "@id" 17 | }, 18 | "subject": 19 | { 20 | "@id": "earl:subject", 21 | "@type": "@id" 22 | }, 23 | "result": "earl:result", 24 | "outcome": 25 | { 26 | "@id": "earl:outcome", 27 | "@type": "@id" 28 | }, 29 | "dcterms": "http://purl.org/dc/terms/", 30 | "description": "dcterms:description" 31 | }, 32 | "@graph": [ 33 | { 34 | "@type": "Assertion", 35 | "assertedBy": "_:evaluator", 36 | "subject": "https://website-name.org", 37 | "result": 38 | { 39 | "@type": "TestResult", 40 | "description": "No violations found", 41 | "outcome": "earl:passed" 42 | }, 43 | "test": "WCAG21:non-text-content" 44 | }, 45 | { 46 | "@type": "Assertion", 47 | "assertedBy": "_:evaluator", 48 | "subject": "https://website-name.org/contact-us/", 49 | "result": 50 | { 51 | "@type": "TestResult", 52 | "description": "Found a heading like text “Contact us” without heading markup! (`

`)", 53 | "outcome": "earl:failed" 54 | }, 55 | "test": "WCAG21:info-and-relationships" 56 | }, 57 | { 58 | "@type": "Assertion", 59 | "assertedBy": "_:evaluator", 60 | "subject": "https://website-name.org/search/?search=some-random-page", 61 | "result": 62 | { 63 | "@type": "TestResult", 64 | "description": "Found focus order to start with last search entry visible going up instead of down! And when reverse tabbing focus jumps to body (and focus body only)", 65 | "outcome": "earl:failed" 66 | }, 67 | "test": "WCAG21:meaningful-sequence" 68 | }, 69 | { 70 | "@context": 71 | { 72 | "@vocab": "http://xmlns.com/foaf/0.1/" 73 | }, 74 | "@id": "_:evaluator", 75 | "@type": "Person", 76 | "name": "External Evaluator" 77 | }] 78 | } 79 | -------------------------------------------------------------------------------- /karma-e2e.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // http://karma-runner.github.io/0.10/config/configuration-file.html 3 | 4 | module.exports = function(config) { 5 | config.set({ 6 | // base path, that will be used to resolve files and exclude 7 | basePath: '', 8 | 9 | // testing framework to use (jasmine/mocha/qunit/...) 10 | frameworks: ['ng-scenario'], 11 | 12 | // list of files / patterns to load in the browser 13 | files: [ 14 | 'test/e2e/**/*.js' 15 | ], 16 | 17 | // list of files / patterns to exclude 18 | exclude: [], 19 | 20 | // web server port 21 | port: 8080, 22 | 23 | // level of logging 24 | // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG 25 | logLevel: config.LOG_INFO, 26 | 27 | 28 | // enable / disable watching file and executing tests whenever any file changes 29 | autoWatch: false, 30 | 31 | 32 | // Start these browsers, currently available: 33 | // - Chrome 34 | // - ChromeCanary 35 | // - Firefox 36 | // - Opera 37 | // - Safari (only Mac) 38 | // - PhantomJS 39 | // - IE (only Windows) 40 | browsers: ['Chrome'], 41 | 42 | 43 | // Continuous Integration mode 44 | // if true, it capture browsers, run tests and exit 45 | singleRun: false 46 | 47 | // Uncomment the following lines if you are using grunt's server to run the tests 48 | // proxies: { 49 | // '/': 'http://localhost:9000/' 50 | // }, 51 | // URL root prevent conflicts with the site root 52 | // urlRoot: '_karma_' 53 | }); 54 | }; 55 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // http://karma-runner.github.io/0.10/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | 'use strict'; 6 | config.set({ 7 | // base path, that will be used to resolve files and exclude 8 | basePath: '', 9 | 10 | client: { 11 | jasmine: { 12 | random: false 13 | } 14 | }, 15 | // testing framework to use (jasmine/mocha/qunit/...) 16 | frameworks: ['jasmine'], 17 | 18 | // list of files / patterns to load in the browser 19 | files: [ 20 | 'app/bower_components/jquery/dist/jquery.js', 21 | 'app/bower_components/angular/angular.js', 22 | 'app/bower_components/angular-animate/angular-animate.js', 23 | 'app/bower_components/angular-mocks/angular-mocks.js', 24 | 'app/bower_components/angular-resource/angular-resource.js', 25 | 'app/bower_components/angular-route/angular-route.js', 26 | 'app/bower_components/angular-sanitize/angular-sanitize.js', 27 | 'app/bower_components/angular-translate/angular-translate.js', 28 | 'app/bower_components/angular-translate-loader-static-files/angular-translate-loader-static-files.js', 29 | 'app/bower_components/json3/lib/json3.js', 30 | 'app/bower_components/textarea-autosize/dist/jquery.textarea_autosize.js', 31 | 'app/scripts/libs/promise-1.0.0.js', 32 | 'app/scripts/libs/jsonld.js', 33 | 'app/scripts/**/{,*/}*.js', 34 | 'app/scripts/app.language.js', 35 | 'app/scripts/app.run.js', 36 | 'app/scripts/app.js', 37 | { 38 | pattern: '.tmp/locale/*.json', 39 | included: false, 40 | served: true 41 | }, 42 | { 43 | pattern: 'app/wcag2spec/*.json', 44 | included: false, 45 | served: true 46 | }, 47 | 'test/setup.js', 48 | 'test/dummyData/*.js', 49 | 'test/spec/**/{,*/}*.js' 50 | ], 51 | 52 | // list of files / patterns to exclude 53 | exclude: [], 54 | 55 | proxies: { 56 | '/wcag2spec/': 'http://localhost:8080/base/app/wcag2spec/', 57 | '/locale/': 'http://localhost:8080/base/.tmp/locale/' 58 | }, 59 | 60 | // web server port 61 | port: 8080, 62 | 63 | // level of logging 64 | // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG 65 | logLevel: config.LOG_INFO, 66 | 67 | // enable / disable watching file and executing tests whenever any file changes 68 | autoWatch: false, 69 | 70 | // Start these browsers, currently available: 71 | // - Chrome 72 | // - ChromeCanary 73 | // - Firefox 74 | // - Opera 75 | // - Safari (only Mac) 76 | // - PhantomJS 77 | // - IE (only Windows) 78 | browsers: ['PhantomJS'], 79 | 80 | // Continuous Integration mode 81 | // if true, it capture browsers, run tests and exit 82 | singleRun: false 83 | }); 84 | }; 85 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "WCAG-EM-Report-Tool", 3 | "version": "2.0.3", 4 | "repository": { 5 | "type": "git", 6 | "url": "git://github.com/w3c/wcag-em-report-tool.git" 7 | }, 8 | "devDependencies": { 9 | "bower": "^1.8.8", 10 | "eslint": "^6.2.2", 11 | "eslint-config-standard": "^14.1.0", 12 | "eslint-plugin-import": "^2.18.2", 13 | "eslint-plugin-node": "^9.2.0", 14 | "eslint-plugin-promise": "^4.2.1", 15 | "eslint-plugin-standard": "^4.0.1", 16 | "grunt": "~1.0.4", 17 | "grunt-autoprefixer": "~3.0.4", 18 | "grunt-cli": "~1.3.2", 19 | "grunt-concat-json": "0.0.10", 20 | "grunt-concurrent": "~2.0.4", 21 | "grunt-contrib-clean": "~2.0.0", 22 | "grunt-contrib-compass": "~1.1.1", 23 | "grunt-contrib-concat": "~1.0.1", 24 | "grunt-contrib-connect": "~2.0.0", 25 | "grunt-contrib-copy": "~1.0.0", 26 | "grunt-contrib-cssmin": "~3.0.0", 27 | "grunt-contrib-htmlmin": "~3.1.0", 28 | "grunt-contrib-uglify": "~4.0.1", 29 | "grunt-contrib-watch": "~1.1.0", 30 | "grunt-html2js": "~0.6.0", 31 | "grunt-karma": "^3.0.2", 32 | "grunt-newer": "~1.3.0", 33 | "grunt-ng-annotate": "~3.0.0", 34 | "grunt-replace": "~1.0.1", 35 | "grunt-rev": "~0.1.0", 36 | "grunt-usemin": "~3.1.1", 37 | "grunt-wiredep": "~3.0.1", 38 | "jasmine-core": "^3.4.0", 39 | "karma": "^4.2.0", 40 | "karma-chrome-launcher": "^0.2.0", 41 | "karma-jasmine": "^2.0.1", 42 | "karma-ng-html2js-preprocessor": "^0.1.0", 43 | "karma-phantomjs-launcher": "^1.0.4", 44 | "load-grunt-tasks": "~5.0.0", 45 | "phantomjs": "^2.1.7", 46 | "stylelint": "^10.1.0", 47 | "stylelint-config-standard": "^18.3.0", 48 | "stylelint-scss": "^3.10.0", 49 | "time-grunt": "2.0.0" 50 | }, 51 | "engines": { 52 | "node": ">=8.15.0" 53 | }, 54 | "scripts": { 55 | "install": "npx bower install && gem install compass", 56 | "build": "npx grunt build", 57 | "start": "npx grunt serve", 58 | "test": "npx grunt test", 59 | "lint": "npm run lint:styles && npm run lint:scripts", 60 | "lint:scripts": "npx eslint ./app/scripts ./test -f table", 61 | "lint:styles": "npx stylelint ./app/styles/*.scss -f verbose" 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /plugin-guide.md: -------------------------------------------------------------------------------- 1 | The WCAG-EM Reporter was build with the idea in mind that other 2 | developers would have to extend the tool with components specific to their 3 | work flow. The reporter was not intended to be the catch-all solution. 4 | 5 | Because of this, features have been added that allow third party developers 6 | to create plugins for wcag-em reporter. 7 | 8 | # Decorators 9 | 10 | The following directives can be extended: 11 | 12 | - scAuditDirective 13 | - scResult 14 | 15 | These directives can be extended by creating additional link functions 16 | that are set during the config stage of the angular app. To add a plugin 17 | Angular's `$provide.decorator()` method is used. Because we're manipulating 18 | a directive, the term `Directive` must be added to the end of the name. 19 | This works as follows: 20 | 21 | // Tell the app to run this config function, and use $provider 22 | angular.module('wcagReporter').config(function($provide) { 23 | // Decorate the scAudit directive 24 | $provide.decorator('scAuditDirective', function($delegate) { 25 | // The directive is the first item on the $deletate list 26 | var directive = $delegate[0]; 27 | // Push an object 28 | directive.plugins.push({ 29 | link: function (scope, elm, attr) { 30 | console.log('Plugin is working'); 31 | } 32 | }); 33 | return $delegate; 34 | }); 35 | }); 36 | 37 | Currently, the plugin structure is kept very basic. An array called 38 | `plugins` is on each directive that can be decorated. Any `link` function 39 | on objects put on the array will be called (in order) during the link step. 40 | Other properties of directives are not supported and will be added as the 41 | need for them arises. -------------------------------------------------------------------------------- /structure redesign: -------------------------------------------------------------------------------- 1 | # Roadmap WeRT 2 | 3 | 1.1 4 | - Recreate the navigation bar 5 | - Improved integration with auditing tools 6 | - Refactored the tool for easier maintenance 7 | - Set up basic testing 8 | - Add multi-language support 9 | 10 | 11 | 1.2 12 | - Toolbars for the audit screen 13 | - Save to and load from REST API, including autosave 14 | - Support more EARL features 15 | - WCAG-EM validation messages 16 | - Final report customisation 17 | - Improved documentation 18 | 19 | later 20 | - Option to add screen grabs 21 | - Support for auditing and reporting subsites 22 | 23 | - Improved design 24 | - Backend for managing evaluations and reëvaluations 25 | - Export to PDF 26 | 27 | 28 | --- Current state --- 29 | @ wcagReporter 30 | wcagReporterExport 31 | evalModel 32 | evalTestModel 33 | evalScopeModel- 34 | wcag20spec 35 | wcag20specData- 36 | CriterionAssert 37 | wcag20spec... 38 | evalSampleModel... 39 | currentUser- 40 | TestCaseAssert 41 | evalSampleModel 42 | Page- 43 | currentUser- 44 | TestCaseAssert... 45 | evalExploreModel 46 | knownTechService- 47 | evalSampleModel... 48 | evalReportModel- 49 | evalContextService- 50 | reportStorage 51 | appState- 52 | 53 | evalLoaderService 54 | evalWindow 55 | wcagReporterImport 56 | evalModel.. 57 | currentUser- 58 | reportStorageService 59 | appState- 60 | appState- 61 | fileReader- 62 | wcagReporterImport.. 63 | 64 | -------- 65 | General rules: 66 | - Models don't require services 67 | - Models contain domain logic 68 | - Services contain application logic 69 | - Controllers connect views to models/services 70 | 71 | 72 | @ wertUtill 73 | 74 | fileReader (fileStorage) 75 | evalWindow (windowManager) 76 | jsonLd 77 | promise 78 | 79 | 80 | @ wertStorage 81 | @ wertUtill 82 | 83 | _fileReader (fileStorage) 84 | reportStorage (networkStorage) 85 | evalLoaderService 86 | _evalWindow 87 | 88 | 89 | @ wertModelComponents 90 | 91 | Page 92 | CriterionAssert 93 | TestCaseAssert 94 | wcag20spec 95 | wcag20specData 96 | knownTechService (knownTech) 97 | 98 | 99 | @ wertModel 100 | @ wertModelComponents 101 | 102 | evalModel (evaluationModel) 103 | evalScopeModel (scopeModel) 104 | _wcag20spec 105 | _knownTechService 106 | evalExploreModel (exploreModel) 107 | evalSampleModel (sampleModel) 108 | _Page 109 | evalTestModel (auditModel) 110 | _CriterionAssert 111 | evalReportModel- (reportModel) 112 | evaluationImport 113 | evaluationExport 114 | 115 | 116 | 117 | @ WcagEmReportTool 118 | @ wertControllers 119 | @ wertModels 120 | @ wertModelComponents 121 | @ wertStorage 122 | @ wertUtill 123 | 124 | appState (wertAppMain) 125 | evalModel 126 | 127 | 128 | --- Module structure --- 129 | -------------------------------------------------------------------------------- /stylelint.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Stylelint configuration for WCAG-EM Reporting Tool 3 | * --- 4 | * Intended to adhere to a consistent style notation 5 | * and to improve readabillity. 6 | * 7 | * @type {Object} 8 | */ 9 | module.exports = { 10 | extends: 'stylelint-config-standard', 11 | plugins: ['stylelint-scss'], 12 | rules: { 13 | 14 | /** 15 | * Enable scss at-rule to add scss at-rules to whitelist 16 | */ 17 | 'at-rule-no-unknown': null, 18 | 'scss/at-rule-no-unknown': true, 19 | 20 | /** 21 | * Force multiline declarations 22 | * @type {Array} 23 | */ 24 | 'block-closing-brace-newline-before': 'always', 25 | 'block-opening-brace-newline-after': 'always', 26 | 27 | /** 28 | * Add empty line before comments. 29 | * Comments belong to folowing ruleblocks. 30 | */ 31 | 'comment-empty-line-before': 'always', 32 | 33 | /** 34 | * Add extra empty line between rule blocks 35 | */ 36 | 'rule-empty-line-before': [ 37 | 'always', 38 | { 39 | ignore: ['after-comment'] 40 | } 41 | ], 42 | 43 | /** 44 | * Attribute selector require quotes (consistency), like: 45 | * 46 | * [attribute="value"] 47 | */ 48 | 'selector-attribute-quotes': 'always' 49 | } 50 | }; 51 | -------------------------------------------------------------------------------- /test/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "env": { 3 | "jasmine": true 4 | }, 5 | "globals": { 6 | "inject": "readonly", 7 | "setupwcagReporterTest": "readonly" 8 | } 9 | }; 10 | -------------------------------------------------------------------------------- /test/runner.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | End2end Test Runner 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /test/setup.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function setupwcagReporterTest () { 4 | beforeEach(module( 5 | 'wcagReporter', 6 | function ($provide, $translateProvider) { 7 | $provide.factory('customLoader', function ($q) { 8 | return function () { 9 | var deferred = $q.defer(); 10 | deferred.resolve({}); 11 | return deferred.promise; 12 | }; 13 | }); 14 | $translateProvider.useLoader('customLoader'); 15 | } 16 | )); 17 | 18 | beforeEach(module('wertDummy')); 19 | } 20 | -------------------------------------------------------------------------------- /test/spec/controllers/evaluation/audit/samplePages.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | describe('Controller: AuditSamplePagesCtrl', function () { 3 | // load the service's module 4 | setupwcagReporterTest(); 5 | 6 | var scope; 7 | var ctrl; 8 | var evalModel; 9 | var sampleModel; 10 | 11 | beforeEach(inject(function ($controller, $rootScope, _evalModel_) { 12 | scope = $rootScope.$new(); 13 | ctrl = $controller('AuditSamplePagesCtrl', { $scope: scope }); 14 | evalModel = _evalModel_; 15 | sampleModel = evalModel.sampleModel; 16 | 17 | expect(sampleModel.randomSample.webpage.length) 18 | .toBe(0); 19 | expect(sampleModel.structuredSample.webpage.length) 20 | .toBe(0); 21 | })); 22 | 23 | it('gives access to structured and random sample', function () { 24 | expect(scope.randomSample) 25 | .toBe(sampleModel.randomSample); 26 | 27 | expect(scope.structuredSample) 28 | .toBe(sampleModel.structuredSample); 29 | }); 30 | 31 | it('has access to filled pages', function () { 32 | var filledPages = scope.filledPages(); 33 | expect(filledPages.length) 34 | .toBe(0); 35 | 36 | var page0 = sampleModel.addNewPage(); 37 | var page1 = sampleModel.addNewPage(); 38 | var page2 = sampleModel.addNewPage(); 39 | var page3 = sampleModel.addNewPage(); 40 | 41 | page0.title = 'foo'; 42 | page1.title = 'bar'; 43 | 44 | filledPages = scope.filledPages(); 45 | expect(filledPages[0]) 46 | .toBe(page0); 47 | expect(filledPages[1]) 48 | .toBe(page1); 49 | expect(filledPages.length) 50 | .toBe(2); 51 | 52 | page2.description = 'http://foo.com'; 53 | page3.description = 'http://bar.com'; 54 | filledPages = scope.filledPages(); 55 | expect(filledPages[2]) 56 | .toBe(page2); 57 | expect(filledPages[3]) 58 | .toBe(page3); 59 | expect(filledPages.length) 60 | .toBe(4); 61 | 62 | page2.description = ''; 63 | page3.description = ''; 64 | filledPages = scope.filledPages(); 65 | expect(filledPages[0]) 66 | .toBe(page0); 67 | expect(filledPages[1]) 68 | .toBe(page1); 69 | expect(filledPages.length) 70 | .toBe(2); 71 | 72 | page0.title = ''; 73 | page1.title = ''; 74 | filledPages = scope.filledPages(); 75 | expect(filledPages.length) 76 | .toBe(0); 77 | }); 78 | 79 | it('complete and uncomplete selected pages', function () { 80 | var page0 = sampleModel.addNewPage(); 81 | var page1 = sampleModel.addNewPage(); 82 | 83 | expect(sampleModel.getSelectedPages().length) 84 | .toBe(0); 85 | 86 | page0.selected = true; 87 | page1.selected = true; 88 | 89 | scope.completePages(); 90 | expect(page0.tested) 91 | .toBe(true); 92 | expect(page1.tested) 93 | .toBe(true); 94 | 95 | page0.selected = false; 96 | scope.uncompletePages(); 97 | expect(page0.tested) 98 | .toBe(true); 99 | expect(page1.tested) 100 | .toBe(false); 101 | 102 | page0.selected = true; 103 | page1.selected = false; 104 | scope.uncompletePages(); 105 | expect(page0.tested) 106 | .toBe(false); 107 | expect(page1.tested) 108 | .toBe(false); 109 | 110 | page0.selected = false; 111 | expect(sampleModel.getSelectedPages().length) 112 | .toBe(0); 113 | }); 114 | }); 115 | -------------------------------------------------------------------------------- /test/spec/controllers/evaluation/report.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | describe('Controller: EvalReportCtrl', function () { 3 | var modelName = 'reportModel'; 4 | 5 | // load the service's module 6 | setupwcagReporterTest(); 7 | 8 | var scope; 9 | var ctrl; 10 | var model; 11 | 12 | beforeEach(inject(function ($controller, $rootScope, _evalModel_) { 13 | scope = $rootScope.$new(); 14 | ctrl = $controller('EvalReportCtrl', { $scope: scope }); 15 | model = _evalModel_[modelName]; 16 | })); 17 | 18 | it('Should be able to update the evalModel.' + modelName, function () { 19 | expect(scope[modelName]) 20 | .toBe(model); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /test/spec/controllers/evaluation/scope.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | describe('Controller: EvalScopeCtrl', function () { 3 | var modelName = 'scopeModel'; 4 | 5 | // load the service's module 6 | setupwcagReporterTest(); 7 | 8 | var scope; 9 | var ctrl; 10 | var model; 11 | 12 | beforeEach(inject(function ($controller, $rootScope, evalModel) { 13 | scope = $rootScope.$new(); 14 | ctrl = $controller('EvalScopeCtrl', { $scope: scope }); 15 | model = evalModel[modelName]; 16 | })); 17 | 18 | it('Should be able to update the evalModel.' + modelName, function () { 19 | expect(scope[modelName]) 20 | .toBe(model); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /test/spec/models/wcag2spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('model: wcag2spec', function () { 4 | // load the service's module 5 | setupwcagReporterTest(); 6 | 7 | // instantiate service 8 | var wcag2spec; 9 | beforeEach( 10 | inject(function (_wcag2spec_) { 11 | wcag2spec = _wcag2spec_; 12 | }) 13 | ); 14 | 15 | beforeEach(function (done) { 16 | inject(function ($rootScope) { 17 | $rootScope.$on('wcag2spec:langChange', done); 18 | }); 19 | }); 20 | 21 | describe('getPrinciples', function () { 22 | var principles; 23 | 24 | beforeEach(function () { 25 | principles = wcag2spec.getPrinciples(); 26 | }); 27 | 28 | it('should return an array', function () { 29 | expect(jQuery.isArray(principles)) 30 | .toBe(true); 31 | }); 32 | 33 | it('should contain guidelines', function () { 34 | principles.forEach(function (p) { 35 | expect(jQuery.isArray(p.guidelines)) 36 | .toBe(true); 37 | }); 38 | }); 39 | }); 40 | 41 | describe('getGuidelines', function () { 42 | var guidelines; 43 | 44 | beforeEach(function () { 45 | guidelines = wcag2spec.getGuidelines(); 46 | }); 47 | 48 | it('should return an array', function () { 49 | expect(jQuery.isArray(guidelines)) 50 | .toBe(true); 51 | }); 52 | 53 | it('should contain successcriteria', function () { 54 | guidelines.forEach(function (g) { 55 | expect(jQuery.isArray(g.successcriteria)) 56 | .toBe(true); 57 | }); 58 | }); 59 | }); 60 | 61 | describe('getCriteria', function () { 62 | var criteria; 63 | 64 | beforeEach(function () { 65 | criteria = wcag2spec.getCriteria(); 66 | }); 67 | 68 | it('should return an array', function () { 69 | expect(jQuery.isArray(criteria)) 70 | .toBe(true); 71 | }); 72 | }); 73 | 74 | describe('getCriterion', function () { 75 | it('should return a criterion with the given ID (WCAG2:non-text-content)', function () { 76 | var criterionId = 'WCAG2:non-text-content'; 77 | var criterion = wcag2spec.getCriterion(criterionId); 78 | 79 | expect(typeof criterion) 80 | .toBe('object'); 81 | 82 | expect(criterion.id) 83 | .toBe(criterionId); 84 | }); 85 | 86 | it('should return undefined if the ID is unknown', function () { 87 | var getCriterion = wcag2spec.getCriterion; 88 | 89 | // No ID passed to getCriterion 90 | expect(typeof getCriterion()) 91 | .toBe('undefined'); 92 | 93 | [ 94 | '', 95 | 'someUnknownId' 96 | ].forEach(function (unknownId) { 97 | var criterion = getCriterion(unknownId); 98 | 99 | expect(typeof criterion) 100 | .toBe('undefined'); 101 | }); 102 | }); 103 | }); 104 | }); 105 | -------------------------------------------------------------------------------- /test/spec/services/evalContext.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('Service: evalContext', function () { 4 | // load the service's module 5 | setupwcagReporterTest(); 6 | 7 | // instantiate service 8 | var evalContext; 9 | beforeEach(inject(function (evalContextV2) { 10 | evalContext = evalContextV2; 11 | })); 12 | 13 | beforeEach(function (done) { 14 | inject(function ($rootScope) { 15 | $rootScope.$on('wcag2spec:langChange', done); 16 | }); 17 | }); 18 | 19 | it('should be an object', function () { 20 | expect(typeof evalContext) 21 | .toBe('object'); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /w3c.json: -------------------------------------------------------------------------------- 1 | { 2 | "group": 35532 3 | , "contacts": [ "nitedog", "yatil", "slhenry" ] 4 | , "policy": "open" 5 | , "repo-type": "article" 6 | } 7 | --------------------------------------------------------------------------------