├── .github └── workflows │ └── npm-test.yml ├── .travis.yml ├── LICENSE ├── README.md ├── Wikiapi.js ├── _CeL.loader.nodejs.js ├── _test suite └── test.js ├── docs ├── Wikiapi.html ├── fonts │ ├── Montserrat │ │ ├── Montserrat-Bold.eot │ │ ├── Montserrat-Bold.ttf │ │ ├── Montserrat-Bold.woff │ │ ├── Montserrat-Bold.woff2 │ │ ├── Montserrat-Regular.eot │ │ ├── Montserrat-Regular.ttf │ │ ├── Montserrat-Regular.woff │ │ └── Montserrat-Regular.woff2 │ ├── OpenSans-Bold-webfont.eot │ ├── OpenSans-Bold-webfont.svg │ ├── OpenSans-Bold-webfont.woff │ ├── OpenSans-BoldItalic-webfont.eot │ ├── OpenSans-BoldItalic-webfont.svg │ ├── OpenSans-BoldItalic-webfont.woff │ ├── OpenSans-Italic-webfont.eot │ ├── OpenSans-Italic-webfont.svg │ ├── OpenSans-Italic-webfont.woff │ ├── OpenSans-Light-webfont.eot │ ├── OpenSans-Light-webfont.svg │ ├── OpenSans-Light-webfont.woff │ ├── OpenSans-LightItalic-webfont.eot │ ├── OpenSans-LightItalic-webfont.svg │ ├── OpenSans-LightItalic-webfont.woff │ ├── OpenSans-Regular-webfont.eot │ ├── OpenSans-Regular-webfont.svg │ ├── OpenSans-Regular-webfont.woff │ └── Source-Sans-Pro │ │ ├── sourcesanspro-light-webfont.eot │ │ ├── sourcesanspro-light-webfont.svg │ │ ├── sourcesanspro-light-webfont.ttf │ │ ├── sourcesanspro-light-webfont.woff │ │ ├── sourcesanspro-light-webfont.woff2 │ │ ├── sourcesanspro-regular-webfont.eot │ │ ├── sourcesanspro-regular-webfont.svg │ │ ├── sourcesanspro-regular-webfont.ttf │ │ ├── sourcesanspro-regular-webfont.woff │ │ └── sourcesanspro-regular-webfont.woff2 ├── global.html ├── index.html ├── scripts │ ├── collapse.js │ ├── linenumber.js │ ├── nav.js │ ├── polyfill.js │ ├── prettify │ │ ├── Apache-License-2.0.txt │ │ ├── lang-css.js │ │ └── prettify.js │ └── search.js ├── styles │ ├── jsdoc-default.css │ ├── jsdoc.css │ ├── prettify-jsdoc.css │ ├── prettify-tomorrow.css │ └── prettify.css └── wikiapi.js.html └── package.json /.github/workflows/npm-test.yml: -------------------------------------------------------------------------------- 1 | # https://github.com/actions/starter-workflows/blob/main/ci/node.js.yml 2 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node 3 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 4 | 5 | name: Node.js CI test 6 | 7 | on: 8 | push: 9 | branches: [ master ] 10 | pull_request: 11 | branches: [ master ] 12 | 13 | jobs: 14 | test: 15 | 16 | runs-on: ubuntu-latest 17 | 18 | strategy: 19 | matrix: 20 | # https://nodejs.org/en/about/releases/ 21 | node-version: [ 20.x, 21.x ] 22 | # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ 23 | 24 | steps: 25 | - uses: actions/checkout@v2 26 | - name: Use Node.js ${{ matrix.node-version }} 27 | uses: actions/setup-node@v1 28 | with: 29 | #token: ${{ secrets.CODECOV_TOKEN }} 30 | node-version: ${{ matrix.node-version }} 31 | - run: npm install 32 | #- run: npm ci 33 | #- run: npm run build --if-present 34 | - run: npm run test 35 | 36 | # https://github.community/t/how-to-implement-an-after-success-action/16919/5 37 | - name: report-coverage 38 | if: ${{ success() }} 39 | run: npm run report-coverage 40 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | env: 2 | global: 3 | secure: 4 | 5 | language: node_js 6 | node_js: 7 | - "14" 8 | - "15" 9 | 10 | # https://github.com/codecov/example-node 11 | install: 12 | - npm install 13 | # move to devDependencies @ package.json 14 | #- npm install -g nyc 15 | #- npm install -g codecov 16 | 17 | script: 18 | - npm test 19 | 20 | after_success: 21 | - npm run report-coverage 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD-3-Clause License 2 | 3 | Copyright (c) 2022, kanasimi 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 11 | 12 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![npm version](https://badge.fury.io/js/wikiapi.svg)](https://www.npmjs.com/package/wikiapi) 2 | [![npm downloads](https://img.shields.io/npm/dm/wikiapi.svg)](https://www.npmjs.com/package/wikiapi) 3 | [![GitHub Actions workflow build status](https://github.com/kanasimi/wikiapi/actions/workflows/npm-test.yml/badge.svg)](https://github.com/kanasimi/wikiapi/actions) 4 | [![codecov](https://codecov.io/gh/kanasimi/wikiapi/branch/master/graph/badge.svg)](https://codecov.io/gh/kanasimi/wikiapi) 5 | 6 | [![Known Vulnerabilities](https://snyk.io/test/github/kanasimi/wikiapi/badge.svg?targetFile=package.json)](https://snyk.io/test/github/kanasimi/wikiapi?targetFile=package.json) 7 | [![codebeat badge](https://codebeat.co/badges/47d3b442-fd49-4142-a69b-05171bf8fe36)](https://codebeat.co/projects/github-com-kanasimi-wikiapi-master) 8 | [![Codacy Badge](https://app.codacy.com/project/badge/Grade/bfb4fe9fe6e04346986f5cc83099369e)](https://www.codacy.com/gh/kanasimi/wikiapi/dashboard?utm_source=github.com&utm_medium=referral&utm_content=kanasimi/wikiapi&utm_campaign=Badge_Grade) 9 | [![DeepScan grade](https://deepscan.io/api/teams/4788/projects/6757/branches/58325/badge/grade.svg)](https://deepscan.io/dashboard#view=project&tid=4788&pid=6757&bid=58325) 10 | 11 | # JavaScript MediaWiki API 12 |

13 | Wikiapi logo 14 |

15 | 16 | A simple way to access MediaWiki API via JavaScript with [wikitext parser](https://kanasimi.github.io/CeJS/_test%20suite/wikitext_parser.html). 17 | This is basically a modern syntax version of [CeJS MediaWiki module](https://github.com/kanasimi/CeJS/blob/master/application/net/wiki). For example, using [async functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function). 18 | 19 | ## Features 20 | * Read / edit pages. 21 | * Get list of categorymembers, pages transclude specified template, and more... 22 | * Auto-limited editing rate. 23 | * Parse wikitext / pages. You may modify parts of the wikitext, then regenerate the page just using .toString(). See [wikitext parser examples](https://kanasimi.github.io/CeJS/_test%20suite/wikitext_parser.html). 24 | 25 | ## Installation 26 | This is a nodejs module. Please install [node.js](https://nodejs.org/) first. 27 | 28 | ```bash 29 | npm install wikiapi 30 | ``` 31 | 32 | ## Usage 33 | Here lists some examples of this module. 34 | * [Login to wiki site](https://kanasimi.github.io/wikiapi/Wikiapi.html#login) 35 | * [Login to wiki site #1](https://kanasimi.github.io/wikiapi/Wikiapi.html#example__Login%20to%20wiki%20site%201) 36 | * [Login to wiki site #2](https://kanasimi.github.io/wikiapi/Wikiapi.html#example__Login%20to%20wiki%20site%202) 37 | * [Get page data and parse the wikitext](https://kanasimi.github.io/wikiapi/Wikiapi.html#page) 38 | * [Listen to page modification](https://kanasimi.github.io/wikiapi/Wikiapi.html#listen) 39 | * [Edit page](https://kanasimi.github.io/wikiapi/Wikiapi.html#edit) 40 | * [Edit multiple pages](https://kanasimi.github.io/wikiapi/Wikiapi.html#for_each_page) 41 | * [Get category tree](https://kanasimi.github.io/wikiapi/Wikiapi.html#category_tree) 42 | * [Get wikidata](https://kanasimi.github.io/wikiapi/Wikiapi.html#data) 43 | * [Upload file / media](https://kanasimi.github.io/wikiapi/Wikiapi.html#upload) 44 | * [Upload file / media](https://kanasimi.github.io/wikiapi/Wikiapi.html#example__Upload%20file%20/%20media) 45 | * [Download file / media](https://kanasimi.github.io/wikiapi/Wikiapi.html#download) 46 | * [Move page](https://kanasimi.github.io/wikiapi/Wikiapi.html#move_page) 47 | 48 | ### As node.js module 49 | ```javascript 50 | // Load Wikiapi module 51 | const Wikiapi = require('wikiapi'); 52 | 53 | // OPEN ASYNC DOMAIN: 54 | (async () => { 55 | 56 | // LOGIN IN: In any wiki, any language 57 | const wiki = new Wikiapi('zh'); // or new Wikiapi('https://zh.wikipedia.org/w/api.php') 58 | await wiki.login('user', 'password'); // get your own account and password on your target wiki. 59 | 60 | 61 | /* ***************************************************** */ 62 | /* READ ONLY ******************************************* */ 63 | // load page 64 | let page_data = await wiki.page('Universe', {}); 65 | console.log('page_data: ', page_data); 66 | console.log('page_data.text: ', page_data.wikitext); 67 | 68 | // Get multi revisions (ex: 2) 69 | let page_data = await wiki.page('Universe', { revisions: 2 }); 70 | console.log('page_data: ', page_data); 71 | console.log('page_data.text: ', page_data.wikitext); 72 | 73 | /* ***************************************************** */ 74 | /* EDITING ********************************************* */ 75 | /* Note: .page() then .edit() ************************** */ 76 | // Edit page: append content, as bot. 77 | let page_data = await wiki.page('Universe'), 78 | newContent = page_data.wikitext + '\nTest edit using wikiapi.'; 79 | await enwiki.edit( 80 | function (page_data) { return newContent; }, // new content 81 | { bot: 1, summary: 'Test edit.' } // options 82 | ); 83 | 84 | // Edit page: replace content, with more options. 85 | let page_data = await wiki.page('Universe'), 86 | newContent = page_data.wikitext.replace(/Test edit using wikiapi/g, 'Test: replace content was successful!'); 87 | await enwiki.edit( 88 | function (page_data) { return newContent; }, // new content 89 | { bot: 1, minor: 1, nocreate: 1, summary: 'Test: replace content.' } // more options 90 | ); 91 | 92 | // Edit page: wipe clean, replace by string 93 | let page_data = await wiki.page('Universe'); 94 | await wiki.edit( 95 | '{{Speedy|reason=Vandalism}}', 96 | { bot: 1, minor: 0, nocreate: 1, summary: 'Test: wipe clean, please delete.' } 97 | ); 98 | 99 | /* edit_page(): a more direct method ******************* */ 100 | // Edit page: 101 | await wiki.edit_page('Wikipedia:Sandbox', function (page_data) { 102 | return page_data.wikitext + '\nTest edit using {{GitHub|kanasimi/wikiapi}}.'; 103 | }, { bot: 1, nocreate: 1, minor: 1, summary: 'Test: edit page via .edit_page().' }); 104 | 105 | 106 | /* ***************************************************** */ 107 | /* PROVIDE MANY **************************************** */ 108 | // List of hand-picked target pages 109 | let list = ['Wikipedia:Sandbox', 'Wikipedia:Sandbox2', 'Wikipedia:Sandbox/wikiapi']; 110 | // List pages in [[Category:Chemical_elements]] 111 | let listMembers = await wiki.categorymembers('Chemical elements'); // array of titles 112 | // List intra-wiki links in [[ABC]] 113 | let listLinks = await wiki.redirects_here('ABC'); // array of titles 114 | // List of transcluded pages {{w:en:Periodic table}} 115 | let listTranscluded = await wiki.embeddedin('Template:Periodic table'); 116 | // List of searched pages with expression in its title name 117 | let listSearch = await wiki.search(' dragon'); // array of titles 118 | 119 | /* ***************************************************** */ 120 | /* MULTI-read/edit ************************************* */ 121 | // Multi edit, members of category 122 | await wiki.for_each_page( 123 | listMembers, 124 | page_data => { return `{{stub}}\n` + page_data.wikitext; }, 125 | { summary: 'Test: multi-edits', minor: 1 } 126 | ); 127 | 128 | // Multi read, following intra-wiki links 129 | await wiki.for_each_page( 130 | listLinks, // array of targets 131 | page_data => { 132 | console.log(page_data.title); // print page title 133 | return Wikiapi.skip_edit; // skip edit, just read, return nothing to edit with. 134 | }, // no edit therefore no options 135 | ); 136 | 137 | 138 | /* ***************************************************** */ 139 | /* MOVE PAGE (RENAME) ********************************** */ 140 | // Move page once. 141 | result = await wiki.move_page('Wikipedia:Sanbox/Wikiapi', 'Wikipedia:Sanbox/NewWikiapi', 142 | { reason: 'Test: move page (1).', noredirect: true, movetalk: true } 143 | ); 144 | // Reverse move 145 | result = await wiki.move_page('Wikipedia:Sanbox/NewWikiapi', 'Wikipedia:Sanbox/Wikiapi', 146 | { reason: 'Test: move page (2).', noredirect: true, movetalk: true } 147 | ); 148 | 149 | 150 | /* ***************************************************** */ 151 | /* PARSE *********************************************** */ 152 | // Read Infobox templates, convert to JSON. 153 | const page_data = await wiki.page('JavaScript'); 154 | // `page_data.parse(options)` will startup the parser process, create page_data.parsed. After .parse(), we can use parsed.each(). 155 | const parsed = page_data.parse(); 156 | let infobox; 157 | parsed.each('template', template_token => { 158 | if (template_token.name.startsWith('Infobox')) { 159 | infobox = template_token.parameters; 160 | return parsed.each.exit; 161 | } 162 | }); 163 | for (const [key, value] of Object.entries(infobox)) 164 | infobox[key] = value.toString(); 165 | // print json of the infobox 166 | console.log(infobox); 167 | 168 | // Edit page and parse 169 | const parsed = await wiki.page('Wikipedia:Sandbox').parse(); 170 | parsed.each('template', template_token => {/* modify token */ }); 171 | await wiki.edit(parsed.toString(), { bot: 1, minor: 1, nocreate: 1 }); 172 | 173 | let page_data = await wiki.page('Universe'); 174 | // See all type in wiki_toString @ https://github.com/kanasimi/CeJS/tree/master/application/net/wiki/parser.js 175 | // List all template name. 176 | page_data.parse().each('template', 177 | token => console.log(token.name)); 178 | 179 | /* ***************************************************** */ 180 | /* MONITORING ****************************************** */ 181 | // Listen to new edits, check every 2 minutes 182 | wiki.listen(function for_each_row() { 183 | // ... 184 | }, { 185 | // 檢查的延遲時間。 186 | delay: '2m', 187 | filter: function filter_row(row) { 188 | // row is the same format as page_data 189 | }, 190 | // also get diff 191 | with_diff: { LCS: true, line: true }, 192 | // only for articles (0:main namespace) and talk pages 193 | namespace: '0|talk', 194 | }); 195 | 196 | /* ***************************************************** */ 197 | /* FILES *********************************************** */ 198 | // Set upload parameters, maily for licensing reasons. 199 | // Note: parameter `text`, filled with the right wikicode `{{description|}}`, can replace most parameters. 200 | let options = { 201 | description: 'Photo of Osaka', 202 | date: new Date() || '2021-01-01', 203 | source_url: 'https://github.com/kanasimi/wikiapi', 204 | author: '[[User:user]]', 205 | permission: '{{cc-by-sa-2.5}}', 206 | other_versions: '', 207 | other_fields: '', 208 | license: ['{{cc-by-sa-2.5}}'], 209 | categories: ['[[Category:test images]]'], 210 | bot: 1, 211 | tags: "tag1|tag2", 212 | }; 213 | 214 | // Upload file from local path 215 | let result = await wiki.upload({ 216 | file_path: '/local/file/path', 217 | filename: 'New_Osaka_Photograph.jpg', // default : keep filename 218 | comment: '', 219 | ignorewarnings: 1, // overwrite 220 | ...options 221 | }); 222 | 223 | // Upload file from URL 224 | result = await wiki.upload({ 225 | media_url: 'https://media.url/Thunder-Dragon.ogg', 226 | text: "Her eis wikicode to replave the page's content instead of various other parameters.", 227 | comment: 'Thunder Dragon audio from vacation in Philipines. Page uses custom template.', 228 | ignorewarnings: 1, // overwrite 229 | ...options 230 | }); 231 | 232 | 233 | /* ***************************************************** */ 234 | /* WIKIDATA, WIKIBASES ********************************* */ 235 | // Read Qid Q1 (Universe), print Chinese label 236 | const wiki = new Wikiapi('https://wikidata.org/w/api.php') 237 | let page_data = await wiki.data('Q1'); 238 | console.log(page_data.labels.zh) // '宇宙' 239 | 240 | // Read, access by title (English), access property P1419 241 | // Get P1419 of wikidata entity: 'Universe' 242 | let data = await wiki.data('Universe', 'P1419'); 243 | // assert: {Array}data = [ 'shape of the universe', '...', ... ] 244 | console.assert(data.includes('shape of the universe')); 245 | 246 | // update wikidata 247 | // Get https://test.wikidata.org/wiki/Q7 248 | let entity = await wiki.data('Q7'); 249 | // search [ language, label ] 250 | //entity = await wiki.data(['en', 'Earth']); 251 | 252 | // Update claim 253 | await entity.modify({ claims: [{ P17: 'Q213280' }] }); 254 | // Update claim: set country (P17) to 'Test Country 1' (Q213280) ([language, label] as entity) 255 | await entity.modify({ claims: [{ language: 'en', country: [, 'Test Country 1'] }] }); 256 | // Remove country (P17) : 'Test Country 1' (Q213280) 257 | await entity.modify({ claims: [{ language: 'en', country: [, 'Test Country 1'], remove: true }] }); 258 | 259 | // Update label 260 | await entity.modify({ labels: [{ language: 'zh-tw', value: '地球' }] }); 261 | 262 | // CLOSE ASYNC DOMAIN: 263 | })(); 264 | ``` 265 | 266 | More examples: Please see [test.js](https://github.com/kanasimi/wikiapi/blob/master/_test%20suite/test.js). 267 | 268 | ### User agent 269 | By default, the library will use the user agent `get_URL_node.default_user_agent` set in [Ajax.js](https://github.com/kanasimi/CeJS/blob/master/application/net/Ajax.js). If you want to [set another user agent](https://meta.wikimedia.org/wiki/User-Agent_policy), you can change `CeL.wiki.query.get_URL_options` listed in [query.js](https://github.com/kanasimi/CeJS/blob/master/application/net/wiki/query.js): 270 | ```javascript 271 | CeL.wiki.query.get_URL_options.headers['User-Agent'] = 'testbot/1.0'; 272 | ``` 273 | 274 | ## OS support 275 | | Platform | support | 276 | | ----------- | ------- | 277 | | Windows | ✔️ | 278 | | macOS | ✔️ | 279 | | UNIX, Linux | ✔️ | 280 | 281 | ## See also 282 | For old style JavaScript, or general environment usage, please see [wikibot](https://github.com/kanasimi/wikibot). 283 | 284 | ## Contact 285 | Contact us at [GitHub](https://github.com/kanasimi/wikiapi/issues). 286 | 287 | [![logo](https://raw.githubusercontent.com/kanasimi/CeJS/master/_test%20suite/misc/logo.jpg)](http://lyrics.meicho.com.tw/) 288 | -------------------------------------------------------------------------------- /_CeL.loader.nodejs.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name framework loader for node.js. 3 | * 4 | * @fileoverview Example to include CeL (CeJS) in node.js. node.js 下之 CeL 5 | * 簡易加載器。本檔僅包括含入並運用 node.loader.js 的最精簡程式碼。
6 | * Copy from: 7 | * https://github.com/kanasimi/CeJS/blob/master/_for%20include/_CeL.loader.nodejs.js 8 | * 9 | * usage: See ../README.md 10 | */ 11 | 12 | typeof CeL !== 'function' && (function() { 13 | "use strict"; 14 | 15 | var full_root = module.filename /* require('electron').app.getPath('userData') */ 16 | // TODO: 17 | // https://www.electronjs.org/docs/latest/api/app#appgetpathname 18 | // https://stackoverflow.com/questions/71365401/how-to-read-config-file-in-electronjs-app 19 | && module.filename.replace(/[^\\\/]+$/, ''), 20 | // WARNING: repository_path_list_file should be an absolute path in some 21 | // environment. 22 | repository_path_list_file 23 | // 24 | = (full_root || './') + '_repository_path_list.txt', 25 | // 26 | matched = full_root.match(/^(.+?[\\\/])_for include[\\\/]$/), 27 | // 28 | node_fs = require('fs'), 29 | // 30 | CeL_path_list = node_fs.readFileSync(repository_path_list_file); 31 | CeL_path_list = CeL_path_list && CeL_path_list.toString() || ''; 32 | 33 | if (matched) { 34 | // `CeL_path_list` should not be "" here, 35 | // but it doesn’t matter. 36 | 37 | // 直接 require 函式庫下面的本檔案。 e.g., 38 | // require('path\\JS\\_for include\\_CeL.loader.nodejs.js'); 39 | // 如此可以不依靠 repository_path_list_file。 40 | // ** 這時應該採用: require('path/to/node.loader.js'); 41 | CeL_path_list += '\n' + matched[1]; 42 | } 43 | 44 | if (!CeL_path_list) { 45 | console.error( 46 | // 47 | 'Please set the absolute path list of CeL library in the file [' 48 | // 49 | + repository_path_list_file + ']!'); 50 | return; 51 | } 52 | 53 | // ---------------------------------------------------------------------------- 54 | // Load CeJS library. For node.js loading. 55 | // Copy/modified from "/_for include/_CeL.loader.nodejs.js". 56 | 57 | function check_path(path) { 58 | path = path.trim(); 59 | if (!path || path.charAt(0) === '#') { 60 | // path is comments or blank line 61 | return; 62 | } 63 | // console.log('Try path: ' + JSON.stringify(path)); 64 | try { 65 | // old node.js has no method 'accessSync'. 66 | // accessSync() added in: v0.11.15 67 | if (node_fs.accessSync) { 68 | // accessSync() throws if any accessibility checks fail, 69 | // and does nothing otherwise. 70 | node_fs.accessSync(path); 71 | } else if (!node_fs.existsSync(path)) { 72 | throw 'ENOENT'; 73 | } 74 | 75 | if (!/[^\\\/]$/.test(path)) { 76 | path += require('path').sep; 77 | } 78 | if (typeof global.CeL !== 'function' 79 | // 80 | && (typeof global.CeL !== 'object' || !CeL)) { 81 | global.CeL = {}; 82 | } 83 | CeL.library_path = path + 'ce.js'; 84 | 85 | var loader = '/_for include/node.loader.js'; 86 | loader = path + (path.indexOf('/') !== -1 ? loader 87 | // 88 | : loader.replace(/\//g, '\\')); 89 | // console.log('Try loader path: ' + loader); 90 | require(loader); 91 | return CeL.version; 92 | } catch (e) { 93 | // console.error(e); 94 | // try next path 95 | } 96 | 97 | // Try the file below loader for relative path. 98 | if (full_root && !/^(?:\/|[A-Z]:\\)/i.test(path)) { 99 | return check_path(full_root + path); 100 | } 101 | } 102 | 103 | CeL_path_list.split(CeL_path_list.indexOf('\n') === -1 ? '|' : /\r?\n/) 104 | // 載入CeJS基礎泛用之功能。(例如非特殊目的使用的載入功能) 105 | .some(check_path); 106 | 107 | // If no latest version found, try to use cejs module instead. 108 | if (typeof use_cejs_mudule === 'boolean' 109 | // Set "global.use_cejs_mudule = true;" if you need to do so anyway. 110 | && use_cejs_mudule && typeof CeL !== 'function') { 111 | try { 112 | // 若有 CeJS 則用之。 113 | require('cejs'); 114 | console.log('cejs loader: use npm, not the latest version!'); 115 | return; 116 | 117 | } catch (e) { 118 | // console.error(e); 119 | } 120 | 121 | console.error('Failed to load CeJS library!\n'); 122 | console.info('Please install CeJS library first.' 123 | // 124 | + ' 請先安裝 CeJS library:\n' + 'npm install cejs\n\n' 125 | // 126 | + 'Or you may trying the latest version:\n' 127 | // 128 | + 'See https://github.com/kanasimi/CeJS'); 129 | throw 'No CeJS library'; 130 | } 131 | 132 | if (typeof CeL !== 'function') { 133 | console.error('Failed to load CeL!'); 134 | console.error('current working directory: ' + process.cwd()); 135 | console.error('main script: ' 136 | // 137 | + (require.main && require.main.filename)); 138 | console.error('loader path: ' + module.filename); 139 | } 140 | 141 | })(); 142 | 143 | // ---------------------------------------------------------------------------- 144 | // Load module. 145 | 146 | // CeL.env.no_catch = true; 147 | // CeL.set_debug(2); 148 | 149 | // CeL.run([ 'data.code.compatibility' ]); 150 | -------------------------------------------------------------------------------- /_test suite/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // load module 4 | const Wikiapi = require('../Wikiapi.js'); 5 | 6 | const CeL = global.CeL; 7 | CeL.info('Using CeJS version: ' + CeL.version); 8 | 9 | // load modules for test 10 | CeL.run(['application.debug.log', 11 | // gettext(), and for .detect_HTML_language(), .time_zone_of_language() 12 | 'application.locale.gettext' 13 | ]); 14 | 15 | // ============================================================================ 16 | 17 | /** {ℕ⁰:Natural+0}count of all errors (failed + fatal) */ 18 | let all_error_count = 0; 19 | /** {ℕ⁰:Natural+0}all tests count */ 20 | let all_tests = 0; 21 | /** {ℕ⁰:Natural+0}tests done */ 22 | let test_done = 0; 23 | /** {ℕ⁰:Natural}test start time value */ 24 | const test_start_time = Date.now(); 25 | 26 | function check_tests(recorder, error_count) { 27 | all_error_count += error_count; 28 | ++test_done; 29 | if (test_done < all_tests) { 30 | return; 31 | } 32 | 33 | // finish_test 34 | 35 | // 耗時,經過時間 36 | const elapsed_message = ' Elapsed time: ' 37 | + Math.round((Date.now() - test_start_time) / 1000) + ' s.'; 38 | 39 | if (all_error_count === 0) { 40 | CeL.info(`check_tests: All ${all_tests} test group(s) done.${elapsed_message}`); 41 | // normal done. No error. 42 | return; 43 | } 44 | 45 | CeL.gettext.conversion['error'] = ['no %n', '1 %n', '%d %ns']; 46 | const error_message = CeL.gettext('All %error@1.', all_error_count) + elapsed_message; 47 | throw new Error(error_message); 48 | } 49 | 50 | function add_test(test_name, conditions) { 51 | if (!conditions) { 52 | // shift arguments: 跳過 test_name。 53 | conditions = test_name; 54 | test_name = null; 55 | } 56 | 57 | all_tests++; 58 | CeL.test(test_name, conditions, check_tests); 59 | } 60 | 61 | // ============================================================================ 62 | 63 | // Just for test 64 | delete CeL.wiki.query.default_maxlag; 65 | 66 | add_test('load page', async (assert, setup_test, finish_test) => { 67 | const enwiki = new Wikiapi('en'); 68 | let page_data; 69 | 70 | setup_test('load page: [[w:en:Universe]]'); 71 | assert(['enwiki', enwiki.site_name()], '.site_name() #1'); 72 | assert(['zhwiki', Wikiapi.site_name('zh')], '.site_name() #2'); 73 | 74 | page_data = await enwiki.page('Universe'); 75 | // console.log(CeL.wiki.title_link_of(page_data) + ':'); 76 | // console.log(page_data.wikitext); 77 | assert(page_data.wikitext.includes('space]]') 78 | && page_data.wikitext.includes('time]]'), 'load page: wikitext'); 79 | finish_test('load page: [[w:en:Universe]]'); 80 | 81 | setup_test('load page: [[w:en:Earth]]'); 82 | page_data = await enwiki.page('Earth', { 83 | revisions: 2 84 | }); 85 | // console.log(CeL.wiki.title_link_of(page_data) + ':'); 86 | // console.log(page_data.revisions); 87 | assert([page_data.revisions.length, 2], 'load page: revisions.length'); 88 | assert([page_data.wikitext, page_data.revision(0)], 'load page: revision(0)'); 89 | assert(page_data.wikitext !== page_data.revision(1), 'load page: revision(1)'); 90 | 91 | const redirects_taregt = await enwiki.redirects_root('WP:SB'); 92 | assert(['Wikipedia:Sandbox', redirects_taregt], '.redirects_root()'); 93 | const redirects_list = await enwiki.redirects_here('WP:SB'); 94 | assert(['WP:SB', redirects_list.query_title], '.redirects_here() #1'); 95 | assert(redirects_list.length > 1, '.redirects_here() #2'); 96 | assert(['Wikipedia:Sandbox', redirects_list[0].title], '.redirects_here() #3'); 97 | 98 | finish_test('load page: [[w:en:Earth]]'); 99 | }); 100 | 101 | // https://en.wikipedia.org/wiki/List_of_wikis 102 | // https://meta.wikimedia.org/wiki/List_of_largest_wikis 103 | add_test('load page of other wiki', async (assert, setup_test, finish_test) => { 104 | const wiki = new Wikiapi('https://harrypotter.fandom.com/api.php'); 105 | let page_data; 106 | 107 | setup_test('load page of other wiki: [[Harry Potter]]'); 108 | page_data = await wiki.page('Harry Potter'); 109 | // console.log(page_data.wikitext); 110 | assert(page_data.wikitext.includes('{{Individual infobox'), 'load page: wikitext of [[Harry Potter]]'); 111 | finish_test('load page of other wiki: [[Harry Potter]]'); 112 | }); 113 | 114 | // ------------------------------------------------------------------ 115 | 116 | function normally_blocked_edit(result) { 117 | // @see wiki_API.edit @ wiki.js 118 | return result.edit && result.edit.captcha 119 | // e.g., [[m:NOP|Open Proxy]] is blocked. 120 | || result.error && (result.error.code in { 121 | 'blocked': true, 122 | 'globalblocking-ipblocked-range': true, 123 | 'wikimedia-globalblocking-ipblocked-range': true, 124 | }); 125 | } 126 | 127 | function handle_edit_error(assert, error) { 128 | const result = error.result; 129 | if (normally_blocked_edit(result)) { 130 | CeL.log(`${handle_edit_error.name}: Skip blocked edit: ${result.message || result.error && result.error.code || JSON.stringify(result)}`); 131 | return; 132 | } 133 | //console.trace(result); 134 | 135 | assert(error.message === '[blocked] You have been blocked from editing.' 136 | || error.message === 'OK', 'test edit page result'); 137 | } 138 | 139 | add_test('edit page', async (assert, setup_test, finish_test) => { 140 | setup_test('edit page'); 141 | const test_page_title = 'Project:Sandbox'; 142 | const test_wikitext = '\nTest edit using {{GitHub|kanasimi/wikiapi}}.'; 143 | const bot_name = null; 144 | const password = null; 145 | 146 | const enwiki = new Wikiapi; 147 | await enwiki.login({ user_name: bot_name, password, API_URL: 'en' }); 148 | const query_result = await enwiki.query({ action: 'query', meta: 'userinfo' }); 149 | //console.trace(query_result); 150 | 151 | // node.js v12 does not support the optional chaining operator (?.) 152 | // EoL of node.js v12: 2022-04-30 153 | if (password) { 154 | //assert([bot_name, query_result?.query?.userinfo?.name], 'test wiki.query()'); 155 | assert([bot_name, query_result?.query.userinfo.name], 'test wiki.query()'); 156 | } else { 157 | //assert(['' in query_result?.query?.userinfo?.anon], 'test wiki.query()'); 158 | assert(['', query_result?.query.userinfo.anon], 'test wiki.query()'); 159 | } 160 | 161 | await enwiki.page(test_page_title); 162 | 163 | // CeL.set_debug(6); 164 | try { 165 | await enwiki.edit((page_data) => { 166 | // append text 167 | return page_data.wikitext 168 | + test_wikitext; 169 | }, { 170 | bot: 1, 171 | summary: 'Test edit using wikiapi module' 172 | }); 173 | 174 | // edit successed 175 | // reget page to test. 176 | const page_data = await enwiki.page(test_page_title); 177 | assert(page_data.wikitext.endsWith(test_wikitext), 'test edit page result'); 178 | } catch (error) { 179 | // failed to edit 180 | handle_edit_error(assert, error); 181 | } 182 | // CeL.set_debug(0); 183 | 184 | // console.log('Done.'); 185 | finish_test('edit page'); 186 | }); 187 | 188 | add_test('edit page #2', async (assert, setup_test, finish_test) => { 189 | setup_test('edit page #2'); 190 | const test_page_title = 'Wikipedia:沙盒'; 191 | const test_wikitext = '\nTest edit using {{GitHub|kanasimi/wikiapi}} #2.'; 192 | const bot_name = null; 193 | const password = null; 194 | 195 | const zhwiki = new Wikiapi; 196 | await zhwiki.login(bot_name, password, { API_URL: 'zh' }); 197 | 198 | // CeL.set_debug(6); 199 | try { 200 | await zhwiki.edit_page(test_page_title, (page_data) => { 201 | //console.trace(page_data); 202 | // append text 203 | return page_data.wikitext 204 | + test_wikitext; 205 | }, { 206 | bot: 1, 207 | summary: 'Test edit using wikiapi module' 208 | }); 209 | 210 | // edit successed 211 | // reget page to test. 212 | const page_data = await zhwiki.page(test_page_title); 213 | assert(page_data.wikitext.endsWith(test_wikitext), 'test edit page result'); 214 | } catch (result) { 215 | // failed to edit 216 | handle_edit_error(assert, result); 217 | } 218 | // CeL.set_debug(0); 219 | 220 | // console.log('Done.'); 221 | finish_test('edit page #2'); 222 | }); 223 | 224 | // ------------------------------------------------------------------ 225 | 226 | add_test('parse page: en', async (assert, setup_test, finish_test) => { 227 | setup_test('parse page: en'); 228 | const user_name = null; 229 | const password = null; 230 | 231 | const enwiki = new Wikiapi('en'); 232 | await enwiki.login(user_name, password/*, 'en' */); 233 | const page_data = await enwiki.page('Human'); 234 | const template_list = []; 235 | page_data.parse().each('template', 236 | (token) => template_list.push(token.name)); 237 | assert(template_list.includes('Speciesbox'), '[[w:en:Human]] must includes {{Speciesbox}}'); 238 | finish_test('parse page: en'); 239 | }); 240 | 241 | // ------------------------------------------------------------------ 242 | 243 | add_test('parse page: zh', async (assert, setup_test, finish_test) => { 244 | setup_test('parse page: zh'); 245 | // Usage with other language 246 | const zhwiki = new Wikiapi('zh'); 247 | const page_data = await zhwiki.page('宇宙'); 248 | const template_list = []; 249 | page_data.parse().each('template', 250 | (token) => template_list.push(token.name)); 251 | assert(template_list.includes('Infobox'), '[[w:zh:宇宙]] must includes {{Infobox}}'); 252 | finish_test('parse page: zh'); 253 | }); 254 | 255 | // ------------------------------------------------------------------ 256 | 257 | add_test('Get page list', async (assert, setup_test, finish_test) => { 258 | setup_test('Get page list'); 259 | 260 | const enwiki = new Wikiapi('en'); 261 | 262 | let page_list, count; 263 | 264 | page_list = await enwiki.categorymembers('Chemical elements', { limit: 3 }); 265 | await page_list.each((page_data) => { 266 | assert(['string', typeof page_data.wikitext], 'page_list.each(page_data) with content: ' + CeL.wiki.title_link_of(page_data)); 267 | }); 268 | 269 | page_list = []; 270 | count = 0; 271 | for await (const page_data of enwiki.allpages({ namespace: 'Talk', apfrom: 'ABC', limit: 50 })) { 272 | page_list.push(page_data); 273 | if (++count === 7) break; 274 | } 275 | assert(['Talk:ABC', page_list[0].title], 'for await (namespace: Talk, apfrom: ABC)'); 276 | assert([7, page_list.length], 'for await () { break; }'); 277 | 278 | page_list = []; 279 | count = 0; 280 | for await (const _page_list of enwiki.allpages({ namespace: 'Talk', apfrom: 'ABC', batch_size: 3, limit: 50 })) { 281 | assert([3, _page_list.length], 'for await (batch_size) { }'); 282 | page_list.push(_page_list); 283 | if (++count === 6) break; 284 | } 285 | assert([6, page_list.length], 'for await (batch_size) { break; }'); 286 | 287 | finish_test('Get page list'); 288 | }); 289 | 290 | // ------------------------------------------------------------------ 291 | 292 | add_test('featured content: en', async (assert, setup_test, finish_test) => { 293 | setup_test('featured content: en'); 294 | CeL.run('application.net.wiki.featured_content'); 295 | // Usage with other language 296 | const enwiki = new Wikiapi('en'); 297 | // get only type: featured article 298 | enwiki.get_featured_content.default_types = ['FA']; 299 | // FC_data_hash === wiki.FC_data_hash[page_title] 300 | const FC_data_hash = await enwiki.get_featured_content({ 301 | // get only type: featured article 302 | // type: 'FA', 303 | on_conflict(FC_title, data) { 304 | CeL.warn(`Category conflict: ${data.from}→${CeL.wiki.title_link_of('Category:' + data.category, data.to)}`); 305 | } 306 | }); 307 | assert(FC_data_hash['Sun'].type === 'FA', '[[w:en:Sun]] is featured article'); 308 | 309 | // cache alias of {{Article history}} 310 | const Article_history_alias = (await enwiki.redirects_here('Template:Article history')) 311 | .map(page_data => page_data.title 312 | // remove "Template:" prefix 313 | .replace(/^[^:]+:/, '')); 314 | 315 | await enwiki.for_each_page(Object.keys(FC_data_hash).filter((title) => 'FA' === FC_data_hash[title].type).slice(0, 4), async (page_data) => { 316 | const talk_page_data = await enwiki.page(enwiki.to_talk_page(page_data)); 317 | let has_Article_history; 318 | talk_page_data.parse().each('template', 319 | (token) => { if (Article_history_alias.includes(token.name)) has_Article_history = true; }); 320 | assert(has_Article_history, `${CeL.wiki.title_link_of(talk_page_data)} has {{ArticleHistory}}`); 321 | }); 322 | finish_test('featured content: en'); 323 | }); 324 | 325 | // ------------------------------------------------------------------ 326 | 327 | add_test('move page', async (assert, setup_test, finish_test) => { 328 | setup_test('move page: testwiki'); 329 | const testwiki = new Wikiapi('test'); 330 | 331 | const move_from_title = 'move test from'; 332 | const move_to_title = 'move test to'; 333 | const reason = 'move test'; 334 | let result; 335 | try { 336 | result = await testwiki.move_page(move_from_title, move_to_title, { reason: reason }); 337 | assert([result.to, move_to_title], `move page: [[testwiki:${move_from_title}]]→[[testwiki:${move_to_title}]]`); 338 | 339 | 340 | await testwiki.page(move_from_title); 341 | result = await testwiki.move_to(move_to_title, { reason: reason, noredirect: true, movetalk: true }); 342 | // revert 343 | await testwiki.page(move_to_title); 344 | await testwiki.move_to(move_from_title, { reason: reason, noredirect: true, movetalk: true }); 345 | 346 | assert([result.from, move_from_title], `move page from: [[testwiki:${move_from_title}]]`); 347 | assert([result.to, move_to_title], `move page to: [[testwiki:${move_to_title}]]`); 348 | 349 | } catch (e) { 350 | if (e.code !== 'missingtitle' && e.code !== 'articleexists') { 351 | if (e.code) { 352 | CeL.error(`[${e.code}] ${e.info}`); 353 | } else { 354 | console.trace(e); 355 | } 356 | } 357 | assert(e === 'No csrftoken specified' 358 | || e.code && e.code !== 'missingtitle' && e.code !== 'articleexists', 359 | `move page from: [[testwiki:${move_from_title}]]`); 360 | } 361 | 362 | finish_test('move page: testwiki'); 363 | }); 364 | 365 | 366 | // ------------------------------------------------------------------ 367 | 368 | add_test('purge page', async (assert, setup_test, finish_test) => { 369 | setup_test('purge page: meta'); 370 | const metawiki = new Wikiapi('meta'); 371 | 372 | let page_data; 373 | try { 374 | page_data = await metawiki.purge('Project:Sandbox'); 375 | } catch (e) { 376 | if (e.code === 'blocked') { 377 | // info: 'You have been blocked from editing.' 378 | finish_test('purge page: meta'); 379 | return; 380 | } 381 | } 382 | // [ { ns: 4, title: 'Meta:Sandbox', purged: '' } ] 383 | assert(page_data.title === 'Meta:Sandbox' && ('purged' in page_data), 'purge page: [[meta:Project:Sandbox]]'); 384 | 385 | // ----------------------------------- 386 | 387 | await metawiki.page('Meta:Babel'); 388 | page_data = await metawiki.purge({ 389 | multi: true 390 | }); 391 | // You may also using: 392 | // page_data = await testwiki.purge(/* no options */); 393 | 394 | // console.log(page_data); 395 | assert(Array.isArray(page_data) && page_data.length === 1, 'purge page: [[meta:Meta:Babel]]: multi return {Array}'); 396 | page_data = page_data[0]; 397 | assert(page_data.title === 'Meta:Babel' && ('purged' in page_data), 'purge page: [[meta:Meta:Babel]]'); 398 | 399 | finish_test('purge page: meta'); 400 | }); 401 | 402 | // ------------------------------------------------------------------ 403 | 404 | add_test('read wikidata', async (assert, setup_test, finish_test) => { 405 | setup_test('read wikidata'); 406 | const wiki = new Wikiapi; 407 | // Q1: Universe 408 | const page_data = await wiki.data('Q1', { 409 | props: 'labels|sitelinks' 410 | }); 411 | // CeL.info('page:'); 412 | // console.log(page); 413 | 414 | // Work with other language 415 | assert([CeL.wiki.data.value_of(page_data.labels.zh), '宇宙'], 'zh label of Q1 is 宇宙'); 416 | finish_test('read wikidata'); 417 | }); 418 | 419 | // ------------------------------------------------------------------ 420 | 421 | add_test('read wikidata #2', async (assert, setup_test, finish_test) => { 422 | setup_test('read wikidata #2'); 423 | const wiki = new Wikiapi('en'); 424 | // P1419: shape 425 | const data = await wiki.data('Universe', 'P1419'); 426 | // console.log('`shape` of the `Universe`:'); 427 | // console.log(data); 428 | assert(data.includes('shape of the universe'), '`shape` of the `Universe` is Q1647152 (shape of the universe)'); 429 | finish_test('read wikidata #2'); 430 | }); 431 | 432 | // ------------------------------------------------------------------ 433 | 434 | add_test('繁簡轉換', async (assert, setup_test, finish_test) => { 435 | setup_test('繁簡轉換'); 436 | const wiki = new Wikiapi; 437 | assert(['中國', await wiki.convert_Chinese('中国', { uselang: 'zh-hant' })], '繁簡轉換: 中国'); 438 | assert(['中国', await wiki.convert_Chinese('中國', { uselang: 'zh-hans' })], '繁簡轉換: 中國'); 439 | assert(['繁体,简体', (await wiki.convert_Chinese(['繁體', '簡體'], { uselang: 'zh-hans' })).join()], '繁簡轉換: {Array}'); 440 | finish_test('繁簡轉換'); 441 | }); 442 | 443 | // ------------------------------------------------------------------ 444 | 445 | add_test('tracking revisions to lookup what revision had added "an international team led by scientists"', async (assert, setup_test, finish_test) => { 446 | setup_test('tracking revisions to lookup what revision had added "an international team led by scientists"'); 447 | const wiki = new Wikiapi('en.wikinews'); 448 | // trace https://en.wikinews.org/w/index.php?title=Study_suggests_Mars_hosted_life-sustaining_habitat_for_millions_of_years&diff=4434584&oldid=4434582 449 | const newer_revision = await wiki.tracking_revisions('Study suggests Mars hosted life-sustaining habitat for millions of years', 'an international team led by scientists'); 450 | assert([4434584, newer_revision.revid], 'tracking revisions: Get the revid added the text'); 451 | assert(newer_revision.diff_list[0][0].includes('a team led by scientists'), 'tracking revisions: Get the text removed'); 452 | assert(newer_revision.diff_list[0][1].includes('an international team led by scientists'), 'tracking revisions: Get the text added'); 453 | finish_test('tracking revisions to lookup what revision had added "an international team led by scientists"'); 454 | }); 455 | 456 | add_test('tracking revisions to lookup what revision had added "金星快车效果图"', async (assert, setup_test, finish_test) => { 457 | setup_test('tracking revisions to lookup what revision had added "金星快车效果图"'); 458 | const wiki = new Wikiapi('zh.wikinews'); 459 | // trace https://zh.wikinews.org/w/index.php?title=%E9%87%91%E6%98%9F%E5%BF%AB%E8%BD%A6%E5%8F%91%E5%9B%9E%E4%BA%91%E5%B1%82%E7%85%A7%E7%89%87&diff=12260&oldid=12259 460 | const newer_revision = await wiki.tracking_revisions('金星快车发回云层照片', '金星快车效果图'); 461 | assert([12260, newer_revision.revid], 'tracking revisions: Get the revid added the text'); 462 | assert(['[[Image:Venus_express.jpg|thumb|200px|金星快车效果图]]', newer_revision.diff_list[0][1]], 'tracking revisions: Get the text added'); 463 | finish_test('tracking revisions to lookup what revision had added "金星快车效果图"'); 464 | }); 465 | 466 | // ------------------------------------------------------------------ 467 | 468 | add_test('get list of categorymembers', async (assert, setup_test, finish_test) => { 469 | setup_test('get list of [[w:en:Category:Chemical_elements]]'); 470 | const wiki = new Wikiapi; 471 | const page_list = await wiki.categorymembers('Chemical elements'); 472 | assert(page_list.map((page_data) => page_data.title).includes('Iron'), 'Iron is a chemical element'); 473 | finish_test('get list of [[w:en:Category:Chemical_elements]]'); 474 | }); 475 | 476 | // ------------------------------------------------------------------ 477 | 478 | add_test('get pages transclude specified template', async (assert, setup_test, finish_test) => { 479 | setup_test('get pages transclude {{w:en:Periodic table}}'); 480 | const wiki = new Wikiapi; 481 | const page_list = await wiki.embeddedin('Template:Periodic table'); 482 | assert(page_list.map((page_data) => page_data.title).includes('Periodic table'), '[[w:en:Periodic table]] transclude {{w:en:Periodic table}}'); 483 | finish_test('get pages transclude {{w:en:Periodic table}}'); 484 | }); 485 | 486 | // ------------------------------------------------------------------ 487 | 488 | add_test('get list of categorymembers using for_each_page_in_list', async (assert, setup_test, finish_test) => { 489 | setup_test('get list of [[w:en:Category:Wikimedia Cloud Services]] using for_each'); 490 | 491 | const wiki = new Wikiapi('en'); 492 | let has_category_count = 0; 493 | const page_list_proto = await wiki.for_each_page_in_list('categorymembers', 'Wikimedia Cloud Services', async (category) => { 494 | const page_data = await wiki.page(category); 495 | const parsed = page_data.parse(); 496 | const to_exit = parsed.each.exit; 497 | // console.log(page_data.revisions[0].slots.main['*']); 498 | // console.log(parsed); 499 | parsed.each('category', (token) => { 500 | if (token.name === 'Wikimedia Cloud Services') { 501 | has_category_count++; 502 | return to_exit; 503 | } 504 | }); 505 | }); 506 | // console.log(page_list_proto); 507 | // console.log([page_list_proto.length, has_category_count]); 508 | 509 | assert([page_list_proto.length, has_category_count], 'Count of [[w:en:Category:Wikimedia Cloud Services]] using for_each'); 510 | finish_test('get list of [[w:en:Category:Wikimedia Cloud Services]] using for_each'); 511 | }); 512 | 513 | add_test('get list of categorymembers using for_each_page', async (assert, setup_test, finish_test) => { 514 | setup_test('get list of [[w:en:Category:Wikimedia Cloud Services]] using for_each_page'); 515 | 516 | const wiki = new Wikiapi('en'); 517 | let has_category_count = 0; 518 | const page_list = await wiki.categorymembers('Wikimedia Cloud Services'); 519 | await wiki.for_each_page(page_list, (page_data) => { 520 | const parsed = page_data.parse(); 521 | // console.log(parsed); 522 | assert([page_data.wikitext, parsed.toString()], 'wikitext parser check'); 523 | let has_category; 524 | parsed.each('category', (token) => { 525 | if (token.name === 'Wikimedia Cloud Services') { 526 | has_category = true; 527 | } 528 | }); 529 | if (has_category) { 530 | has_category_count++; 531 | } 532 | }); 533 | // console.log([page_list.length, has_category_count]); 534 | 535 | assert([page_list.length, has_category_count], 'Count of [[w:en:Category:Wikimedia Cloud Services]] using for_each_page'); 536 | finish_test('get list of [[w:en:Category:Wikimedia Cloud Services]] using for_each_page'); 537 | }); 538 | 539 | // ------------------------------------------------------------------ 540 | 541 | add_test('list category tree', async (assert, setup_test, finish_test) => { 542 | setup_test('list category tree: Countries in North America'); 543 | 544 | const enwiki = new Wikiapi('en'); 545 | const page_list = await enwiki.category_tree('Countries in North America', 1); 546 | assert(page_list.some(page_data => page_data.title === 'United States'), 'list category tree: [[Category:Countries in North America]] must includes [[United States]]'); 547 | assert('Mexico' in page_list[Wikiapi.KEY_subcategories], 'list category tree: [[Category:Mexico]] is a subcategory of [[Category:Countries in North America]]'); 548 | finish_test('list category tree: Countries in North America'); 549 | }); 550 | 551 | // ------------------------------------------------------------------ 552 | 553 | add_test('search pages include key', async (assert, setup_test, finish_test) => { 554 | setup_test('search pages include key: 霍金'); 555 | 556 | const zhwikinews = new Wikiapi('zh.wikinews'); 557 | const page_list = await zhwikinews.search('"霍金"'); 558 | // node.js v12 does not support the optional chaining operator (?.) 559 | // EoL of node.js v12: 2022-04-30 560 | //assert(page_list?.some(page_data => page_data?.title === '霍金访问香港'), 'search pages include key: "霍金" must includes [[n:zh:霍金访问香港]]'); 561 | assert(page_list.some(page_data => page_data.title === '霍金访问香港'), 'search pages include key: "霍金" must includes [[n:zh:霍金访问香港]]'); 562 | finish_test('search pages include key: 霍金'); 563 | }); 564 | 565 | // ------------------------------------------------------------------ 566 | 567 | add_test('query MediaWiki API manually', async (assert, setup_test, finish_test) => { 568 | setup_test('query MediaWiki API manually'); 569 | const wiki = new Wikiapi('mediawiki'); 570 | const results = await wiki.query({ 571 | action: "flow-parsoid-utils", 572 | content: "bold & italic", 573 | title: "MediaWiki", from: "html", to: "wikitext" 574 | }); 575 | // node.js v12 does not support the optional chaining operator (?.) 576 | // EoL of node.js v12: 2022-04-30 577 | //assert(["'''bold''' & ''italic''", results['flow-parsoid-utils']?.content], 'query MediaWiki API manually: flow-parsoid-utils'); 578 | assert(["'''bold''' & ''italic''", results['flow-parsoid-utils'].content], 'query MediaWiki API manually: flow-parsoid-utils'); 579 | finish_test('query MediaWiki API manually'); 580 | }); 581 | -------------------------------------------------------------------------------- /docs/fonts/Montserrat/Montserrat-Bold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanasimi/wikiapi/0ece4bf9178e347ce6dff0f96b194f11f8a7a005/docs/fonts/Montserrat/Montserrat-Bold.eot -------------------------------------------------------------------------------- /docs/fonts/Montserrat/Montserrat-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanasimi/wikiapi/0ece4bf9178e347ce6dff0f96b194f11f8a7a005/docs/fonts/Montserrat/Montserrat-Bold.ttf -------------------------------------------------------------------------------- /docs/fonts/Montserrat/Montserrat-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanasimi/wikiapi/0ece4bf9178e347ce6dff0f96b194f11f8a7a005/docs/fonts/Montserrat/Montserrat-Bold.woff -------------------------------------------------------------------------------- /docs/fonts/Montserrat/Montserrat-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanasimi/wikiapi/0ece4bf9178e347ce6dff0f96b194f11f8a7a005/docs/fonts/Montserrat/Montserrat-Bold.woff2 -------------------------------------------------------------------------------- /docs/fonts/Montserrat/Montserrat-Regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanasimi/wikiapi/0ece4bf9178e347ce6dff0f96b194f11f8a7a005/docs/fonts/Montserrat/Montserrat-Regular.eot -------------------------------------------------------------------------------- /docs/fonts/Montserrat/Montserrat-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanasimi/wikiapi/0ece4bf9178e347ce6dff0f96b194f11f8a7a005/docs/fonts/Montserrat/Montserrat-Regular.ttf -------------------------------------------------------------------------------- /docs/fonts/Montserrat/Montserrat-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanasimi/wikiapi/0ece4bf9178e347ce6dff0f96b194f11f8a7a005/docs/fonts/Montserrat/Montserrat-Regular.woff -------------------------------------------------------------------------------- /docs/fonts/Montserrat/Montserrat-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanasimi/wikiapi/0ece4bf9178e347ce6dff0f96b194f11f8a7a005/docs/fonts/Montserrat/Montserrat-Regular.woff2 -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Bold-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanasimi/wikiapi/0ece4bf9178e347ce6dff0f96b194f11f8a7a005/docs/fonts/OpenSans-Bold-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Bold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanasimi/wikiapi/0ece4bf9178e347ce6dff0f96b194f11f8a7a005/docs/fonts/OpenSans-Bold-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-BoldItalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanasimi/wikiapi/0ece4bf9178e347ce6dff0f96b194f11f8a7a005/docs/fonts/OpenSans-BoldItalic-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-BoldItalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanasimi/wikiapi/0ece4bf9178e347ce6dff0f96b194f11f8a7a005/docs/fonts/OpenSans-BoldItalic-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Italic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanasimi/wikiapi/0ece4bf9178e347ce6dff0f96b194f11f8a7a005/docs/fonts/OpenSans-Italic-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Italic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanasimi/wikiapi/0ece4bf9178e347ce6dff0f96b194f11f8a7a005/docs/fonts/OpenSans-Italic-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Light-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanasimi/wikiapi/0ece4bf9178e347ce6dff0f96b194f11f8a7a005/docs/fonts/OpenSans-Light-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Light-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanasimi/wikiapi/0ece4bf9178e347ce6dff0f96b194f11f8a7a005/docs/fonts/OpenSans-Light-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-LightItalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanasimi/wikiapi/0ece4bf9178e347ce6dff0f96b194f11f8a7a005/docs/fonts/OpenSans-LightItalic-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-LightItalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanasimi/wikiapi/0ece4bf9178e347ce6dff0f96b194f11f8a7a005/docs/fonts/OpenSans-LightItalic-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Regular-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanasimi/wikiapi/0ece4bf9178e347ce6dff0f96b194f11f8a7a005/docs/fonts/OpenSans-Regular-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanasimi/wikiapi/0ece4bf9178e347ce6dff0f96b194f11f8a7a005/docs/fonts/OpenSans-Regular-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanasimi/wikiapi/0ece4bf9178e347ce6dff0f96b194f11f8a7a005/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanasimi/wikiapi/0ece4bf9178e347ce6dff0f96b194f11f8a7a005/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf -------------------------------------------------------------------------------- /docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanasimi/wikiapi/0ece4bf9178e347ce6dff0f96b194f11f8a7a005/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanasimi/wikiapi/0ece4bf9178e347ce6dff0f96b194f11f8a7a005/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2 -------------------------------------------------------------------------------- /docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanasimi/wikiapi/0ece4bf9178e347ce6dff0f96b194f11f8a7a005/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanasimi/wikiapi/0ece4bf9178e347ce6dff0f96b194f11f8a7a005/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf -------------------------------------------------------------------------------- /docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanasimi/wikiapi/0ece4bf9178e347ce6dff0f96b194f11f8a7a005/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanasimi/wikiapi/0ece4bf9178e347ce6dff0f96b194f11f8a7a005/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2 -------------------------------------------------------------------------------- /docs/global.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Global - Documentation 7 | 8 | 9 | 10 | 11 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 25 | 26 | 27 | 28 | 32 | 33 |
34 | 35 |

Global

36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 |
44 | 45 |
46 | 47 |

48 | 49 |

50 | 51 | 52 |
53 | 54 |
55 | 56 |
57 | 58 | 59 | 60 |
61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 |
94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 |
103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 |

Methods

121 | 122 | 123 | 124 | 125 | 126 | 127 |

for_each_page_in_list(type, titleopt, for_each_page, optionsopt) → {Promise}

128 | 129 | 130 | 131 | 132 | 133 | 134 |
135 | 136 | 137 |
Source:
138 |
141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 |
Deprecated:
159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 |
175 | 176 | 177 | 178 | 179 | 180 |
181 | Syntactic sugar for several kinds of lists. 182 |
183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 |
Example
193 | 194 |

List all redirected categories

195 | 196 |
// <code>
197 | await wiki.for_each_page_in_list('allredirects', page_data => console.log('page_data: ', page_data), { namespace: 'Category' });
198 | // </code>
199 | 200 | 201 | 202 | 203 |
Parameters:
204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 241 | 242 | 243 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 272 | 273 | 274 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 305 | 306 | 307 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 336 | 337 | 338 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 |
NameTypeAttributesDescription
type 234 | 235 | 236 | String 237 | 238 | 239 | 240 | 244 | 245 | 246 | 247 | 248 | 249 | list type
title 265 | 266 | 267 | String 268 | 269 | 270 | 271 | 275 | 276 | <optional>
277 | 278 | 279 | 280 | 281 | 282 |
page title if necessary.
for_each_page 298 | 299 | 300 | function 301 | 302 | 303 | 304 | 308 | 309 | 310 | 311 | 312 | 313 | Executing for each page.
options 329 | 330 | 331 | Object 332 | 333 | 334 | 335 | 339 | 340 | <optional>
341 | 342 | 343 | 344 | 345 | 346 |
options to run this function.
357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 |
Returns:
374 | 375 | 376 | 377 | 378 |
379 |
380 | Type 381 |
382 |
383 | 384 | Promise 385 | 386 | 387 |
388 |
389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 |

Wikiapi_list()

400 | 401 | 402 | 403 | 404 | 405 | 406 |
407 | 408 | 409 |
Source:
410 |
413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 |
445 | 446 | 447 | 448 | 449 | 450 |
451 | Tool function to access page list.
Please refer to all supported types (search "get_list.type ="). 452 |
453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 |
Examples
463 | 464 |

get list of [[w:en:Category:Chemical_elements]]

465 | 466 |
// <code>
467 | const wiki = new Wikiapi;
468 | let page_list = await wiki.categorymembers('Chemical elements');
469 | console.log(page_list);
470 | // Working on multiple pages
471 | await wiki.for_each_page(
472 | 	// {Array} title liat / page data list
473 | 	page_list,
474 | 	page_data => {
475 | 		// ...
476 | 	});
477 | // </code>
478 | 479 |

get pages transcluding {{w:en:Periodic table}}

480 | 481 |
// <code>
482 | const wiki = new Wikiapi;
483 | let page_list = await wiki.embeddedin('Template:Periodic table');
484 | console.log(page_list);
485 | // </code>
486 | 487 |

Process each page of the category.

488 | 489 |
// <code>
490 | // Get the list of all pages at once first.
491 | const page_list = await wiki.categorymembers('Category:Articles not listed in the vital article list');
492 | await page_list.each((page_data) => { }, options);
493 | 
494 | // Imperative code, for huge pages. 用於巨量的頁面。
495 | for await (const page_data of wiki.categorymembers('Category:Articles not listed in the vital article list')) {
496 | 	console.trace(`page_data #${count}:`, page_data);
497 | }
498 | 
499 | // Declarative code(?), for huge pages.
500 | await wiki.categorymembers('Category:Articles not listed in the vital article list', {
501 | 	for_each_page(page_data) {
502 | 		console.log('page_data:', page_data);
503 | 	}
504 | });
505 | 
506 | await wiki.allpages({
507 | 	async for_each_slice(page_list) {
508 | 	}
509 | });
510 | 
511 | // </code>
512 | 513 |

Process all pages.

514 | 515 |
// <code>
516 | let count = 0;
517 | for await (const page_data of wiki.allpages({ namespace: 'Talk', apfrom: wiki.remove_namespace('ABC') })) {
518 | 	console.trace(`page_data #${count}:`, page_data);
519 | 	if (++count > 5) break;
520 | }
521 | console.log('Done.');
522 | // </code>
523 | 524 |

Process all pages with batch_size.

525 | 526 |
// <code>
527 | let count = 0;
528 | for await (const page_list of wiki.allpages({ namespace: 'Talk', apfrom: wiki.remove_namespace('ABC'), batch_size: 5 })) {
529 | 	console.trace('page_list:', page_list);
530 | 	if (++count > 2) break;
531 | }
532 | console.log('Done.');
533 | // </code>
534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 |
562 | 563 |
564 | 565 | 566 | 567 | 568 | 569 | 570 |
571 | 572 |
573 | 574 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Home - Documentation 7 | 8 | 9 | 10 | 11 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 25 | 26 | 27 | 28 | 32 | 33 |
34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 |
44 |

45 |
46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 |
60 |

npm version 61 | npm downloads 62 | GitHub Actions workflow build status 63 | codecov

64 |

Known Vulnerabilities 65 | codebeat badge 66 | Codacy Badge 67 | DeepScan grade

68 |

JavaScript MediaWiki API

69 |

70 | Wikiapi logo 71 |

72 |

A simple way to access MediaWiki API via JavaScript with wikitext parser. 73 | This is basically a modern syntax version of CeJS MediaWiki module. For example, using async functions.

74 |

Features

75 |
    76 |
  • Read / edit pages.
  • 77 |
  • Get list of categorymembers, pages transclude specified template, and more...
  • 78 |
  • Auto-limited editing rate.
  • 79 |
  • Parse wikitext / pages. You may modify parts of the wikitext, then regenerate the page just using .toString(). See wikitext parser examples.
  • 80 |
81 |

Installation

82 |

This is a nodejs module. Please install node.js first.

83 |
npm install wikiapi
 84 | 
85 |

Usage

86 |

Here lists some examples of this module.

87 | 108 |

As node.js module

109 |
// Load Wikiapi module
110 | const Wikiapi = require('wikiapi');
111 | 
112 | // OPEN ASYNC DOMAIN:
113 | (async () => {
114 | 
115 | 	// LOGIN IN: In any wiki, any language
116 | 	const wiki = new Wikiapi('zh');		// or new Wikiapi('https://zh.wikipedia.org/w/api.php')
117 | 	await wiki.login('user', 'password');		// get your own account and password on your target wiki.
118 | 
119 | 
120 | 	/* ***************************************************** */
121 | 	/* READ ONLY ******************************************* */
122 | 	// load page
123 | 	let page_data = await wiki.page('Universe', {});
124 | 	console.log('page_data: ', page_data);
125 | 	console.log('page_data.text: ', page_data.wikitext);
126 | 
127 | 	// Get multi revisions (ex: 2)
128 | 	let page_data = await wiki.page('Universe', { revisions: 2 });
129 | 	console.log('page_data: ', page_data);
130 | 	console.log('page_data.text: ', page_data.wikitext);
131 | 
132 | 	/* ***************************************************** */
133 | 	/* EDITING ********************************************* */
134 | 	/* Note: .page() then .edit() ************************** */
135 | 	// Edit page: append content, as bot.
136 | 	let page_data = await wiki.page('Universe'),
137 | 		newContent = page_data.wikitext + '\nTest edit using wikiapi.';
138 | 	await enwiki.edit(
139 | 		function (page_data) { return newContent; },		// new content
140 | 		{ bot: 1, summary: 'Test edit.' }			// options
141 | 	);
142 | 
143 | 	// Edit page: replace content, with more options.
144 | 	let page_data = await wiki.page('Universe'),
145 | 		newContent = page_data.wikitext.replace(/Test edit using wikiapi/g, 'Test: replace content was successful!');
146 | 	await enwiki.edit(
147 | 		function (page_data) { return newContent; },  // new content
148 | 		{ bot: 1, minor: 1, nocreate: 1, summary: 'Test: replace content.' } // more options
149 | 	);
150 | 
151 | 	// Edit page: wipe clean, replace by string
152 | 	let page_data = await wiki.page('Universe');
153 | 	await wiki.edit(
154 | 		'{{Speedy|reason=Vandalism}}',
155 | 		{ bot: 1, minor: 0, nocreate: 1, summary: 'Test: wipe clean, please delete.' }
156 | 	);
157 | 
158 | 	/* edit_page(): a more direct method ******************* */
159 | 	// Edit page: 
160 | 	await wiki.edit_page('Wikipedia:Sandbox', function (page_data) {
161 | 		return page_data.wikitext + '\nTest edit using {{GitHub|kanasimi/wikiapi}}.';
162 | 	}, { bot: 1, nocreate: 1, minor: 1, summary: 'Test: edit page via .edit_page().' });
163 | 
164 | 
165 | 	/* ***************************************************** */
166 | 	/* PROVIDE MANY **************************************** */
167 | 	// List of hand-picked target pages
168 | 	let list = ['Wikipedia:Sandbox', 'Wikipedia:Sandbox2', 'Wikipedia:Sandbox/wikiapi'];
169 | 	// List pages in [[Category:Chemical_elements]]
170 | 	let listMembers = await wiki.categorymembers('Chemical elements');  // array of titles
171 | 	// List intra-wiki links in [[ABC]]
172 | 	let listLinks = await wiki.redirects_here('ABC');  // array of titles
173 | 	// List of transcluded pages {{w:en:Periodic table}}
174 | 	let listTranscluded = await wiki.embeddedin('Template:Periodic table');
175 | 	// List of searched pages with expression in its title name
176 | 	let listSearch = await wiki.search(' dragon');  // array of titles
177 | 
178 | 	/* ***************************************************** */
179 | 	/* MULTI-read/edit ************************************* */
180 | 	// Multi edit, members of category
181 | 	await wiki.for_each_page(
182 | 		listMembers,
183 | 		page_data => { return `{{stub}}\n` + page_data.wikitext; },
184 | 		{ summary: 'Test: multi-edits', minor: 1 }
185 | 	);
186 | 
187 | 	// Multi read, following intra-wiki links
188 | 	await wiki.for_each_page(
189 | 		listLinks,			// array of targets
190 | 		page_data => {
191 | 			console.log(page_data.title);		// print page title
192 | 			return Wikiapi.skip_edit;		// skip edit, just read, return nothing to edit with.
193 | 		}, // no edit therefore no options
194 | 	);
195 | 
196 | 
197 | 	/* ***************************************************** */
198 | 	/* MOVE PAGE (RENAME) ********************************** */
199 | 	// Move page once.
200 | 	result = await wiki.move_page('Wikipedia:Sanbox/Wikiapi', 'Wikipedia:Sanbox/NewWikiapi',
201 | 		{ reason: 'Test: move page (1).', noredirect: true, movetalk: true }
202 | 	);
203 | 	// Reverse move
204 | 	result = await wiki.move_page('Wikipedia:Sanbox/NewWikiapi', 'Wikipedia:Sanbox/Wikiapi',
205 | 		{ reason: 'Test: move page (2).', noredirect: true, movetalk: true }
206 | 	);
207 | 
208 | 
209 | 	/* ***************************************************** */
210 | 	/* PARSE *********************************************** */
211 | 	// Read Infobox templates, convert to JSON.
212 | 	const page_data = await wiki.page('JavaScript');
213 | 	// `page_data.parse(options)` will startup the parser process, create page_data.parsed. After .parse(), we can use parsed.each().
214 | 	const parsed = page_data.parse();
215 | 	let infobox;
216 | 	parsed.each('template', template_token => {
217 | 		if (template_token.name.startsWith('Infobox')) {
218 | 			infobox = template_token.parameters;
219 | 			return parsed.each.exit;
220 | 		}
221 | 	});
222 | 	for (const [key, value] of Object.entries(infobox))
223 | 		infobox[key] = value.toString();
224 | 	// print json of the infobox
225 | 	console.log(infobox);
226 | 
227 | 	// Edit page and parse
228 | 	const parsed = await wiki.page('Wikipedia:Sandbox').parse();
229 | 	parsed.each('template', template_token => {/* modify token */ });
230 | 	await wiki.edit(parsed.toString(), { bot: 1, minor: 1, nocreate: 1 });
231 | 
232 | 	let page_data = await wiki.page('Universe');
233 | 	// See all type in wiki_toString @ https://github.com/kanasimi/CeJS/tree/master/application/net/wiki/parser.js
234 | 	// List all template name.
235 | 	page_data.parse().each('template',
236 | 		token => console.log(token.name));
237 | 
238 | 	/* ***************************************************** */
239 | 	/* MONITORING ****************************************** */
240 | 	// Listen to new edits, check every 2 minutes
241 | 	wiki.listen(function for_each_row() {
242 | 		// ...
243 | 	}, {
244 | 		// 檢查的延遲時間。
245 | 		delay: '2m',
246 | 		filter: function filter_row(row) {
247 | 			// row is the same format as page_data
248 | 		},
249 | 		// also get diff
250 | 		with_diff: { LCS: true, line: true },
251 | 		// only for articles (0:main namespace) and talk pages
252 | 		namespace: '0|talk',
253 | 	});
254 | 
255 | 	/* ***************************************************** */
256 | 	/* FILES *********************************************** */
257 | 	// Set upload parameters, maily for licensing reasons.
258 | 	// Note: parameter `text`, filled with the right wikicode `{{description|}}`, can replace most parameters.
259 | 	let options = {
260 | 		description: 'Photo of Osaka',
261 | 		date: new Date() || '2021-01-01',
262 | 		source_url: 'https://github.com/kanasimi/wikiapi',
263 | 		author: '[[User:user]]',
264 | 		permission: '{{cc-by-sa-2.5}}',
265 | 		other_versions: '',
266 | 		other_fields: '',
267 | 		license: ['{{cc-by-sa-2.5}}'],
268 | 		categories: ['[[Category:test images]]'],
269 | 		bot: 1,
270 | 		tags: "tag1|tag2",
271 | 	};
272 | 
273 | 	// Upload file from local path
274 | 	let result = await wiki.upload({
275 | 		file_path: '/local/file/path',
276 | 		filename: 'New_Osaka_Photograph.jpg',  // default : keep filename
277 | 		comment: '',
278 | 		ignorewarnings: 1,  // overwrite
279 | 		...options
280 | 	});
281 | 
282 | 	// Upload file from URL
283 | 	result = await wiki.upload({
284 | 		media_url: 'https://media.url/Thunder-Dragon.ogg',
285 | 		text: "Her eis wikicode to replave the page's content instead of various other parameters.",
286 | 		comment: 'Thunder Dragon audio from vacation in Philipines. Page uses custom template.',
287 | 		ignorewarnings: 1,  // overwrite
288 | 		...options
289 | 	});
290 | 
291 | 
292 | 	/* ***************************************************** */
293 | 	/* WIKIDATA, WIKIBASES ********************************* */
294 | 	// Read Qid Q1 (Universe), print Chinese label
295 | 	const wiki = new Wikiapi('https://wikidata.org/w/api.php')
296 | 	let page_data = await wiki.data('Q1');
297 | 	console.log(page_data.labels.zh)		// '宇宙'
298 | 
299 | 	// Read, access by title (English), access property P1419
300 | 	// Get P1419 of wikidata entity: 'Universe'
301 | 	let data = await wiki.data('Universe', 'P1419');
302 | 	// assert: {Array}data = [ 'shape of the universe', '...', ... ]
303 | 	console.assert(data.includes('shape of the universe'));
304 | 
305 | 	// update wikidata
306 | 	// Get https://test.wikidata.org/wiki/Q7
307 | 	let entity = await wiki.data('Q7');
308 | 	// search [ language, label ]
309 | 	//entity = await wiki.data(['en', 'Earth']);
310 | 
311 | 	// Update claim
312 | 	await entity.modify({ claims: [{ P17: 'Q213280' }] });
313 | 	// Update claim: set country (P17) to 'Test Country 1' (Q213280) ([language, label] as entity)
314 | 	await entity.modify({ claims: [{ language: 'en', country: [, 'Test Country 1'] }] });
315 | 	// Remove country (P17) : 'Test Country 1' (Q213280)
316 | 	await entity.modify({ claims: [{ language: 'en', country: [, 'Test Country 1'], remove: true }] });
317 | 
318 | 	// Update label
319 | 	await entity.modify({ labels: [{ language: 'zh-tw', value: '地球' }] });
320 | 
321 | 	// CLOSE ASYNC DOMAIN:
322 | })();
323 | 
324 |

More examples: Please see test.js.

325 |

User agent

326 |

By default, the library will use the user agent get_URL_node.default_user_agent set in Ajax.js. If you want to set another user agent, you can change CeL.wiki.query.get_URL_options listed in query.js:

327 |
CeL.wiki.query.get_URL_options.headers['User-Agent'] = 'testbot/1.0';
328 | 
329 |

OS support

330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 |
Platformsupport
Windows✔️
macOS✔️
UNIX, Linux✔️
352 |

See also

353 |

For old style JavaScript, or general environment usage, please see wikibot.

354 |

Contact

355 |

Contact us at GitHub.

356 |

logo

357 |
358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 |
368 | 369 |
370 | 371 |

372 | wikiapi.js 373 |

374 | 375 | 376 |
377 | 378 |
379 | 380 |
381 | 382 | 383 | 384 |
385 | 386 | 387 |
Source:
388 |
391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 |
423 | 424 | 425 | 426 | 427 | 428 |
Main codes of module wikiapi (class Wikiapi)
429 | 430 | 431 | 432 | 433 |
434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 |
456 | 457 |
458 | 459 | 460 | 461 | 462 | 463 | 464 |
465 | 466 |
467 | 468 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | -------------------------------------------------------------------------------- /docs/scripts/collapse.js: -------------------------------------------------------------------------------- 1 | function hideAllButCurrent(){ 2 | //by default all submenut items are hidden 3 | //but we need to rehide them for search 4 | document.querySelectorAll("nav > ul > li > ul li").forEach(function(parent) { 5 | parent.style.display = "none"; 6 | }); 7 | 8 | //only current page (if it exists) should be opened 9 | var file = window.location.pathname.split("/").pop().replace(/\.html/, ''); 10 | document.querySelectorAll("nav > ul > li > a").forEach(function(parent) { 11 | var href = parent.attributes.href.value.replace(/\.html/, ''); 12 | if (file === href) { 13 | parent.parentNode.querySelectorAll("ul li").forEach(function(elem) { 14 | elem.style.display = "block"; 15 | }); 16 | } 17 | }); 18 | } 19 | 20 | hideAllButCurrent(); -------------------------------------------------------------------------------- /docs/scripts/linenumber.js: -------------------------------------------------------------------------------- 1 | /*global document */ 2 | (function() { 3 | var source = document.getElementsByClassName('prettyprint source linenums'); 4 | var i = 0; 5 | var lineNumber = 0; 6 | var lineId; 7 | var lines; 8 | var totalLines; 9 | var anchorHash; 10 | 11 | if (source && source[0]) { 12 | anchorHash = document.location.hash.substring(1); 13 | lines = source[0].getElementsByTagName('li'); 14 | totalLines = lines.length; 15 | 16 | for (; i < totalLines; i++) { 17 | lineNumber++; 18 | lineId = 'line' + lineNumber; 19 | lines[i].id = lineId; 20 | if (lineId === anchorHash) { 21 | lines[i].className += ' selected'; 22 | } 23 | } 24 | } 25 | })(); 26 | -------------------------------------------------------------------------------- /docs/scripts/nav.js: -------------------------------------------------------------------------------- 1 | function scrollToNavItem() { 2 | var path = window.location.href.split('/').pop().replace(/\.html/, ''); 3 | document.querySelectorAll('nav a').forEach(function(link) { 4 | var href = link.attributes.href.value.replace(/\.html/, ''); 5 | if (path === href) { 6 | link.scrollIntoView({block: 'center'}); 7 | return; 8 | } 9 | }) 10 | } 11 | 12 | scrollToNavItem(); 13 | -------------------------------------------------------------------------------- /docs/scripts/polyfill.js: -------------------------------------------------------------------------------- 1 | //IE Fix, src: https://www.reddit.com/r/programminghorror/comments/6abmcr/nodelist_lacks_foreach_in_internet_explorer/ 2 | if (typeof(NodeList.prototype.forEach)!==typeof(alert)){ 3 | NodeList.prototype.forEach=Array.prototype.forEach; 4 | } -------------------------------------------------------------------------------- /docs/scripts/prettify/Apache-License-2.0.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /docs/scripts/prettify/lang-css.js: -------------------------------------------------------------------------------- 1 | PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n "]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com", 2 | /^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]); 3 | -------------------------------------------------------------------------------- /docs/scripts/prettify/prettify.js: -------------------------------------------------------------------------------- 1 | var q=null;window.PR_SHOULD_USE_CONTINUATION=!0; 2 | (function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a= 3 | [],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;ci[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m), 9 | l=[],p={},d=0,g=e.length;d=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, 10 | q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/, 11 | q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g, 12 | "");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a), 13 | a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e} 14 | for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], 18 | "catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"], 19 | H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"], 20 | J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+ 21 | I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]), 22 | ["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css", 23 | /^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}), 24 | ["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes", 25 | hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p=0){var k=k.match(g),f,b;if(b= 26 | !k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p ul > li:not(.level-hide)").forEach(function(elem) { 16 | elem.style.display = "block"; 17 | }); 18 | 19 | if (typeof hideAllButCurrent === "function"){ 20 | //let's do what ever collapse wants to do 21 | hideAllButCurrent(); 22 | } else { 23 | //menu by default should be opened 24 | document.querySelectorAll("nav > ul > li > ul li").forEach(function(elem) { 25 | elem.style.display = "block"; 26 | }); 27 | } 28 | } else { 29 | //we are searching 30 | document.documentElement.setAttribute(searchAttr, ''); 31 | 32 | //show all parents 33 | document.querySelectorAll("nav > ul > li").forEach(function(elem) { 34 | elem.style.display = "block"; 35 | }); 36 | //hide all results 37 | document.querySelectorAll("nav > ul > li > ul li").forEach(function(elem) { 38 | elem.style.display = "none"; 39 | }); 40 | //show results matching filter 41 | document.querySelectorAll("nav > ul > li > ul a").forEach(function(elem) { 42 | if (!contains(elem.parentNode, search)) { 43 | return; 44 | } 45 | elem.parentNode.style.display = "block"; 46 | }); 47 | //hide parents without children 48 | document.querySelectorAll("nav > ul > li").forEach(function(parent) { 49 | var countSearchA = 0; 50 | parent.querySelectorAll("a").forEach(function(elem) { 51 | if (contains(elem, search)) { 52 | countSearchA++; 53 | } 54 | }); 55 | 56 | var countUl = 0; 57 | var countUlVisible = 0; 58 | parent.querySelectorAll("ul").forEach(function(ulP) { 59 | // count all elements that match the search 60 | if (contains(ulP, search)) { 61 | countUl++; 62 | } 63 | 64 | // count all visible elements 65 | var children = ulP.children 66 | for (i=0; i th:last-child { border-right: 1px solid #ddd; } 224 | 225 | .ancestors, .attribs { color: #999; } 226 | .ancestors a, .attribs a 227 | { 228 | color: #999 !important; 229 | text-decoration: none; 230 | } 231 | 232 | .clear 233 | { 234 | clear: both; 235 | } 236 | 237 | .important 238 | { 239 | font-weight: bold; 240 | color: #950B02; 241 | } 242 | 243 | .yes-def { 244 | text-indent: -1000px; 245 | } 246 | 247 | .type-signature { 248 | color: #aaa; 249 | } 250 | 251 | .name, .signature { 252 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 253 | } 254 | 255 | .details { margin-top: 14px; border-left: 2px solid #DDD; } 256 | .details dt { width: 120px; float: left; padding-left: 10px; padding-top: 6px; } 257 | .details dd { margin-left: 70px; } 258 | .details ul { margin: 0; } 259 | .details ul { list-style-type: none; } 260 | .details li { margin-left: 30px; padding-top: 6px; } 261 | .details pre.prettyprint { margin: 0 } 262 | .details .object-value { padding-top: 0; } 263 | 264 | .description { 265 | margin-bottom: 1em; 266 | margin-top: 1em; 267 | } 268 | 269 | .code-caption 270 | { 271 | font-style: italic; 272 | font-size: 107%; 273 | margin: 0; 274 | } 275 | 276 | .source 277 | { 278 | border: 1px solid #ddd; 279 | width: 80%; 280 | overflow: auto; 281 | } 282 | 283 | .prettyprint.source { 284 | width: inherit; 285 | } 286 | 287 | .source code 288 | { 289 | font-size: 100%; 290 | line-height: 18px; 291 | display: block; 292 | padding: 4px 12px; 293 | margin: 0; 294 | background-color: #fff; 295 | color: #4D4E53; 296 | } 297 | 298 | .prettyprint code span.line 299 | { 300 | display: inline-block; 301 | } 302 | 303 | .prettyprint.linenums 304 | { 305 | padding-left: 70px; 306 | -webkit-user-select: none; 307 | -moz-user-select: none; 308 | -ms-user-select: none; 309 | user-select: none; 310 | } 311 | 312 | .prettyprint.linenums ol 313 | { 314 | padding-left: 0; 315 | } 316 | 317 | .prettyprint.linenums li 318 | { 319 | border-left: 3px #ddd solid; 320 | } 321 | 322 | .prettyprint.linenums li.selected, 323 | .prettyprint.linenums li.selected * 324 | { 325 | background-color: lightyellow; 326 | } 327 | 328 | .prettyprint.linenums li * 329 | { 330 | -webkit-user-select: text; 331 | -moz-user-select: text; 332 | -ms-user-select: text; 333 | user-select: text; 334 | } 335 | 336 | .params .name, .props .name, .name code { 337 | color: #4D4E53; 338 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 339 | font-size: 100%; 340 | } 341 | 342 | .params td.description > p:first-child, 343 | .props td.description > p:first-child 344 | { 345 | margin-top: 0; 346 | padding-top: 0; 347 | } 348 | 349 | .params td.description > p:last-child, 350 | .props td.description > p:last-child 351 | { 352 | margin-bottom: 0; 353 | padding-bottom: 0; 354 | } 355 | 356 | .disabled { 357 | color: #454545; 358 | } 359 | -------------------------------------------------------------------------------- /docs/styles/jsdoc.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box 3 | } 4 | 5 | html, body { 6 | height: 100%; 7 | width: 100%; 8 | } 9 | 10 | body { 11 | color: #4d4e53; 12 | background-color: white; 13 | margin: 0 auto; 14 | padding: 0 20px; 15 | font-family: 'Helvetica Neue', Helvetica, sans-serif; 16 | font-size: 16px; 17 | } 18 | 19 | img { 20 | max-width: 100%; 21 | } 22 | 23 | a, 24 | a:active { 25 | color: #606; 26 | text-decoration: none; 27 | } 28 | 29 | a:hover { 30 | text-decoration: none; 31 | } 32 | 33 | article a { 34 | border-bottom: 1px solid #ddd; 35 | } 36 | 37 | article a:hover, article a:active { 38 | border-bottom-color: #222; 39 | } 40 | 41 | article .description a { 42 | word-break: break-word; 43 | } 44 | 45 | p, ul, ol, blockquote { 46 | margin-bottom: 1em; 47 | line-height: 160%; 48 | } 49 | 50 | h1, h2, h3, h4, h5, h6 { 51 | font-family: 'Montserrat', sans-serif; 52 | } 53 | 54 | h1, h2, h3, h4, h5, h6 { 55 | color: #000; 56 | font-weight: 400; 57 | margin: 0; 58 | } 59 | 60 | h1 { 61 | font-weight: 300; 62 | font-size: 48px; 63 | margin: 1em 0 .5em; 64 | } 65 | 66 | h1.page-title { 67 | font-size: 48px; 68 | margin: 1em 30px; 69 | line-height: 100%; 70 | word-wrap: break-word; 71 | } 72 | 73 | h2 { 74 | font-size: 24px; 75 | margin: 1.5em 0 .3em; 76 | } 77 | 78 | h3 { 79 | font-size: 24px; 80 | margin: 1.2em 0 .3em; 81 | } 82 | 83 | h4 { 84 | font-size: 18px; 85 | margin: 1em 0 .2em; 86 | color: #4d4e53; 87 | } 88 | 89 | h4.name { 90 | color: #fff; 91 | background: #6d426d; 92 | box-shadow: 0 .25em .5em #d3d3d3; 93 | border-top: 1px solid #d3d3d3; 94 | border-bottom: 1px solid #d3d3d3; 95 | margin: 1.5em 0 0.5em; 96 | padding: .75em 0 .75em 10px; 97 | } 98 | 99 | h4.name a { 100 | color: #fc83ff; 101 | } 102 | 103 | h4.name a:hover { 104 | border-bottom-color: #fc83ff; 105 | } 106 | 107 | h5, .container-overview .subsection-title { 108 | font-size: 120%; 109 | letter-spacing: -0.01em; 110 | margin: 8px 0 3px 0; 111 | } 112 | 113 | h6 { 114 | font-size: 100%; 115 | letter-spacing: -0.01em; 116 | margin: 6px 0 3px 0; 117 | font-style: italic; 118 | } 119 | 120 | .usertext h1 { 121 | font-family: "Source Sans Pro"; 122 | font-size: 24px; 123 | margin: 2.5em 0 1em; 124 | font-weight: 400; 125 | } 126 | 127 | .usertext h2 { 128 | font-family: "Source Sans Pro"; 129 | font-size: 18px; 130 | margin: 2em 0 0.5em; 131 | font-weight: 400; 132 | 133 | } 134 | 135 | .usertext h3 { 136 | font-family: "Source Sans Pro"; 137 | font-size: 15px; 138 | margin: 1.5em 0 0; 139 | font-weight: 400; 140 | } 141 | 142 | .usertext h4 { 143 | font-family: "Source Sans Pro"; 144 | font-size: 14px; 145 | margin: 0 0 0; 146 | font-weight: 400; 147 | } 148 | 149 | .usertext h5 { 150 | font-size: 12px; 151 | margin: 1em 0 0; 152 | font-weight: normal; 153 | color: #666; 154 | } 155 | 156 | .usertext h6 { 157 | font-size: 11px; 158 | margin: 1em 0 0; 159 | font-weight: normal; 160 | font-style: normal; 161 | color: #666; 162 | } 163 | 164 | 165 | tt, code, kbd, samp { 166 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 167 | background: #f4f4f4; 168 | padding: 1px 5px; 169 | } 170 | 171 | .class-description { 172 | font-size: 130%; 173 | line-height: 140%; 174 | margin-bottom: 1em; 175 | margin-top: 1em; 176 | } 177 | 178 | .class-description:empty { 179 | margin: 0 180 | } 181 | 182 | #main { 183 | float: right; 184 | width: calc(100% - 240px); 185 | } 186 | 187 | header { 188 | display: block 189 | } 190 | 191 | section { 192 | display: block; 193 | background-color: #fff; 194 | padding: 0 0 0 30px; 195 | } 196 | 197 | .variation { 198 | display: none 199 | } 200 | 201 | .signature-attributes { 202 | font-size: 60%; 203 | color: #eee; 204 | font-style: italic; 205 | font-weight: lighter; 206 | } 207 | 208 | nav { 209 | float: left; 210 | display: block; 211 | width: 250px; 212 | background: #fff; 213 | overflow: auto; 214 | position: fixed; 215 | height: 100%; 216 | } 217 | 218 | nav #nav-search{ 219 | width: 210px; 220 | height: 30px; 221 | padding: 5px 10px; 222 | font-size: 12px; 223 | line-height: 1.5; 224 | border-radius: 3px; 225 | margin-right: 20px; 226 | margin-top: 20px; 227 | } 228 | 229 | nav.wrap a{ 230 | word-wrap: break-word; 231 | } 232 | 233 | nav h3 { 234 | margin-top: 12px; 235 | font-size: 13px; 236 | text-transform: uppercase; 237 | letter-spacing: 1px; 238 | font-weight: 700; 239 | line-height: 24px; 240 | margin: 15px 0 10px; 241 | padding: 0; 242 | color: #000; 243 | } 244 | 245 | nav ul { 246 | font-family: 'Lucida Grande', 'Lucida Sans Unicode', arial, sans-serif; 247 | font-size: 100%; 248 | line-height: 17px; 249 | padding: 0; 250 | margin: 0; 251 | list-style-type: none; 252 | } 253 | 254 | nav ul a, 255 | nav ul a:active { 256 | font-family: 'Montserrat', sans-serif; 257 | line-height: 18px; 258 | padding: 0; 259 | display: block; 260 | font-size: 12px; 261 | } 262 | 263 | nav a:hover, 264 | nav a:active { 265 | color: #606; 266 | } 267 | 268 | nav > ul { 269 | padding: 0 10px; 270 | } 271 | 272 | nav > ul > li > a { 273 | color: #606; 274 | margin-top: 10px; 275 | } 276 | 277 | nav ul ul a { 278 | color: hsl(207, 1%, 60%); 279 | border-left: 1px solid hsl(207, 10%, 86%); 280 | } 281 | 282 | nav ul ul a, 283 | nav ul ul a:active { 284 | padding-left: 20px 285 | } 286 | 287 | nav h2 { 288 | font-size: 13px; 289 | margin: 10px 0 0 0; 290 | padding: 0; 291 | } 292 | 293 | nav > h2 > a { 294 | margin: 10px 0 -10px; 295 | color: #606 !important; 296 | } 297 | 298 | footer { 299 | color: hsl(0, 0%, 28%); 300 | margin-left: 250px; 301 | display: block; 302 | padding: 15px; 303 | font-style: italic; 304 | font-size: 90%; 305 | } 306 | 307 | .ancestors { 308 | color: #999 309 | } 310 | 311 | .ancestors a { 312 | color: #999 !important; 313 | } 314 | 315 | .clear { 316 | clear: both 317 | } 318 | 319 | .important { 320 | font-weight: bold; 321 | color: #950B02; 322 | } 323 | 324 | .yes-def { 325 | text-indent: -1000px 326 | } 327 | 328 | .type-signature { 329 | color: #CA79CA 330 | } 331 | 332 | .type-signature:last-child { 333 | color: #eee; 334 | } 335 | 336 | .name, .signature { 337 | font-family: Consolas, Monaco, 'Andale Mono', monospace 338 | } 339 | 340 | .signature { 341 | color: #fc83ff; 342 | } 343 | 344 | .details { 345 | margin-top: 6px; 346 | border-left: 2px solid #DDD; 347 | line-height: 20px; 348 | font-size: 14px; 349 | } 350 | 351 | .details dt { 352 | width: auto; 353 | float: left; 354 | padding-left: 10px; 355 | } 356 | 357 | .details dd { 358 | margin-left: 70px; 359 | margin-top: 6px; 360 | margin-bottom: 6px; 361 | } 362 | 363 | .details ul { 364 | margin: 0 365 | } 366 | 367 | .details ul { 368 | list-style-type: none 369 | } 370 | 371 | .details pre.prettyprint { 372 | margin: 0 373 | } 374 | 375 | .details .object-value { 376 | padding-top: 0 377 | } 378 | 379 | .description { 380 | margin-bottom: 1em; 381 | margin-top: 1em; 382 | } 383 | 384 | .code-caption { 385 | font-style: italic; 386 | font-size: 107%; 387 | margin: 0; 388 | } 389 | 390 | .prettyprint { 391 | font-size: 14px; 392 | overflow: auto; 393 | } 394 | 395 | .prettyprint.source { 396 | width: inherit; 397 | line-height: 18px; 398 | display: block; 399 | background-color: #0d152a; 400 | color: #aeaeae; 401 | } 402 | 403 | .prettyprint code { 404 | line-height: 18px; 405 | display: block; 406 | background-color: #0d152a; 407 | color: #4D4E53; 408 | } 409 | 410 | .prettyprint > code { 411 | padding: 15px; 412 | } 413 | 414 | .prettyprint .linenums code { 415 | padding: 0 15px 416 | } 417 | 418 | .prettyprint .linenums li:first-of-type code { 419 | padding-top: 15px 420 | } 421 | 422 | .prettyprint code span.line { 423 | display: inline-block 424 | } 425 | 426 | .prettyprint.linenums { 427 | padding-left: 70px; 428 | -webkit-user-select: none; 429 | -moz-user-select: none; 430 | -ms-user-select: none; 431 | user-select: none; 432 | } 433 | 434 | .prettyprint.linenums ol { 435 | padding-left: 0 436 | } 437 | 438 | .prettyprint.linenums li { 439 | border-left: 3px #34446B solid; 440 | } 441 | 442 | .prettyprint.linenums li.selected, .prettyprint.linenums li.selected * { 443 | background-color: #34446B; 444 | } 445 | 446 | .prettyprint.linenums li * { 447 | -webkit-user-select: text; 448 | -moz-user-select: text; 449 | -ms-user-select: text; 450 | user-select: text; 451 | } 452 | 453 | .prettyprint.linenums li code:empty:after { 454 | content:""; 455 | display:inline-block; 456 | width:0px; 457 | } 458 | 459 | table { 460 | border-spacing: 0; 461 | border: 1px solid #ddd; 462 | border-collapse: collapse; 463 | border-radius: 3px; 464 | box-shadow: 0 1px 3px rgba(0,0,0,0.1); 465 | width: 100%; 466 | font-size: 14px; 467 | margin: 1em 0; 468 | } 469 | 470 | td, th { 471 | margin: 0px; 472 | text-align: left; 473 | vertical-align: top; 474 | padding: 10px; 475 | display: table-cell; 476 | } 477 | 478 | thead tr, thead tr { 479 | background-color: #fff; 480 | font-weight: bold; 481 | border-bottom: 1px solid #ddd; 482 | } 483 | 484 | .params .type { 485 | white-space: nowrap; 486 | } 487 | 488 | .params code { 489 | white-space: pre; 490 | } 491 | 492 | .params td, .params .name, .props .name, .name code { 493 | color: #4D4E53; 494 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 495 | font-size: 100%; 496 | } 497 | 498 | .params td { 499 | border-top: 1px solid #eee 500 | } 501 | 502 | .params td.description > p:first-child, .props td.description > p:first-child { 503 | margin-top: 0; 504 | padding-top: 0; 505 | } 506 | 507 | .params td.description > p:last-child, .props td.description > p:last-child { 508 | margin-bottom: 0; 509 | padding-bottom: 0; 510 | } 511 | 512 | span.param-type, .params td .param-type, .param-type dd { 513 | color: #606; 514 | font-family: Consolas, Monaco, 'Andale Mono', monospace 515 | } 516 | 517 | .param-type dt, .param-type dd { 518 | display: inline-block 519 | } 520 | 521 | .param-type { 522 | margin: 14px 0; 523 | } 524 | 525 | .disabled { 526 | color: #454545 527 | } 528 | 529 | /* navicon button */ 530 | .navicon-button { 531 | display: none; 532 | position: relative; 533 | padding: 2.0625rem 1.5rem; 534 | transition: 0.25s; 535 | cursor: pointer; 536 | -webkit-user-select: none; 537 | -moz-user-select: none; 538 | -ms-user-select: none; 539 | user-select: none; 540 | opacity: .8; 541 | } 542 | .navicon-button .navicon:before, .navicon-button .navicon:after { 543 | transition: 0.25s; 544 | } 545 | .navicon-button:hover { 546 | transition: 0.5s; 547 | opacity: 1; 548 | } 549 | .navicon-button:hover .navicon:before, .navicon-button:hover .navicon:after { 550 | transition: 0.25s; 551 | } 552 | .navicon-button:hover .navicon:before { 553 | top: .825rem; 554 | } 555 | .navicon-button:hover .navicon:after { 556 | top: -.825rem; 557 | } 558 | 559 | /* navicon */ 560 | .navicon { 561 | position: relative; 562 | width: 2.5em; 563 | height: .3125rem; 564 | background: #000; 565 | transition: 0.3s; 566 | border-radius: 2.5rem; 567 | } 568 | .navicon:before, .navicon:after { 569 | display: block; 570 | content: ""; 571 | height: .3125rem; 572 | width: 2.5rem; 573 | background: #000; 574 | position: absolute; 575 | z-index: -1; 576 | transition: 0.3s 0.25s; 577 | border-radius: 1rem; 578 | } 579 | .navicon:before { 580 | top: .625rem; 581 | } 582 | .navicon:after { 583 | top: -.625rem; 584 | } 585 | 586 | /* open */ 587 | .nav-trigger:checked + label:not(.steps) .navicon:before, 588 | .nav-trigger:checked + label:not(.steps) .navicon:after { 589 | top: 0 !important; 590 | } 591 | 592 | .nav-trigger:checked + label .navicon:before, 593 | .nav-trigger:checked + label .navicon:after { 594 | transition: 0.5s; 595 | } 596 | 597 | /* Minus */ 598 | .nav-trigger:checked + label { 599 | -webkit-transform: scale(0.75); 600 | transform: scale(0.75); 601 | } 602 | 603 | /* × and + */ 604 | .nav-trigger:checked + label.plus .navicon, 605 | .nav-trigger:checked + label.x .navicon { 606 | background: transparent; 607 | } 608 | 609 | .nav-trigger:checked + label.plus .navicon:before, 610 | .nav-trigger:checked + label.x .navicon:before { 611 | -webkit-transform: rotate(-45deg); 612 | transform: rotate(-45deg); 613 | background: #FFF; 614 | } 615 | 616 | .nav-trigger:checked + label.plus .navicon:after, 617 | .nav-trigger:checked + label.x .navicon:after { 618 | -webkit-transform: rotate(45deg); 619 | transform: rotate(45deg); 620 | background: #FFF; 621 | } 622 | 623 | .nav-trigger:checked + label.plus { 624 | -webkit-transform: scale(0.75) rotate(45deg); 625 | transform: scale(0.75) rotate(45deg); 626 | } 627 | 628 | .nav-trigger:checked ~ nav { 629 | left: 0 !important; 630 | } 631 | 632 | .nav-trigger:checked ~ .overlay { 633 | display: block; 634 | } 635 | 636 | .nav-trigger { 637 | position: fixed; 638 | top: 0; 639 | clip: rect(0, 0, 0, 0); 640 | } 641 | 642 | .overlay { 643 | display: none; 644 | position: fixed; 645 | top: 0; 646 | bottom: 0; 647 | left: 0; 648 | right: 0; 649 | width: 100%; 650 | height: 100%; 651 | background: hsla(0, 0%, 0%, 0.5); 652 | z-index: 1; 653 | } 654 | 655 | /* nav level */ 656 | .level-hide { 657 | display: none; 658 | } 659 | html[data-search-mode] .level-hide { 660 | display: block; 661 | } 662 | 663 | 664 | @media only screen and (max-width: 680px) { 665 | body { 666 | overflow-x: hidden; 667 | } 668 | 669 | nav { 670 | background: #FFF; 671 | width: 250px; 672 | height: 100%; 673 | position: fixed; 674 | top: 0; 675 | right: 0; 676 | bottom: 0; 677 | left: -250px; 678 | z-index: 3; 679 | padding: 0 10px; 680 | transition: left 0.2s; 681 | } 682 | 683 | .navicon-button { 684 | display: inline-block; 685 | position: fixed; 686 | top: 1.5em; 687 | right: 0; 688 | z-index: 2; 689 | } 690 | 691 | #main { 692 | width: 100%; 693 | } 694 | 695 | #main h1.page-title { 696 | margin: 1em 0; 697 | } 698 | 699 | #main section { 700 | padding: 0; 701 | } 702 | 703 | footer { 704 | margin-left: 0; 705 | } 706 | } 707 | 708 | /** Add a '#' to static members */ 709 | [data-type="member"] a::before { 710 | content: '#'; 711 | display: inline-block; 712 | margin-left: -14px; 713 | margin-right: 5px; 714 | } 715 | 716 | #disqus_thread{ 717 | margin-left: 30px; 718 | } 719 | 720 | @font-face { 721 | font-family: 'Montserrat'; 722 | font-style: normal; 723 | font-weight: 400; 724 | src: url('../fonts/Montserrat/Montserrat-Regular.eot'); /* IE9 Compat Modes */ 725 | src: url('../fonts/Montserrat/Montserrat-Regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ 726 | url('../fonts/Montserrat/Montserrat-Regular.woff2') format('woff2'), /* Super Modern Browsers */ 727 | url('../fonts/Montserrat/Montserrat-Regular.woff') format('woff'), /* Pretty Modern Browsers */ 728 | url('../fonts/Montserrat/Montserrat-Regular.ttf') format('truetype'); /* Safari, Android, iOS */ 729 | } 730 | 731 | @font-face { 732 | font-family: 'Montserrat'; 733 | font-style: normal; 734 | font-weight: 700; 735 | src: url('../fonts/Montserrat/Montserrat-Bold.eot'); /* IE9 Compat Modes */ 736 | src: url('../fonts/Montserrat/Montserrat-Bold.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ 737 | url('../fonts/Montserrat/Montserrat-Bold.woff2') format('woff2'), /* Super Modern Browsers */ 738 | url('../fonts/Montserrat/Montserrat-Bold.woff') format('woff'), /* Pretty Modern Browsers */ 739 | url('../fonts/Montserrat/Montserrat-Bold.ttf') format('truetype'); /* Safari, Android, iOS */ 740 | } 741 | 742 | @font-face { 743 | font-family: 'Source Sans Pro'; 744 | src: url('../fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot'); 745 | src: url('../fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot?#iefix') format('embedded-opentype'), 746 | url('../fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2') format('woff2'), 747 | url('../fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff') format('woff'), 748 | url('../fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf') format('truetype'), 749 | url('../fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg#source_sans_proregular') format('svg'); 750 | font-weight: 400; 751 | font-style: normal; 752 | } 753 | 754 | @font-face { 755 | font-family: 'Source Sans Pro'; 756 | src: url('../fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot'); 757 | src: url('../fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot?#iefix') format('embedded-opentype'), 758 | url('../fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2') format('woff2'), 759 | url('../fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff') format('woff'), 760 | url('../fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf') format('truetype'), 761 | url('../fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg#source_sans_prolight') format('svg'); 762 | font-weight: 300; 763 | font-style: normal; 764 | 765 | } -------------------------------------------------------------------------------- /docs/styles/prettify-jsdoc.css: -------------------------------------------------------------------------------- 1 | /* JSDoc prettify.js theme */ 2 | 3 | /* plain text */ 4 | .pln { 5 | color: #000000; 6 | font-weight: normal; 7 | font-style: normal; 8 | } 9 | 10 | /* string content */ 11 | .str { 12 | color: #006400; 13 | font-weight: normal; 14 | font-style: normal; 15 | } 16 | 17 | /* a keyword */ 18 | .kwd { 19 | color: #000000; 20 | font-weight: bold; 21 | font-style: normal; 22 | } 23 | 24 | /* a comment */ 25 | .com { 26 | font-weight: normal; 27 | font-style: italic; 28 | } 29 | 30 | /* a type name */ 31 | .typ { 32 | color: #000000; 33 | font-weight: normal; 34 | font-style: normal; 35 | } 36 | 37 | /* a literal value */ 38 | .lit { 39 | color: #006400; 40 | font-weight: normal; 41 | font-style: normal; 42 | } 43 | 44 | /* punctuation */ 45 | .pun { 46 | color: #000000; 47 | font-weight: bold; 48 | font-style: normal; 49 | } 50 | 51 | /* lisp open bracket */ 52 | .opn { 53 | color: #000000; 54 | font-weight: bold; 55 | font-style: normal; 56 | } 57 | 58 | /* lisp close bracket */ 59 | .clo { 60 | color: #000000; 61 | font-weight: bold; 62 | font-style: normal; 63 | } 64 | 65 | /* a markup tag name */ 66 | .tag { 67 | color: #006400; 68 | font-weight: normal; 69 | font-style: normal; 70 | } 71 | 72 | /* a markup attribute name */ 73 | .atn { 74 | color: #006400; 75 | font-weight: normal; 76 | font-style: normal; 77 | } 78 | 79 | /* a markup attribute value */ 80 | .atv { 81 | color: #006400; 82 | font-weight: normal; 83 | font-style: normal; 84 | } 85 | 86 | /* a declaration */ 87 | .dec { 88 | color: #000000; 89 | font-weight: bold; 90 | font-style: normal; 91 | } 92 | 93 | /* a variable name */ 94 | .var { 95 | color: #000000; 96 | font-weight: normal; 97 | font-style: normal; 98 | } 99 | 100 | /* a function name */ 101 | .fun { 102 | color: #000000; 103 | font-weight: bold; 104 | font-style: normal; 105 | } 106 | 107 | /* Specify class=linenums on a pre to get line numbering */ 108 | ol.linenums { 109 | margin-top: 0; 110 | margin-bottom: 0; 111 | } 112 | -------------------------------------------------------------------------------- /docs/styles/prettify-tomorrow.css: -------------------------------------------------------------------------------- 1 | /* Tomorrow Theme */ 2 | /* Original theme - https://github.com/chriskempson/tomorrow-theme */ 3 | /* Pretty printing styles. Used with prettify.js. */ 4 | /* SPAN elements with the classes below are added by prettyprint. */ 5 | /* plain text */ 6 | .pln { 7 | color: #4d4d4c; } 8 | 9 | @media screen { 10 | /* string content */ 11 | .str { 12 | color: #718c00; } 13 | 14 | /* a keyword */ 15 | .kwd { 16 | color: #8959a8; } 17 | 18 | /* a comment */ 19 | .com { 20 | color: #8e908c; } 21 | 22 | /* a type name */ 23 | .typ { 24 | color: #4271ae; } 25 | 26 | /* a literal value */ 27 | .lit { 28 | color: #f5871f; } 29 | 30 | /* punctuation */ 31 | .pun { 32 | color: #4d4d4c; } 33 | 34 | /* lisp open bracket */ 35 | .opn { 36 | color: #4d4d4c; } 37 | 38 | /* lisp close bracket */ 39 | .clo { 40 | color: #4d4d4c; } 41 | 42 | /* a markup tag name */ 43 | .tag { 44 | color: #c82829; } 45 | 46 | /* a markup attribute name */ 47 | .atn { 48 | color: #f5871f; } 49 | 50 | /* a markup attribute value */ 51 | .atv { 52 | color: #3e999f; } 53 | 54 | /* a declaration */ 55 | .dec { 56 | color: #f5871f; } 57 | 58 | /* a variable name */ 59 | .var { 60 | color: #c82829; } 61 | 62 | /* a function name */ 63 | .fun { 64 | color: #4271ae; } } 65 | /* Use higher contrast and text-weight for printable form. */ 66 | @media print, projection { 67 | .str { 68 | color: #060; } 69 | 70 | .kwd { 71 | color: #006; 72 | font-weight: bold; } 73 | 74 | .com { 75 | color: #600; 76 | font-style: italic; } 77 | 78 | .typ { 79 | color: #404; 80 | font-weight: bold; } 81 | 82 | .lit { 83 | color: #044; } 84 | 85 | .pun, .opn, .clo { 86 | color: #440; } 87 | 88 | .tag { 89 | color: #006; 90 | font-weight: bold; } 91 | 92 | .atn { 93 | color: #404; } 94 | 95 | .atv { 96 | color: #060; } } 97 | /* Style */ 98 | /* 99 | pre.prettyprint { 100 | background: white; 101 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 102 | font-size: 12px; 103 | line-height: 1.5; 104 | border: 1px solid #ccc; 105 | padding: 10px; } 106 | */ 107 | 108 | /* Specify class=linenums on a pre to get line numbering */ 109 | ol.linenums { 110 | margin-top: 0; 111 | margin-bottom: 0; } 112 | 113 | /* IE indents via margin-left */ 114 | li.L0, 115 | li.L1, 116 | li.L2, 117 | li.L3, 118 | li.L4, 119 | li.L5, 120 | li.L6, 121 | li.L7, 122 | li.L8, 123 | li.L9 { 124 | /* */ } 125 | 126 | /* Alternate shading for lines */ 127 | li.L1, 128 | li.L3, 129 | li.L5, 130 | li.L7, 131 | li.L9 { 132 | /* */ } 133 | -------------------------------------------------------------------------------- /docs/styles/prettify.css: -------------------------------------------------------------------------------- 1 | .pln { 2 | color: #ddd; 3 | } 4 | 5 | /* string content */ 6 | .str { 7 | color: #61ce3c; 8 | } 9 | 10 | /* a keyword */ 11 | .kwd { 12 | color: #fbde2d; 13 | } 14 | 15 | /* a comment */ 16 | .com { 17 | color: #aeaeae; 18 | } 19 | 20 | /* a type name */ 21 | .typ { 22 | color: #8da6ce; 23 | } 24 | 25 | /* a literal value */ 26 | .lit { 27 | color: #fbde2d; 28 | } 29 | 30 | /* punctuation */ 31 | .pun { 32 | color: #ddd; 33 | } 34 | 35 | /* lisp open bracket */ 36 | .opn { 37 | color: #000000; 38 | } 39 | 40 | /* lisp close bracket */ 41 | .clo { 42 | color: #000000; 43 | } 44 | 45 | /* a markup tag name */ 46 | .tag { 47 | color: #8da6ce; 48 | } 49 | 50 | /* a markup attribute name */ 51 | .atn { 52 | color: #fbde2d; 53 | } 54 | 55 | /* a markup attribute value */ 56 | .atv { 57 | color: #ddd; 58 | } 59 | 60 | /* a declaration */ 61 | .dec { 62 | color: #EF5050; 63 | } 64 | 65 | /* a variable name */ 66 | .var { 67 | color: #c82829; 68 | } 69 | 70 | /* a function name */ 71 | .fun { 72 | color: #4271ae; 73 | } 74 | 75 | /* Specify class=linenums on a pre to get line numbering */ 76 | ol.linenums { 77 | margin-top: 0; 78 | margin-bottom: 0; 79 | } 80 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wikiapi", 3 | "title": "JavaScript MediaWiki API for node.js", 4 | "version": "1.20.0", 5 | "description": "A simple way to access MediaWiki API via JavaScript with simple wikitext parser.", 6 | "keywords": [ 7 | "MediaWiki", 8 | "MediaWiki API", 9 | "wikitext", 10 | "ECMAScript 2017", 11 | "wikidata", 12 | "wdq", 13 | "sparql" 14 | ], 15 | "author": { 16 | "name": "vimunci", 17 | "email": "vimunci@gmail.com", 18 | "url": "https://github.com/kanasimi/CeJS" 19 | }, 20 | "contributors": [ 21 | "vimunci" 22 | ], 23 | "license": "BSD-3-Clause", 24 | "bugs": { 25 | "url": "https://github.com/kanasimi/wikiapi/issues" 26 | }, 27 | "homepage": "https://github.com/kanasimi/wikiapi", 28 | "repository": { 29 | "type": "git", 30 | "url": "git+https://github.com/kanasimi/wikiapi.git" 31 | }, 32 | 33 | "type": "commonjs", 34 | "main": "Wikiapi.js", 35 | "scripts": { 36 | "test": "nyc node \"_test suite/test.js\"", 37 | "report-coverage": "nyc report --reporter=text-lcov > coverage.lcov && curl -Os https://uploader.codecov.io/latest/linux/codecov && chmod +x codecov && ./codecov", 38 | "doc": "jsdoc --template node_modules/docdash --readme README.md --destination docs Wikiapi.js" 39 | }, 40 | "nyc": { 41 | "exclude": [ 42 | "_test suite/*" 43 | ] 44 | }, 45 | "engines": { 46 | "node": ">=12.0" 47 | }, 48 | "devDependencies": { 49 | "jsdoc": "latest", 50 | "docdash": "latest", 51 | 52 | "nyc": "latest" 53 | }, 54 | "dependencies": { 55 | "cejs": "latest" 56 | } 57 | } 58 | --------------------------------------------------------------------------------