├── .circleci └── config.yml ├── .gitattributes ├── .gitignore ├── .travis.yml ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── SECURITY.md ├── all.js ├── code-of-conduct.md ├── demo ├── _charts.js ├── app.js ├── demo.js ├── demo.tag ├── index.html ├── static │ ├── img │ │ ├── amex.png │ │ ├── diners_club.png │ │ ├── discover.png │ │ ├── example.png │ │ ├── first.jpg │ │ ├── jcb.png │ │ ├── mastercard.png │ │ ├── second.jpg │ │ ├── third.jpg │ │ └── visa.png │ ├── inc.html │ ├── inc.md │ ├── inc2.html │ └── tab.html └── style.css ├── dependencies └── js │ ├── iframify.js │ ├── riot+compiler-2.6.9.min.js │ └── riot+compiler-3.13.2.min.js ├── dist ├── rg-alerts │ └── rg-alerts.js ├── rg-bubble │ └── rg-bubble.js ├── rg-chart │ └── rg-chart.js ├── rg-code │ └── rg-code.js ├── rg-credit-card │ └── rg-credit-card-number.js ├── rg-date │ └── rg-date.js ├── rg-drawer │ └── rg-drawer.js ├── rg-ga │ └── rg-ga.js ├── rg-iframify │ └── rg-iframify.js ├── rg-include │ └── rg-include.js ├── rg-map │ └── rg-map.js ├── rg-markdown │ └── rg-markdown.js ├── rg-modal │ └── rg-modal.js ├── rg-pagination │ └── rg-pagination.js ├── rg-phone-sim │ └── rg-phone-sim.js ├── rg-placeholdit │ └── rg-placeholdit.js ├── rg-raw │ └── rg-raw.js ├── rg-select │ └── rg-select.js ├── rg-tabs │ └── rg-tabs.js ├── rg-tags │ └── rg-tags.js ├── rg-toast │ └── rg-toasts.js ├── rg-toggle │ └── rg-toggle.js ├── rg-unsplash │ └── rg-unsplash.js ├── rg.js └── rg.min.js ├── karma.conf.js ├── package.json ├── tags ├── rg-alerts │ ├── rg-alerts.blank.spec.js │ ├── rg-alerts.spec.js │ └── rg-alerts.tag ├── rg-audio │ └── rg-audio.tag ├── rg-bubble │ ├── rg-bubble.spec.js │ └── rg-bubble.tag ├── rg-chart │ ├── rg-chart.spec.js │ └── rg-chart.tag ├── rg-code │ ├── rg-code.spec.js │ └── rg-code.tag ├── rg-credit-card │ ├── rg-credit-card-number.tag │ └── rg-credit-card.spec.js ├── rg-date │ ├── rg-date.spec.js │ └── rg-date.tag ├── rg-drawer │ ├── rg-drawer.spec.js │ └── rg-drawer.tag ├── rg-ga │ ├── rg-ga.spec.js │ └── rg-ga.tag ├── rg-iframify │ ├── rg-iframify.spec.js │ └── rg-iframify.tag ├── rg-include │ ├── rg-include.spec.js │ └── rg-include.tag ├── rg-map │ ├── rg-map.spec.js │ └── rg-map.tag ├── rg-markdown │ ├── rg-markdown.spec.js │ └── rg-markdown.tag ├── rg-modal │ ├── rg-modal.spec.js │ └── rg-modal.tag ├── rg-pagination │ ├── rg-pagination.spec.js │ └── rg-pagination.tag ├── rg-phone-sim │ ├── rg-phone-sim.spec.js │ └── rg-phone-sim.tag ├── rg-placeholdit │ ├── rg-placeholdit.spec.js │ └── rg-placeholdit.tag ├── rg-raw │ ├── rg-raw.spec.js │ └── rg-raw.tag ├── rg-select │ ├── rg-select.filter.spec.js │ ├── rg-select.spec.js │ └── rg-select.tag ├── rg-tabs │ ├── rg-tabs.spec.js │ └── rg-tabs.tag ├── rg-tags │ ├── rg-tags.spec.js │ └── rg-tags.tag ├── rg-toast │ ├── rg-toasts.spec.js │ └── rg-toasts.tag ├── rg-toggle │ ├── rg-toggle.spec.js │ └── rg-toggle.tag └── rg-unsplash │ ├── rg-unsplash.spec.js │ └── rg-unsplash.tag ├── test-helpers.js └── yarn.lock /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | build: 4 | docker: 5 | - image: circleci/node:12.6-browsers 6 | 7 | working_directory: ~/repo 8 | 9 | steps: 10 | - checkout 11 | 12 | - restore_cache: 13 | keys: 14 | - v1-dependencies-{{ checksum "package.json" }} 15 | - v1-dependencies- 16 | 17 | - run: yarn install 18 | 19 | - save_cache: 20 | paths: 21 | - node_modules 22 | key: v1-dependencies-{{ checksum "package.json" }} 23 | 24 | - run: yarn test -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | dist/* binary 2 | dist/**/* binary 3 | yarn.lock binary 4 | demo/demo.js binary -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | node_modules/ 3 | coverage 4 | npm-debug.log 5 | 6 | # parcel files 7 | _dist/ 8 | .cache/ -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "5" 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | First of all, Pull Requests, suggestions or comments about RiotGear are all welcome and valued. To start contributing follow these steps: 4 | 5 | ## Step 1 - Fork the repo and install 6 | 7 | ``` 8 | git clone https://github.com/riotgear/rg/ 9 | cd rg 10 | yarn install 11 | yarn demo 12 | ``` 13 | 14 | A local copy of the riotgear demo should now be running on http://localhost:1234 (port may vary if port is already in use) 15 | 16 | ## Step 2 - Write some code 17 | 18 | * You can modify existing tags or add a new tag in the `tags/rg-TAGNAME/rg-TAGNAME.tag` folder (where TAGNAME can be whatever you want). Then edit `all.js` to `import './tags/rg-TAGNAME/rg-TAGNAME`. 19 | 20 | * OPTIONAL - Modify `demo/demo.tag` to include a demo of your tag. This isn't required, but will help you develop and help whoever us understand your contribution. 21 | 22 | * OPTIONAL - Add a test file like `tags/rg-TAGNAME/rg-TAGNAME.spec.js`. You can look at the other tests for ideas for what to write. If you can't get the test runner working (we use puppeteer, which may not work on every machine), feel free to contact us. Tests are run with `yarn test` and an individual test can be run by modifying the spec file with `describe.only` or `it.only`. 23 | 24 | ## Step 3 25 | 26 | **Submit your Pull Request to our DEV branch** so that we can review the code before merging into master. 27 | 28 | ## Sit back 29 | 30 | At some point your changes will get merged in and we'll publish a new version of RiotGear! Yay! 31 | 32 | ### Code Conduct 33 | 34 | We're all friends! This project adheres to the [Contriubtor Covenant](./code-of-conduct.md). By participating, you are expected to honor this code. 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![CircleCI](https://circleci.com/gh/chriscauley/rg.svg?style=svg)](https://circleci.com/gh/chriscauley/rg) 2 | 3 | The open source component library for Riot. 4 | 5 | **http://riotgear.js.org** 6 | 7 | 8 | 9 | 10 | 11 | ## Contributing 12 | 13 | If you're interested in contributing or just in running the RiotGear repo locally, checkout the [Contribution Guide](CONTRIBUTING.md) -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Use this section to tell people about which versions of your project are 6 | currently being supported with security updates. 7 | 8 | | Version | Supported | 9 | | ------- | ------------------ | 10 | | 5.1.x | :white_check_mark: | 11 | | 5.0.x | :x: | 12 | | 4.0.x | :white_check_mark: | 13 | | < 4.0 | :x: | 14 | 15 | ## Reporting a Vulnerability 16 | 17 | Use this section to tell people how to report a vulnerability. 18 | 19 | Tell them where to go, how often they can expect to get an update on a 20 | reported vulnerability, what to expect if the vulnerability is accepted or 21 | declined, etc. 22 | -------------------------------------------------------------------------------- /all.js: -------------------------------------------------------------------------------- 1 | import "./tags/rg-alerts/rg-alerts" 2 | import "./tags/rg-bubble/rg-bubble" 3 | import "./tags/rg-chart/rg-chart" 4 | import "./tags/rg-code/rg-code" 5 | import "./tags/rg-credit-card/rg-credit-card-number" 6 | import "./tags/rg-date/rg-date" 7 | import "./tags/rg-drawer/rg-drawer" 8 | import "./tags/rg-ga/rg-ga" 9 | import "./tags/rg-iframify/rg-iframify" 10 | import "./tags/rg-include/rg-include" 11 | import "./tags/rg-map/rg-map" 12 | import "./tags/rg-markdown/rg-markdown" 13 | import "./tags/rg-modal/rg-modal" 14 | import "./tags/rg-pagination/rg-pagination" 15 | import "./tags/rg-phone-sim/rg-phone-sim" 16 | import "./tags/rg-placeholdit/rg-placeholdit" 17 | import "./tags/rg-raw/rg-raw" 18 | import "./tags/rg-select/rg-select" 19 | import "./tags/rg-tabs/rg-tabs" 20 | import "./tags/rg-tags/rg-tags" 21 | import "./tags/rg-toast/rg-toasts" 22 | import "./tags/rg-toggle/rg-toggle" 23 | import "./tags/rg-unsplash/rg-unsplash" -------------------------------------------------------------------------------- /code-of-conduct.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies within all project spaces, and it also applies when 49 | an individual is representing the project or its community in public spaces. 50 | Examples of representing a project or community include using an official 51 | project e-mail address, posting via an official social media account, or acting 52 | as an appointed representative at an online or offline event. Representation of 53 | a project may be further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at [INSERT EMAIL ADDRESS]. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | 78 | -------------------------------------------------------------------------------- /demo/_charts.js: -------------------------------------------------------------------------------- 1 | window._charts = { 2 | linechart: { 3 | type: 'line', 4 | data: { 5 | labels: ["January", "February", "March", "April", "May", "June", "July"], 6 | datasets: [{ 7 | label: "My First dataset", 8 | fillColor: "rgba(220,220,220,0.2)", 9 | strokeColor: "rgba(220,220,220,1)", 10 | pointColor: "rgba(220,220,220,1)", 11 | pointStrokeColor: "#fff", 12 | pointHighlightFill: "#fff", 13 | pointHighlightStroke: "rgba(220,220,220,1)", 14 | data: [65, 59, 80, 81, 56, 55, 40] 15 | }, { 16 | label: "My Second dataset", 17 | fillColor: "rgba(151,187,205,0.2)", 18 | strokeColor: "rgba(151,187,205,1)", 19 | pointColor: "rgba(151,187,205,1)", 20 | pointStrokeColor: "#fff", 21 | pointHighlightFill: "#fff", 22 | pointHighlightStroke: "rgba(151,187,205,1)", 23 | data: [28, 48, 40, 19, 86, 27, 90] 24 | }] 25 | } 26 | }, 27 | 28 | barchart: { 29 | type: 'bar', 30 | data: { 31 | labels: ["January", "February", "March", "April", "May", "June", "July"], 32 | datasets: [{ 33 | label: "My First dataset", 34 | fillColor: "rgba(220,220,220,0.5)", 35 | strokeColor: "rgba(220,220,220,0.8)", 36 | highlightFill: "rgba(220,220,220,0.75)", 37 | highlightStroke: "rgba(220,220,220,1)", 38 | data: [65, 59, 80, 81, 56, 55, 40] 39 | }, { 40 | label: "My Second dataset", 41 | fillColor: "rgba(151,187,205,0.5)", 42 | strokeColor: "rgba(151,187,205,0.8)", 43 | highlightFill: "rgba(151,187,205,0.75)", 44 | highlightStroke: "rgba(151,187,205,1)", 45 | data: [28, 48, 40, 19, 86, 27, 90] 46 | }] 47 | } 48 | }, 49 | 50 | radarchart: { 51 | type: 'radar', 52 | data: { 53 | labels: ["Eating", "Drinking", "Sleeping", "Designing", "Coding", "Cycling", "Running"], 54 | datasets: [{ 55 | label: "My First dataset", 56 | fillColor: "rgba(220,220,220,0.2)", 57 | strokeColor: "rgba(220,220,220,1)", 58 | pointColor: "rgba(220,220,220,1)", 59 | pointStrokeColor: "#fff", 60 | pointHighlightFill: "#fff", 61 | pointHighlightStroke: "rgba(220,220,220,1)", 62 | data: [65, 59, 90, 81, 56, 55, 40] 63 | }, { 64 | label: "My Second dataset", 65 | fillColor: "rgba(151,187,205,0.2)", 66 | strokeColor: "rgba(151,187,205,1)", 67 | pointColor: "rgba(151,187,205,1)", 68 | pointStrokeColor: "#fff", 69 | pointHighlightFill: "#fff", 70 | pointHighlightStroke: "rgba(151,187,205,1)", 71 | data: [28, 48, 40, 19, 96, 27, 100] 72 | }] 73 | } 74 | }, 75 | 76 | polarchart: { 77 | type: 'polar', 78 | data: [{ 79 | value: 300, 80 | color: "#F7464A", 81 | highlight: "#FF5A5E", 82 | label: "Red" 83 | }, { 84 | value: 50, 85 | color: "#46BFBD", 86 | highlight: "#5AD3D1", 87 | label: "Green" 88 | }, { 89 | value: 100, 90 | color: "#FDB45C", 91 | highlight: "#FFC870", 92 | label: "Yellow" 93 | }, { 94 | value: 40, 95 | color: "#949FB1", 96 | highlight: "#A8B3C5", 97 | label: "Grey" 98 | }, { 99 | value: 120, 100 | color: "#4D5360", 101 | highlight: "#616774", 102 | label: "Dark Grey" 103 | }] 104 | }, 105 | 106 | piechart: { 107 | type: 'pie', 108 | data: [{ 109 | value: 300, 110 | color: "#F7464A", 111 | highlight: "#FF5A5E", 112 | label: "Red" 113 | }, { 114 | value: 50, 115 | color: "#46BFBD", 116 | highlight: "#5AD3D1", 117 | label: "Green" 118 | }, { 119 | value: 100, 120 | color: "#FDB45C", 121 | highlight: "#FFC870", 122 | label: "Yellow" 123 | }] 124 | }, 125 | 126 | doughnutchart: { 127 | type: 'doughnut', 128 | data: [{ 129 | value: 300, 130 | color: "#F7464A", 131 | highlight: "#FF5A5E", 132 | label: "Red" 133 | }, { 134 | value: 50, 135 | color: "#46BFBD", 136 | highlight: "#5AD3D1", 137 | label: "Green" 138 | }, { 139 | value: 100, 140 | color: "#FDB45C", 141 | highlight: "#FFC870", 142 | label: "Yellow" 143 | }] 144 | } 145 | } -------------------------------------------------------------------------------- /demo/app.js: -------------------------------------------------------------------------------- 1 | import riot from 'riot' 2 | import "../dependencies/js/iframify.js" 3 | 4 | import './demo.tag' 5 | import '../all' 6 | 7 | riot.mount('rg-demo') -------------------------------------------------------------------------------- /demo/demo.js: -------------------------------------------------------------------------------- 1 | import './_charts.js' 2 | 3 | riot.tag2('rg-demo', '

Alert

Bubble

Hover over me

Code

Chart

Credit Card

Date

{date.date}

Drawer

GA

Google Analytics tag is on this page. Look at Network tab in Developer Tools

iFramify

This is a component. Under 400px, the border of this component will go pink.

This is a component. Under 400px, the border of this component will go pink.

Include

Map

Markdown

Modal

Well hello there!

Pagination

Phone Sim

Placehold.it

Select

Select -w/ filter

Tabs

Tags

Toast

Toggle



Unsplash

>> END

', '', '', function(opts) { 4 | /* 5 | * ALERTS 6 | */ 7 | this.alerts = [{ 8 | type: 'primary', 9 | text: 'Look! Something you should know about.' 10 | }, { 11 | type: 'secondary', 12 | text: 'Warning! Something sort of bad happened.', 13 | dismissable: false 14 | }, { 15 | type: 'success', 16 | text: 'Success! Well done.' 17 | }, { 18 | type: 'error', 19 | text: 'Error! Something bad happened.', 20 | dismissable: true, 21 | timeout: 2000 22 | }]; 23 | 24 | this.addAlert = () => { 25 | this.alerts.push({ 26 | type: 'error', 27 | text: 'Eeek! Something broke...' 28 | }); 29 | }; 30 | /* 31 | * BUBBLE 32 | */ 33 | 34 | this.bubble = { 35 | text: 'Ping' 36 | }; 37 | 38 | this.updateBubbleText = () => { 39 | this.bubble = { 40 | text: 'Pong!' 41 | }; 42 | }; 43 | /* 44 | * CHART 45 | */ 46 | 47 | Object.assign(this, _charts); 48 | /* 49 | * CODE 50 | */ 51 | 52 | this.editorSettings = { 53 | code: '

Hello world!

' 54 | }; 55 | 56 | this.changeCode = () => { 57 | this.editorSettings.code = 'this.msg = "Hello RiotGear!";'; 58 | this.editorSettings.mode = 'javascript'; 59 | }; 60 | /* 61 | * CREDIT CARD NUMBER 62 | */ 63 | 64 | this.creditcard = { 65 | placeholder: 'Long number on front', 66 | cardnumber: '4000 0000 0000 0002' 67 | }; 68 | 69 | this.changeCardNumber = () => { 70 | this.creditcard.cardnumber = 5105105105105100; 71 | }; 72 | /* 73 | * DATE 74 | */ 75 | 76 | this.date = { 77 | date: moment(), 78 | min: moment().startOf('year'), 79 | max: moment().endOf('year') 80 | }; 81 | 82 | this.changeDate = () => { 83 | this.date.date = '2015-01-01'; 84 | }; 85 | /* 86 | * DRAWER 87 | */ 88 | 89 | this.drawer = { 90 | header: 'Drawer', 91 | isvisible: true, 92 | position: 'bottom', 93 | items: [{ 94 | text: 'Item 1' 95 | }, { 96 | text: 'Item 2' 97 | }] 98 | }; 99 | 100 | this.openDrawer = () => { 101 | this.drawer.isvisible = true; 102 | }; 103 | /* 104 | * IFRAMIFY 105 | */ 106 | 107 | this.iframify = {}; 108 | /* 109 | * INCLUDE 110 | */ 111 | 112 | this.include = { 113 | url: 'inc.html' 114 | }; 115 | this.includeTwo = { 116 | url: 'inc.html', 117 | unsafe: true 118 | }; 119 | this.includeThree = { 120 | url: 'inc2.html', 121 | unsafe: true 122 | /* 123 | * MAP 124 | */ 125 | 126 | }; 127 | this.on("mount", () => { 128 | this.tags['rg-map'].on('loaded', map => { 129 | var marker = new google.maps.Marker({ 130 | position: { 131 | lat: 53.806, 132 | lng: -1.535 133 | }, 134 | map: map, 135 | title: 'Hello RiotGear!' 136 | }); 137 | }); 138 | }); 139 | /* 140 | * MARKDOWN 141 | */ 142 | 143 | this.markdown = { 144 | content: '**Some** content' 145 | }; 146 | 147 | this.changeMarkdown = () => { 148 | this.markdown = { 149 | url: 'inc.md' 150 | }; 151 | }; 152 | /* 153 | * MODAL 154 | */ 155 | 156 | this.modal = { 157 | isvisible: true, 158 | heading: 'Modal heading', 159 | buttons: [{ 160 | text: 'Ok', 161 | type: 'primary', 162 | action: () => this.modal.isvisible = false 163 | }, { 164 | text: 'Canel', 165 | action: () => this.modal.isvisible = false 166 | }] 167 | }; 168 | 169 | this.toggleModal = () => { 170 | this.modal.isvisible = !this.modal.isvisible; 171 | }; 172 | 173 | this.toggleModalType = () => { 174 | this.modal.ghost = !this.modal.ghost; 175 | }; 176 | 177 | this.toggleModalDismissable = () => { 178 | this.modal.dismissable = !this.modal.dismissable; 179 | }; 180 | /* 181 | * PAGINATION 182 | */ 183 | 184 | this.pagination = { 185 | pages: 100, 186 | page: 3, 187 | action: page => console.log(page) 188 | /* 189 | * PHONE SIM 190 | */ 191 | 192 | }; 193 | this.phonesim = { 194 | url: 'http://riotgear.js.org/' 195 | }; 196 | 197 | this.changePhoneSimURL = () => { 198 | this.phonesim.url = 'http://riot.js.org'; 199 | }; 200 | /* 201 | * PLACEHOLDIT 202 | */ 203 | 204 | this.placeholdit = {}; 205 | 206 | this.changePlacholdIt = () => { 207 | this.placeholdit.width = 200; 208 | this.placeholdit.height = 100; 209 | this.placeholdit.background = '1fadc5'; 210 | this.placeholdit.color = '4df'; 211 | this.placeholdit.textsize = 50; 212 | this.placeholdit.text = 'JPEG'; 213 | this.placeholdit.format = 'jpg'; 214 | }; 215 | /* 216 | * SELECT 217 | */ 218 | 219 | this.select = { 220 | placeholder: 'Please select a card', 221 | options: [{ 222 | id: 0, 223 | text: 'Visa' 224 | }, { 225 | id: 1, 226 | text: 'MasterCard', 227 | selected: true 228 | }, { 229 | id: 2, 230 | text: 'American Express' 231 | }, { 232 | id: 3, 233 | text: 'Discover' 234 | }] 235 | /* 236 | * SELECT WITH FILTER 237 | */ 238 | 239 | }; 240 | this.selectWithFilter = { 241 | placeholder: 'Please select a card', 242 | filter: 'text', 243 | options: [{ 244 | id: 0, 245 | text: 'Visa' 246 | }, { 247 | id: 1, 248 | text: 'MasterCard', 249 | selected: true 250 | }, { 251 | id: 2, 252 | text: 'American Express' 253 | }, { 254 | id: 3, 255 | text: 'Discover' 256 | }] 257 | /* 258 | * UNSPLASH 259 | */ 260 | 261 | }; 262 | this.unsplash = {}; 263 | 264 | this.changeUnsplash = () => { 265 | this.unsplash.width = 200; 266 | this.unsplash.height = 100; 267 | this.unsplash.greyscale = "true"; 268 | this.unsplash.random = "true"; 269 | this.unsplash.blur = "true"; 270 | this.unsplash.image = "491"; 271 | this.unsplash.gravity = "north"; 272 | }; 273 | /* 274 | * TOGGLE 275 | */ 276 | 277 | this.toggle = { 278 | type: 'primary', 279 | checked: true 280 | }; 281 | 282 | this.changeToggle = () => { 283 | this.toggle.checked = !this.toggle.checked; 284 | }; 285 | /* 286 | * TAGS 287 | */ 288 | 289 | this.rgTags = { 290 | placeholder: 'Choose a country', 291 | filter: 'text', 292 | options: [{ 293 | id: 0, 294 | text: 'England' 295 | }, { 296 | id: 0, 297 | text: 'Scotland' 298 | }, { 299 | id: 0, 300 | text: 'Ireland' 301 | }, { 302 | id: 0, 303 | text: 'Wales' 304 | }], 305 | tags: [{ 306 | id: 0, 307 | text: 'Russia' 308 | }] 309 | /* 310 | * TOASTS 311 | */ 312 | 313 | }; 314 | this.toasts = { 315 | position: 'topright', 316 | toasts: [{ 317 | type: 'primary', 318 | text: 'Hey look at me!' 319 | }] 320 | }; 321 | 322 | this.changeToasts = () => { 323 | this.toasts.toasts.push({ 324 | text: 'Me is a new toast' 325 | }); 326 | this.toasts.position = 'bottomleft'; 327 | }; 328 | /* 329 | * TABS 330 | */ 331 | 332 | this.tabs = { 333 | type: 'primary', 334 | tabs: [{ 335 | heading: 'Tab one', 336 | text: 'This is tab one' 337 | }, { 338 | heading: 'Tab two', 339 | text: 'This is tab two', 340 | active: true 341 | }, { 342 | heading: 'Disabled tab', 343 | text: 'This is disabled tab', 344 | disabled: true 345 | }, { 346 | heading: 'Tab three', 347 | text: 'This is tab three content', 348 | include: 'tab.html' 349 | }] 350 | }; 351 | 352 | this.changeTabContent = () => { 353 | this.tabs.tabs[0].heading = 'take a look at tab three'; 354 | this.tabs.tabs[3].include = 'inc.html'; 355 | }; 356 | }); 357 | -------------------------------------------------------------------------------- /demo/demo.tag: -------------------------------------------------------------------------------- 1 | import './_charts.js' 2 | 3 | 4 |

Alert

5 | 6 |
7 | 8 | 9 |
10 | 11 |

Bubble

12 | 13 |
14 | Hover over me 15 | 16 |
17 | 18 |

Code

19 | 20 |
21 | 22 |
23 | 24 | 25 |

Chart

26 |
27 | 28 | 29 | 30 | 31 | 32 | 33 |
34 | 35 |

Credit Card

36 | 37 |
38 | 39 | 40 |
41 | 42 |

Date

43 | 44 |
45 | 46 | { date.date } 47 | 48 |
49 | 50 |

Drawer

51 | 52 |
53 | 54 | 55 |
56 | 57 |

GA

58 | 59 |
60 | Google Analytics tag is on this page. Look at Network tab in Developer Tools 61 | 62 |
63 | 64 |

iFramify

65 |
66 |
67 |

This is a component. Under 400px, the border of this component will go pink.

68 |
69 | 70 |
71 |

This is a component. Under 400px, the border of this component will go pink.

72 |
73 |
74 |
75 | 76 |

Include

77 | 78 |
79 |
80 | 81 | 82 | 83 |
84 |
85 | 86 |

Map

87 | 88 |
89 | 90 |
91 | 92 |

Markdown

93 | 94 |
95 | 96 | 97 |
98 | 99 |

Modal

100 | 101 |
102 | 103 | Well hello there! 104 | 105 |
106 | 107 | 108 | 109 | 110 |

Pagination

111 |
112 | 113 |
114 | 115 |

Phone Sim

116 | 117 |
118 | 119 | 120 |
121 | 122 |

Placehold.it

123 | 124 |
125 | 126 |
127 | 128 | 129 |

Select

130 | 131 |
132 | 133 |
134 | 135 |

Select -w/ filter

136 | 137 |
138 | 139 |
140 | 141 |

Tabs

142 | 143 |
144 | 145 |
146 | 147 | 148 |

Tags

149 | 150 |
151 | 152 |
153 | 154 |

Toast

155 | 156 |
157 | 158 | 159 |
160 | 161 |

Toggle

162 | 163 |
164 | 165 |
166 |
167 | 168 |
169 | 170 |

Unsplash

171 | 172 |
173 | 174 |
175 | 176 | 177 |

>> END

178 | 179 | 531 |
532 | -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | RiotGear Demo 10 | 11 | 12 | 13 |
14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /demo/static/img/amex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RiotGear/rg/2470502fff96c1dd98804980213ca85499d80d76/demo/static/img/amex.png -------------------------------------------------------------------------------- /demo/static/img/diners_club.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RiotGear/rg/2470502fff96c1dd98804980213ca85499d80d76/demo/static/img/diners_club.png -------------------------------------------------------------------------------- /demo/static/img/discover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RiotGear/rg/2470502fff96c1dd98804980213ca85499d80d76/demo/static/img/discover.png -------------------------------------------------------------------------------- /demo/static/img/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RiotGear/rg/2470502fff96c1dd98804980213ca85499d80d76/demo/static/img/example.png -------------------------------------------------------------------------------- /demo/static/img/first.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RiotGear/rg/2470502fff96c1dd98804980213ca85499d80d76/demo/static/img/first.jpg -------------------------------------------------------------------------------- /demo/static/img/jcb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RiotGear/rg/2470502fff96c1dd98804980213ca85499d80d76/demo/static/img/jcb.png -------------------------------------------------------------------------------- /demo/static/img/mastercard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RiotGear/rg/2470502fff96c1dd98804980213ca85499d80d76/demo/static/img/mastercard.png -------------------------------------------------------------------------------- /demo/static/img/second.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RiotGear/rg/2470502fff96c1dd98804980213ca85499d80d76/demo/static/img/second.jpg -------------------------------------------------------------------------------- /demo/static/img/third.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RiotGear/rg/2470502fff96c1dd98804980213ca85499d80d76/demo/static/img/third.jpg -------------------------------------------------------------------------------- /demo/static/img/visa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RiotGear/rg/2470502fff96c1dd98804980213ca85499d80d76/demo/static/img/visa.png -------------------------------------------------------------------------------- /demo/static/inc.html: -------------------------------------------------------------------------------- 1 | This content is in a separate file and injected using the include tag 2 | -------------------------------------------------------------------------------- /demo/static/inc.md: -------------------------------------------------------------------------------- 1 | *This* content is in a separate file, parsed and injected using the **markdown** tag 2 | -------------------------------------------------------------------------------- /demo/static/inc2.html: -------------------------------------------------------------------------------- 1 | This is some other content from a different file 2 | -------------------------------------------------------------------------------- /demo/static/tab.html: -------------------------------------------------------------------------------- 1 | This tab three from a separate file 2 | -------------------------------------------------------------------------------- /demo/style.css: -------------------------------------------------------------------------------- 1 | .app-container { 2 | padding: 0 100px 3 | } 4 | 5 | h2 { 6 | padding-top: 40px; 7 | } 8 | 9 | .demo { 10 | position: relative; 11 | min-height: 200px; 12 | } 13 | 14 | .no-overflow { 15 | overflow: hidden; 16 | } 17 | 18 | .chart-container { 19 | width: 400px; 20 | } 21 | 22 | button { 23 | border: 0; 24 | border: 1px solid #ccc; 25 | background: #eee; 26 | padding: 5px; 27 | outline: none; 28 | } 29 | 30 | rg-map { 31 | position: absolute; 32 | left: 0; 33 | right: 0; 34 | height: 200px; 35 | } 36 | 37 | .iframify { 38 | width: 400px; 39 | } 40 | 41 | .component { 42 | background-color: #efefef; 43 | border: 1px solid rgba(0, 0, 0, 0.1); 44 | margin: 10px; 45 | padding: 10px; 46 | } 47 | 48 | .component-child { 49 | color: deeppink; 50 | } 51 | 52 | @media (max-width: 400px) { 53 | .component { 54 | border-color: deeppink; 55 | } 56 | } -------------------------------------------------------------------------------- /dependencies/js/iframify.js: -------------------------------------------------------------------------------- 1 | (function (global) { 2 | var metaViewport = document.querySelector('meta[name="viewport"]'); 3 | var metaCharset = document.querySelector('meta[charset]'); 4 | var metaViewportStr = metaViewport && metaViewport.outerHTML || ''; 5 | var metaCharsetStr = metaCharset && metaCharset.outerHTML || ''; 6 | var queryCache = {}; 7 | 8 | /** 9 | * Get the styling nodes to inject in the head of the embedded document 10 | * 11 | * @param {String} selector 12 | * @return {String} 13 | */ 14 | function getStylingNodes (selector) { 15 | if (typeof queryCache[selector] === 'undefined') { 16 | queryCache[selector] = Array.prototype.map.call( 17 | document.querySelectorAll(selector), 18 | function (stylesheet) { 19 | return stylesheet.outerHTML; 20 | } 21 | ).join(''); 22 | } 23 | 24 | return queryCache[selector]; 25 | } 26 | 27 | /** 28 | * Get the content for the iframified version of a node. 29 | * 30 | * @param {HTMLElement} node 31 | * @param {Object} options 32 | * @return {String} 33 | */ 34 | function getIframeContentForNode (node, options) { 35 | return '' + 36 | '' + 37 | '' + 38 | options.metaCharset + 39 | options.metaViewport + 40 | options.stylesheets + 41 | options.styles + 42 | '' + 43 | '' + 44 | node.innerHTML + 45 | '' + 46 | ''; 47 | } 48 | 49 | /** 50 | * Format an object of attributes into a HTML string 51 | * 52 | * @param {Object} attrObj 53 | * @return {String} 54 | */ 55 | function formatAttributes (attrObj) { 56 | var attributes = []; 57 | 58 | for (var attribute in attrObj) { 59 | attributes.push(attribute + '="' + attrObj[attribute] + '"'); 60 | } 61 | 62 | return attributes.join(' '); 63 | } 64 | 65 | /** 66 | * Get document height (stackoverflow.com/questions/1145850/) 67 | * 68 | * @param {Document} doc 69 | * @return {Number} 70 | */ 71 | function getDocumentHeight (doc) { 72 | doc = doc || document; 73 | var body = doc.body; 74 | var html = doc.documentElement; 75 | 76 | return Math.max( 77 | body.scrollHeight, body.offsetHeight, 78 | html.clientHeight, html.scrollHeight, html.offsetHeight 79 | ); 80 | } 81 | 82 | function getOptions (options) { 83 | var opts = options || {}; 84 | opts.htmlAttr = formatAttributes(opts.htmlAttr || {}); 85 | opts.bodyAttr = formatAttributes(opts.bodyAttr || {}); 86 | opts.sizingTimeout = opts.sizingTimeout || 500; 87 | opts.styles = (opts.styles ? '' : ''); 88 | opts.stylesheets = getStylingNodes(opts.stylesSelector || 'link[rel*=stylesheet], style'); 89 | opts.metaCharset = opts.metaCharset || metaCharsetStr; 90 | opts.metaViewport = opts.metaViewport || metaViewportStr; 91 | 92 | return opts; 93 | } 94 | 95 | /** 96 | * Transform a collection of nodes into an iframe version of themselves 97 | * including all the styles they need to perform correctly. 98 | * 99 | * @param {HTMLElement} nodes 100 | * @param {Object} options 101 | * @return undefined 102 | */ 103 | function iframify (node, options) { 104 | options = getOptions(options); 105 | 106 | var iframe = document.createElement('iframe'); 107 | var html = getIframeContentForNode(node, options); 108 | iframe.srcdoc = html; 109 | 110 | if (!('srcdoc' in iframe)) { 111 | console.log( 112 | 'Your browser does not support the `srcdoc` attribute on elements.' + 113 | 'Therefore, it is not possible to wrap this node with an iframe due' + 114 | 'to CORS policy.' 115 | ); 116 | 117 | return null; 118 | } 119 | 120 | node.parentNode.replaceChild(iframe, node); 121 | 122 | setTimeout(function () { 123 | var iframeDocument = iframe.contentDocument || iframe.contentWindow.document; 124 | iframe.height = getDocumentHeight(iframeDocument); 125 | }, options.sizingTimeout); 126 | 127 | return iframe; 128 | } 129 | 130 | global.iframify = iframify; 131 | }(window)); 132 | -------------------------------------------------------------------------------- /dist/rg-alerts/rg-alerts.js: -------------------------------------------------------------------------------- 1 | riot.tag2('rg-alerts', '
{text}
', '', '', function(opts) { 2 | this.on("mount", () => this.update()); 3 | this.on('update', () => { 4 | if (!opts.alerts) return; 5 | opts.alerts.forEach(alert => { 6 | if (typeof alert.isvisible === 'undefined') alert.isvisible = true; 7 | 8 | if (alert.timeout) { 9 | alert.startTimer = () => { 10 | alert.timer = setTimeout(() => { 11 | this.dismiss({ 12 | item: alert 13 | }); 14 | }, alert.timeout); 15 | }; 16 | 17 | alert.startTimer(); 18 | } 19 | }); 20 | }); 21 | 22 | this.dismiss = e => { 23 | const alert = e.item; 24 | alert.isvisible = false; 25 | clearTimeout(alert.timer); 26 | this.trigger('dismiss', alert); 27 | this.update(); 28 | }; 29 | 30 | this.select = e => { 31 | const alert = e.item; 32 | if (alert.onclick) alert.onclick(alert); 33 | this.trigger('select', alert); 34 | }; 35 | }); 36 | -------------------------------------------------------------------------------- /dist/rg-bubble/rg-bubble.js: -------------------------------------------------------------------------------- 1 | riot.tag2('rg-bubble', '
{opts.bubble.text}
', 'rg-bubble .context,[data-is="rg-bubble"] .context,rg-bubble .content,[data-is="rg-bubble"] .content{ display: inline-block; position: relative; } rg-bubble .bubble,[data-is="rg-bubble"] .bubble{ position: absolute; top: -70px; left: 50%; transform: translate3d(-50%, 0, 0); }', '', function(opts) { 2 | this.showBubble = () => { 3 | clearTimeout(this._timer); 4 | this.isvisible = true; 5 | }; 6 | 7 | this.hideBubble = () => { 8 | this._timer = setTimeout(() => { 9 | this.isvisible = false; 10 | this.update(); 11 | }, 1000); 12 | }; 13 | 14 | this.toggleBubble = () => { 15 | this.isvisible = !this.isvisible; 16 | }; 17 | }); 18 | -------------------------------------------------------------------------------- /dist/rg-chart/rg-chart.js: -------------------------------------------------------------------------------- 1 | riot.tag2('rg-chart', '', 'rg-chart,[data-is="rg-chart"]{ display: inline-block; width: 100%; }', '', function(opts) { 2 | Chart.defaults.global.responsive = true; 3 | this.on('mount', () => { 4 | drawChart(); 5 | }); 6 | this.on('loaded', c => { 7 | this.on('unmount', () => { 8 | c.destroy(); 9 | }); 10 | }); 11 | 12 | const drawChart = () => { 13 | if (!opts.chart) return; 14 | let ctx = this.root.querySelector('canvas').getContext('2d'); 15 | let chart = new Chart(ctx); 16 | let c = null; 17 | 18 | switch (opts.chart.type) { 19 | case 'line': 20 | c = chart.Line(opts.chart.data, opts.chart.options); 21 | break; 22 | 23 | case 'radar': 24 | c = chart.Radar(opts.chart.data, opts.chart.options); 25 | break; 26 | 27 | case 'polar': 28 | c = chart.PolarArea(opts.chart.data, opts.chart.options); 29 | break; 30 | 31 | case 'pie': 32 | c = chart.Pie(opts.chart.data, opts.chart.options); 33 | break; 34 | 35 | case 'doughnut': 36 | c = chart.Doughnut(opts.chart.data, opts.chart.options); 37 | break; 38 | 39 | default: 40 | c = chart.Bar(opts.chart.data, opts.chart.options); 41 | break; 42 | } 43 | 44 | this.trigger('loaded', c); 45 | }; 46 | }); 47 | -------------------------------------------------------------------------------- /dist/rg-code/rg-code.js: -------------------------------------------------------------------------------- 1 | riot.tag2('rg-code', '
', 'rg-code .editor,[data-is="rg-code"] .editor{ position: absolute; top: 0; right: 0; bottom: 0; left: 0; }', '', function(opts) { 2 | if (!opts.editor) opts.editor = { 3 | code: '' 4 | }; 5 | let editor; 6 | 7 | const setupEditor = () => { 8 | editor.setTheme(`ace/theme/${opts.editor.theme || 'monokai'}`); 9 | editor.getSession().setMode(`ace/mode/${opts.editor.mode || 'html'}`); 10 | editor.getSession().setTabSize(opts.editor.tabsize || 2); 11 | editor.getSession().setUseSoftTabs(opts.editor.softtabs); 12 | editor.getSession().setUseWrapMode(opts.editor.wordwrap); 13 | editor.setReadOnly(opts.editor.readonly); 14 | }; 15 | 16 | this.on('update', () => { 17 | /* istanbul ignore next */ 18 | if (!this.isMounted) { 19 | return; 20 | } // riot2 compatibility 21 | 22 | setupEditor(); 23 | if (opts.editor.code != editor.getValue()) editor.setValue(opts.editor.code, 1); 24 | }); 25 | this.on('mount', () => { 26 | opts.editor.code = opts.editor.code || ""; 27 | this.editor = editor = ace.edit(this.root.querySelector('.editor')); 28 | editor.$blockScrolling = Infinity; 29 | 30 | if (opts.editor.url) { 31 | const req = new XMLHttpRequest(); 32 | 33 | req.onload = resp => { 34 | opts.editor.code = resp; 35 | this.update(); 36 | }; 37 | 38 | req.open('get', opts.editor.url, true); 39 | req.send(); 40 | } 41 | 42 | editor.setValue(opts.editor.code, 1); 43 | /* istanbul ignore next */ 44 | 45 | editor.getSession().on('change', e => { 46 | opts.editor.code = editor.getValue(); 47 | this.trigger('onchange', editor.getValue()); 48 | }); 49 | this.update(); 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /dist/rg-credit-card/rg-credit-card-number.js: -------------------------------------------------------------------------------- 1 | riot.tag2('rg-credit-card-number', '', 'rg-credit-card-number .card-no,[data-is="rg-credit-card-number"] .card-no{ padding-right: 60px; background-repeat: no-repeat; background-position: right center; background-size: 60px; } rg-credit-card-number .amex,[data-is="rg-credit-card-number"] .amex{ background-image: url(img/amex.png); } rg-credit-card-number .diners_club,[data-is="rg-credit-card-number"] .diners_club{ background-image: url(img/diners_club.png); } rg-credit-card-number .discover,[data-is="rg-credit-card-number"] .discover{ background-image: url(img/discover.png); } rg-credit-card-number .jcb,[data-is="rg-credit-card-number"] .jcb{ background-image: url(img/jcb.png); } rg-credit-card-number .mastercard,[data-is="rg-credit-card-number"] .mastercard{ background-image: url(img/mastercard.png); } rg-credit-card-number .visa,[data-is="rg-credit-card-number"] .visa{ background-image: url(img/visa.png); }', '', function(opts) { 2 | this.on("mount", () => { 3 | this.input = this.root.querySelector("input"); 4 | this.input.value = opts.card.cardnumber; 5 | this.update(); 6 | }); // this just triggers update 7 | 8 | this.oninput = () => {}; 9 | 10 | if (!opts.card) opts.card = { 11 | cardnumber: '' 12 | }; 13 | this.on("update", () => { 14 | /* istanbul ignore next */ 15 | if (!this.isMounted) { 16 | return; 17 | } // riot2 compatibility 18 | 19 | opts.card.cardnumber = this.input.value; 20 | const res = validateCreditCard(opts.card.cardnumber); 21 | opts.card.valid = res.valid; 22 | this.icon = opts.card.valid ? res.card_type.name : ''; 23 | }); 24 | 25 | function validateCreditCard(input) { 26 | var card, card_type, card_types, get_card_type, is_valid_length, is_valid_luhn, normalize, validate, validate_number, _i, _len; 27 | 28 | card_types = [{ 29 | name: 'amex', 30 | icon: 'images/amex.png', 31 | pattern: /^3[47]/, 32 | valid_length: [15] 33 | }, { 34 | name: 'diners_club', 35 | icon: 'images/diners_club.png', 36 | pattern: /^30[0-5]/, 37 | valid_length: [14] 38 | }, { 39 | name: 'diners_club', 40 | icon: 'images/diners_club.png', 41 | pattern: /^36/, 42 | valid_length: [14] 43 | }, { 44 | name: 'jcb', 45 | icon: 'images/jcb.png', 46 | pattern: /^35(2[89]|[3-8][0-9])/, 47 | valid_length: [16] 48 | }, { 49 | name: 'laser', 50 | pattern: /^(6304|670[69]|6771)/, 51 | valid_length: [16, 17, 18, 19] 52 | }, { 53 | name: 'visa_electron', 54 | pattern: /^(4026|417500|4508|4844|491(3|7))/, 55 | valid_length: [16] 56 | }, { 57 | name: 'visa', 58 | icon: 'images/visa.png', 59 | pattern: /^4/, 60 | valid_length: [16] 61 | }, { 62 | name: 'mastercard', 63 | icon: 'images/mastercard.png', 64 | pattern: /^5[1-5]/, 65 | valid_length: [16] 66 | }, { 67 | name: 'maestro', 68 | pattern: /^(5018|5020|5038|6304|6759|676[1-3])/, 69 | valid_length: [12, 13, 14, 15, 16, 17, 18, 19] 70 | }, { 71 | name: 'discover', 72 | icon: 'images/discover.png', 73 | pattern: /^(6011|622(12[6-9]|1[3-9][0-9]|[2-8][0-9]{2}|9[0-1][0-9]|92[0-5]|64[4-9])|65)/, 74 | valid_length: [16] 75 | }]; 76 | var options = { 77 | accept: card_types.map(c => c.name) 78 | }; 79 | 80 | get_card_type = function (number) { 81 | return card_types.find(c => number.match(c.pattern)) || null; 82 | }; 83 | 84 | is_valid_luhn = function (number) { 85 | var digit, n, sum, _j, _len1, _ref1; 86 | 87 | sum = 0; 88 | _ref1 = number.split('').reverse(); 89 | 90 | for (n = _j = 0, _len1 = _ref1.length; _j < _len1; n = ++_j) { 91 | digit = _ref1[n]; 92 | digit = +digit; 93 | 94 | if (n % 2) { 95 | digit *= 2; 96 | 97 | if (digit < 10) { 98 | sum += digit; 99 | } else { 100 | sum += digit - 9; 101 | } 102 | } else { 103 | sum += digit; 104 | } 105 | } 106 | 107 | return sum % 10 === 0; 108 | }; 109 | 110 | is_valid_length = function (number, card_type) { 111 | return card_type.valid_length.indexOf(number.length) !== -1; 112 | }; 113 | 114 | validate_number = function (_this) { 115 | return function (number) { 116 | var length_valid, luhn_valid; 117 | card_type = get_card_type(number); 118 | luhn_valid = false; 119 | length_valid = false; 120 | 121 | if (card_type != null) { 122 | luhn_valid = is_valid_luhn(number); 123 | length_valid = is_valid_length(number, card_type); 124 | } 125 | 126 | return { 127 | card_type: card_type, 128 | valid: luhn_valid && length_valid, 129 | luhn_valid: luhn_valid, 130 | length_valid: length_valid 131 | }; 132 | }; 133 | }(this); 134 | 135 | normalize = function (number) { 136 | return number.replace(/[ -]/g, ''); 137 | }; 138 | 139 | validate = function (_this) { 140 | return function () { 141 | return validate_number(normalize(input)); 142 | }; 143 | }(this); 144 | 145 | return validate(input); 146 | } 147 | }); 148 | -------------------------------------------------------------------------------- /dist/rg-date/rg-date.js: -------------------------------------------------------------------------------- 1 | riot.tag2('rg-date', '
{opts.date.date.format(yearFormat)}
{opts.date.date.format(monthFormat)}
Mo
Tu
We
Th
Fr
Sa
Su
', 'rg-date .container,[data-is="rg-date"] .container{ position: relative; display: inline-block; cursor: pointer; } rg-date .calendar,[data-is="rg-date"] .calendar{ position: absolute; min-width: 300px; margin-top: .5em; left: 0; }', '', function(opts) { 2 | const toMoment = d => { 3 | if (!moment.isMoment(d)) d = moment(d); 4 | if (d.isValid()) return d; 5 | return moment(); 6 | }; 7 | 8 | const handleClickOutside = e => { 9 | if (!this.root.contains(e.target)) this.close(); 10 | this.update(); 11 | }; 12 | 13 | this.dayObj = dayDate => { 14 | const dateObj = dayDate || moment(); 15 | return { 16 | date: dateObj, 17 | selected: opts.date.date.isSame(dayDate, 'day'), 18 | today: moment().isSame(dayDate, 'day'), 19 | disabled: opts.date.min && opts.date.min.isAfter(dayDate) || opts.date.max && opts.date.max.isBefore(dayDate) 20 | }; 21 | }; 22 | 23 | const buildCalendar = () => { 24 | this.format = 'LL'; 25 | this.yearFormat = 'YYYY'; 26 | this.monthFormat = 'MMMM'; 27 | this.dayFormat = 'DD'; 28 | this.days = []; 29 | this.startBuffer = []; 30 | this.endBuffer = []; 31 | const begin = moment(opts.date.date).startOf('month'); 32 | const daysInMonth = moment(opts.date.date).daysInMonth(); 33 | const end = moment(opts.date.date).endOf('month'); 34 | 35 | for (let i = begin.isoWeekday() - 1; i > 0; i -= 1) { 36 | const d = moment(begin).subtract(i, 'days'); 37 | this.startBuffer.push(this.dayObj(d)); 38 | } 39 | 40 | for (let i = 0; i < daysInMonth; i++) { 41 | const current = moment(begin).add(i, 'days'); 42 | this.days.push(this.dayObj(current)); 43 | } 44 | 45 | for (let i = end.isoWeekday() + 1; i <= 7; i++) { 46 | const d = moment(end).add(i - end.isoWeekday(), 'days'); 47 | this.endBuffer.push(this.dayObj(d)); 48 | } 49 | }; 50 | 51 | this.on('mount', () => { 52 | if (!opts.date) opts.date = { 53 | date: moment() 54 | }; 55 | if (!opts.date.date) opts.date.date = moment(); 56 | opts.date.date = toMoment(opts.date.date); 57 | opts.date.min = toMoment(opts.date.min || -8.64e15); 58 | 59 | if (opts.date.min.isAfter(opts.date.date, 'day')) { 60 | opts.date.date = moment(opts.date.min); 61 | } 62 | 63 | opts.date.max = toMoment(opts.date.max || 8.64e15); 64 | 65 | if (opts.date.max.isBefore(opts.date.date, 'day')) { 66 | opts.date.date = moment(opts.date.max); 67 | } 68 | 69 | document.addEventListener('click', handleClickOutside); 70 | this.update(); 71 | }); 72 | this.on('update', () => { 73 | /* istanbul ignore next */ 74 | if (!this.isMounted) { 75 | return; 76 | } // riot2 compatibility 77 | 78 | opts.date.date = toMoment(opts.date.date); 79 | buildCalendar(); 80 | this.value = opts.date.date.format(this.format); 81 | }); 82 | this.on('unmount', () => { 83 | document.removeEventListener('click', handleClickOutside); 84 | }); 85 | 86 | this.open = () => { 87 | this.isvisible = true; 88 | this.trigger('open'); 89 | }; 90 | 91 | this.close = () => { 92 | if (this.isvisible) { 93 | this.isvisible = false; 94 | this.trigger('close'); 95 | } 96 | }; 97 | 98 | this.select = e => { 99 | opts.date.date = e.item.day.date; 100 | this.trigger('select', opts.date.date); 101 | }; 102 | 103 | this.setToday = () => { 104 | opts.date.date = moment(); 105 | this.trigger('select', opts.date.date); 106 | }; 107 | 108 | this.prevYear = () => { 109 | opts.date.date = opts.date.date.subtract(1, 'year'); 110 | }; 111 | 112 | this.nextYear = () => { 113 | opts.date.date = opts.date.date.add(1, 'year'); 114 | }; 115 | 116 | this.prevMonth = () => { 117 | opts.date.date = opts.date.date.subtract(1, 'month'); 118 | }; 119 | 120 | this.nextMonth = () => { 121 | opts.date.date = opts.date.date.add(1, 'month'); 122 | }; 123 | }); 124 | -------------------------------------------------------------------------------- /dist/rg-drawer/rg-drawer.js: -------------------------------------------------------------------------------- 1 | riot.tag2('rg-drawer', '

{opts.drawer.header}

', '', '', function(opts) { 2 | if (!opts.drawer) opts.drawer = {}; 3 | 4 | this.close = () => { 5 | opts.drawer.isvisible = false; 6 | this.trigger('close'); 7 | }; 8 | 9 | this.select = e => { 10 | opts.drawer.items.forEach(item => item.active = false); 11 | e.item.active = true; 12 | this.trigger('select', e.item); 13 | }; 14 | }); 15 | -------------------------------------------------------------------------------- /dist/rg-ga/rg-ga.js: -------------------------------------------------------------------------------- 1 | riot.tag2('rg-ga', '', '', '', function(opts) { 2 | /* istanbul ignore next */ 3 | (function (i, s, o, g, r, a, m) { 4 | i['GoogleAnalyticsObject'] = r; 5 | i[r] = i[r] || function () { 6 | (i[r].q = i[r].q || []).push(arguments); 7 | }, i[r].l = 1 * new Date(); 8 | a = s.createElement(o), m = s.getElementsByTagName(o)[0]; 9 | a.async = 1; 10 | a.src = g; 11 | m.parentNode.insertBefore(a, m); 12 | })(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga'); 13 | 14 | ga('create', opts.property, 'auto'); 15 | ga('send', 'pageview'); 16 | }); 17 | -------------------------------------------------------------------------------- /dist/rg-iframify/rg-iframify.js: -------------------------------------------------------------------------------- 1 | riot.tag2('rg-iframify', '
', 'rg-iframify .iframify,[data-is="rg-iframify"] .iframify{ margin: 0; padding: 0; } rg-iframify iframe,[data-is="rg-iframify"] iframe{ position: relative; width: 100%; border: 0; }', '', function(opts) { 2 | this.on('mount', () => { 3 | iframify(this.root.querySelector('.frame'), this.opts); 4 | }); 5 | }); 6 | -------------------------------------------------------------------------------- /dist/rg-include/rg-include.js: -------------------------------------------------------------------------------- 1 | riot.tag2('rg-include', '
{responseText}
', '', '', function(opts) { 2 | const fetch = () => { 3 | const req = new XMLHttpRequest(); 4 | 5 | req.onload = resp => { 6 | if (opts.include.unsafe) this.root.innerHTML = req.responseText;else this.responseText = req.responseText; 7 | this.update(); 8 | this.trigger('loaded'); 9 | }; 10 | 11 | req.open('get', opts.include.url, true); 12 | req.send(); 13 | this.trigger('loading'); 14 | }; 15 | 16 | this.on('mount', () => { 17 | fetch(); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /dist/rg-map/rg-map.js: -------------------------------------------------------------------------------- 1 | riot.tag2('rg-map', '
', 'rg-map .rg-map,[data-is="rg-map"] .rg-map{ margin: 0; padding: 0; width: 100%; height: 100%; } rg-map .rg-map img,[data-is="rg-map"] .rg-map img{ max-width: inherit; }', '', function(opts) { 2 | window.rg = window.rg || {}; 3 | window.rg.gmap = riot.observable({ 4 | initialize: () => { 5 | window.rg.gmap.trigger('initialize'); 6 | } 7 | }); 8 | this.on('mount', () => { 9 | if (!opts.map) opts.map = { 10 | center: { 11 | lat: 53.806, 12 | lng: -1.535 13 | }, 14 | zoom: 7 15 | /* istanbul ignore next */ 16 | 17 | }; 18 | rg.gmap.on('initialize', () => { 19 | opts.map.mapObj = new google.maps.Map(this.root.querySelector('.rg-map'), opts.map); 20 | this.trigger('loaded', opts.map.mapObj); 21 | }); 22 | 23 | if (!document.getElementById('gmap_script')) { 24 | let script = document.createElement('script'); 25 | script.setAttribute('id', 'gmap_script'); 26 | script.type = 'text/javascript'; 27 | script.src = 'https://maps.googleapis.com/maps/api/js?callback=window.rg.gmap.initialize'; 28 | document.body.appendChild(script); 29 | } 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /dist/rg-markdown/rg-markdown.js: -------------------------------------------------------------------------------- 1 | riot.tag2('rg-markdown', '', '', '', function(opts) { 2 | this.on("mount", () => this.update()); 3 | this.reader = new commonmark.Parser(); 4 | this.writer = new commonmark.HtmlRenderer(); 5 | this.on('update', () => { 6 | if (!opts.markdown) opts.markdown = {}; 7 | 8 | if (opts.markdown.content) { 9 | this.root.innerHTML = this.writer.render(this.reader.parse(opts.markdown.content)); 10 | } else if (opts.markdown.url) { 11 | const req = new XMLHttpRequest(); 12 | 13 | req.onload = resp => { 14 | this.root.innerHTML = this.writer.render(this.reader.parse(req.responseText)); 15 | this.trigger('loaded'); 16 | }; 17 | 18 | req.open('get', opts.markdown.url, true); 19 | req.send(); 20 | this.trigger('loading'); 21 | } 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /dist/rg-modal/rg-modal.js: -------------------------------------------------------------------------------- 1 | riot.tag2('rg-modal', '
', 'rg-modal .modal--ghost .modal__footer .button,[data-is="rg-modal"] .modal--ghost .modal__footer .button{ margin: 0 .5em 0 0; }', '', function(opts) { 2 | if (!opts.modal) opts.modal = {}; 3 | 4 | this.close = () => { 5 | if (opts.modal.dismissable) { 6 | opts.modal.isvisible = false; 7 | this.trigger('close'); 8 | } 9 | }; 10 | }); 11 | -------------------------------------------------------------------------------- /dist/rg-pagination/rg-pagination.js: -------------------------------------------------------------------------------- 1 | riot.tag2('rg-pagination', '', '', '', function(opts) { 2 | if (!opts.pagination) opts.pagination = { 3 | pages: 1, 4 | page: 1 5 | }; 6 | this.on('page', () => { 7 | const btns = this.root.querySelectorAll('button'); 8 | 9 | for (let i = 0; i < btns.length; i++) { 10 | btns[i].blur(); 11 | } 12 | }); 13 | 14 | this.forward = () => { 15 | opts.pagination.page++; 16 | this.trigger('page', opts.pagination.page); 17 | }; 18 | 19 | this.back = () => { 20 | opts.pagination.page--; 21 | this.trigger('page', opts.pagination.page); 22 | }; 23 | 24 | this.first = () => { 25 | opts.pagination.page = 1; 26 | this.trigger('page', opts.pagination.page); 27 | }; 28 | 29 | this.last = () => { 30 | opts.pagination.page = opts.pagination.pages; 31 | this.trigger('page', opts.pagination.page); 32 | }; 33 | }); 34 | -------------------------------------------------------------------------------- /dist/rg-phone-sim/rg-phone-sim.js: -------------------------------------------------------------------------------- 1 | riot.tag2('rg-phone-sim', '
', 'rg-phone-sim .emulator,[data-is="rg-phone-sim"] .emulator{ position: relative; width: 365px; height: 792px; background-image: url(\'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAW0AAAMYCAMAAAA3r0ZLAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAwBQTFRFMDk6+vr6KTM0lJucMz4/PklKJS8wLTg5Qk1OxsjILzo7gomJ2NvbdH5/ho2O9fb2KzY3ztHRPEdIOkVGZWxtjJSVOEJDkpeYWGRluL2+KTQ1vcHBoaWlPUZHcnp6nKKjOkRF1NfXqa2tp62tZnBxanV2VmFiZ29wVl1eaXJzbXR04uTktbq7QElK1tnZipKTi5CRTlZXpKioo6mqXmlqUVlaOEFCSVFSUFxdISssT1tcTlpbJC4vIiwtTVlaJjAxIy0uTFhZS1dYJzEyKDIzSlZXPUhJOURFO0ZHSVVWKzU2P0pLKjQ1OENEND0+QEtMLDY3SFRVN0JDQ05PLTc4ND9ANUBBQUxNNkFCR1NUMTo7RE9QLjg5N0BBR1JTRlJTLzk6RVFSMjs8RVBRRlFSNj9AMzw9SFNUMj0+IissMTs8MDo7SVRVRFBRMDs8MTw9IiwsMz0+Mjw9SlVWQ09QLjk6NT4/S1ZXND4/JC4uQU1OIy0tQk5PTFdYTVhZQExNTllaJS8vJzIyP0tMLzg5LDc4KDMzNT9AKjU1N0FCNkBBJjAwIywtMDs7Mj09NkFBJjExLjk5LDc3N0JCNUBAKjU2MTw8LDU2Ljc4OUNEKDEyQU1NPEhIPEhJO0dHOkZGND8/Qk5ORFBQQ09PLTY3OUREPkpKPkpLPUlJT1pbP0tLJTAwPUlKJzAxKjM07u/vKTIzsbW2YGprtLm50tXWPkhJo6endn+A3d/f6uvreoOEg4yN2tvc/Pz8n6am8/T0VFtcm6CgJS4v4OLi5ufnYGdncnt8dHp7gYaHJC0uu8DAjJGRQkxNxMfHKzQ1YGtsS1NUaXN0bnh5yMzMyszMy83Oy8/PdoCAKDIy7O3tT1dYuLu70NTUbXd46Onq6erreoCA2dzc8PHx8vPz5OXlnaSkn6Wmqq6ucHZ2t7y8o6eoeoSEkJaWm5+gW2ZnZG5vqa+wOEFB09bWtru7qrCwcXd4t7u83eDgzM7O7/DwNT4+7e7uwMPDwcPEeH5/////70wnUQAAAQB0Uk5T////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AFP3ByUAAA+NSURBVHja7N13nBTlGcDxEQI5AmJQBAkcnqhEDIhoWMt5iogmQbOaYNrqYrJh16gplmTVkILJpYCmF+DSE1JIcjRR7L333ntPYjQxvTl55tnr7N7t7uw+vDP3+/0x3G3hs5+vr++8M7s7eH75Xb5x+rOjN017aeq+tO++U1+atmn0s9M3Xl6BoFfm466ZOPROhIt259CJ19RS++7LdgW133a97O7aaI/a+VE0y+jRnUeF1p6wqfvvaz6+YVjT0jMyJ3rkeSdmzljaNKzh+OZuoE0TQmmvv67zLzrwmMY8wkXLNx5zYCfTdeur1p6wdeegblgKar8tbegc4lv/rirtjTMLT99/UVMKzgFLNS3avwA2c2Pl2n8tPHV1QxLJMks2rC6g/alC7ScvKozrhhyIFZRrKIzvi56sRHt94b/RIsZ1xeN7UYFuffna4/UJB68Er4rGHax648vUfmqkPnxBBrmqyixQv5FPlaP9Dz2eWdIEW9U1LdFjnQsG1n5ETz4dyowdavY+VE9XPTKQ9phddPfICjvk6lt3lruM6V97j132l26BK3S3BJAv79Gf9jN3BY85HKsadHhAedebSmtf+ofgEcOQqknDAsyLLi2pPTq4/0icatSRAefoUto7Bvc2oFSzGgLQHYtr3xTct5DVSA1XJgsD0puKaa99s9wzlwPImh5WzhXTl/5TRHt7uaN5GUI1bVmzqL64ufZfgkF/GD417rCA9e99tf8VzCPHoVPzjhPXaVv10d5bblzCyZE6nDIJ5pKde2u/Egz487Cp1zHlHr20h8otp50ETT2WgaeL7dCe2vcF/uOQqUsrA9z7emgHQ3thdEZLLpeL0kHYwq7BrdqjAv2ofEAnlU0EZaPjvTTgHdWlvXeEhnYu0VkuUoN7707tbW6X35oiciyc6C4yZxmaxPf2bTq0z5VfTo/IC8/20M5GZnAHy5JzO7Tvj85bCKlEzyIzdQdvLNxf0L4wmMQjMgnmemlHZubOBcQXqvb0CO0jk720o3OmIdhPTlft4FTrth5ju55tK8bbq/YG+emUiLzqTC/t6Lz1cYoYbwi0r47QisTz0j2w0xE6ngxWJVeLdrD+WxCZVx3J9ba0QNeAnj9T/twuOi87GcF9pLSdKM8U7Q2rV6+O0jcQMoXJJB2t96tzorzB99Y2NzfPjdQL9zLJZDJynw2YK85rvZ1ku9Cjuq+4xXknb4Js+XxU/WsQ5wnec7LlDcn6d544P+ddLFu+zlT/Vorzxd5k2fIJqfq3TJwney/Lls+RGBwniPPL3g6y5aOWBstWcd7BmypbLjhS/1LiPNWTTTMWBik02mijTWijTWijjTbFVTuZTqSTRW8OUzqJdpGyxT89mU2ELYv25kO4+LvnyUT4kmj3LV38YzjpGmin3dReIm2pF9BlU+LmMDmnrdBbUntQje0trj2o5m2FPlBiTWKQQm9R7cG03nZAexCFNtpoE9poE9poo01oo01oo01oo4021VT7MxIUBik02mijTeG1D5agMEih0UYbbUIbbUIbbbQJbbQJbbQJbbTRplppf1qCwiCFRhtttCm89lwJCoMUGm200Sa00Sa00Uab0Eab0Eab0EY73tqnS1AYpNBoo402hdc+VILCIIVGG220CW20CW200Sa00Sa00aYC9GkSFAYpNNpoo01oR0v7bRIUBik02mijTWijTWijjTahjTah7bL2hyUoDFJotNFGm9BGm0ppv0OCwiCFRhtttAlttAlttNEmtOOhfbwEhUEKjTbaaBPaaBPaLmi/T4LCIIVGG220CW20CW200ab6aS+UoDBIodFGG21CG21C2wXt4yQoDFJotNFGm9BGm9BGe7BpL5KgMEih0UYbbUIbbULbBe0PSFAYpNBoo402oY02oY32YNP+oASFQQqNNtpoE9poE9poDzbtj0hQGKTQaKONNqGNNpXS/qkEhUEKfYwEhUEKjTbaaBPaaBPaaA827Y9LUBik0GijjTahHS3tn0lQGKTQCyQoDFJotNFGm9BGm9BGG22qn/anJCgMUmi00Uabwmv/RILCIIVukKAwSKHRRhttQhttQhtttKl+2p+UoDBIodFGG20Kr/09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\'); background-repeat: no-repeat; background-position: center; background-size: cover; } rg-phone-sim .screen,[data-is="rg-phone-sim"] .screen{ position: absolute; top: 105px; left: 22px; background-color: white; width: 320px; height: 568px; border: 0; }', '', function(opts) { 2 | }); 3 | -------------------------------------------------------------------------------- /dist/rg-placeholdit/rg-placeholdit.js: -------------------------------------------------------------------------------- 1 | riot.tag2('rg-placeholdit', '', '', '', function(opts) { 2 | if (!opts.placeholdit) opts.placeholdit = {}; 3 | this.on("mount", () => this.update()); 4 | this.on('update', () => { 5 | opts.placeholdit.width = opts.placeholdit.width || 450; 6 | opts.placeholdit.height = opts.placeholdit.height || 250; 7 | opts.placeholdit.background = opts.placeholdit.background || '000'; 8 | opts.placeholdit.color = opts.placeholdit.color || 'fff'; 9 | opts.placeholdit.text = opts.placeholdit.text || `${opts.placeholdit.width} x ${opts.placeholdit.height}`; 10 | opts.placeholdit.textsize = opts.placeholdit.textsize || 30; 11 | opts.placeholdit.format = opts.placeholdit.format || 'png'; 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /dist/rg-raw/rg-raw.js: -------------------------------------------------------------------------------- 1 | riot.tag2('rg-raw', '', '', '', function(opts) { 2 | this.on('mount', () => this.update()); 3 | this.on('update', () => { 4 | this.root.innerHTML = opts.content || ''; 5 | }); 6 | }); 7 | -------------------------------------------------------------------------------- /dist/rg-select/rg-select.js: -------------------------------------------------------------------------------- 1 | riot.tag2('rg-select', ' ', 'rg-select .menu,[data-is="rg-select"] .menu{ position: absolute; }', '', function(opts) { 2 | /* istanbul ignore next */ 3 | if (!opts.select) opts.select = { 4 | options: [] 5 | }; 6 | 7 | const handleClickOutside = e => { 8 | if (!this.root.contains(e.target)) this.close(); 9 | this.update(); 10 | }; 11 | 12 | this.on('mount', () => { 13 | document.addEventListener('click', handleClickOutside); 14 | this.update(); 15 | }); 16 | this.on('unmount', () => { 17 | document.removeEventListener('click', handleClickOutside); 18 | }); 19 | 20 | this.keydown = e => { 21 | const was_open = this.isvisible; 22 | this.open(); 23 | 24 | if (e.keyCode === 38) { 25 | // ArrowUp 26 | this.navigate(-1); 27 | e.preventDefault(); 28 | } else if (e.keyCode === 40) { 29 | // ArrowDown 30 | this.navigate(1); 31 | e.preventDefault(); 32 | } else if (e.keyCode === 13) { 33 | // enter 34 | if (!was_open) { 35 | // if enter is pressed and wasn't opened, just open (above) and leave 36 | return; 37 | } 38 | 39 | const item = getActiveItem() || this.options[0]; 40 | item && this.select({ 41 | item 42 | }); 43 | this.close(); 44 | e.preventDefault(); 45 | } else { 46 | this._navigate(0); 47 | } 48 | }; 49 | 50 | this.select = e => { 51 | const value = e.item.text; 52 | getInput().value = e.item.text; 53 | this.trigger('select', e.item.text); 54 | opts.onselect && opts.onselect(e.item, this); 55 | opts.select.options.forEach(o => o.selected = false); 56 | e.item.selected = true; 57 | this.close(); 58 | }; 59 | 60 | this.navigate = dir => { 61 | const { 62 | options 63 | } = this; 64 | let new_index = (options.findIndex(o => o.active) + dir) % options.length; // javascript doesn't mod properly :( 65 | 66 | if (new_index < 0) { 67 | new_index = options.length - 1; 68 | } 69 | 70 | this._navigate(new_index); 71 | }; 72 | 73 | this._navigate = index => { 74 | opts.select.options.forEach(o => o.active = false); 75 | const item = this.options[index || 0]; 76 | 77 | if (item) { 78 | item.active = true; 79 | } 80 | }; 81 | 82 | this.on('update', () => { 83 | /* istanbul ignore next */ 84 | if (!this.isMounted) { 85 | return; 86 | } // riot2 compatibility 87 | 88 | const value = getValue(); 89 | this.options = opts.select.options; 90 | 91 | if (opts.select.filter) { 92 | if (value) { 93 | const r = new RegExp(value, 'i'); 94 | this.options = this.options.filter(o => o.text.match(r)); 95 | this.trigger('filter'); 96 | } 97 | } 98 | }); 99 | 100 | const getValue = () => getInput().value; 101 | 102 | const getInput = () => this.root.querySelector('input'); 103 | 104 | const getActiveItem = () => { 105 | return this.options.find(o => o.active); 106 | }; 107 | 108 | this.open = e => { 109 | this.isvisible = true; 110 | this.trigger('open'); 111 | }; 112 | 113 | this.close = e => { 114 | this.isvisible = false; 115 | this.trigger('close'); 116 | }; 117 | }); 118 | -------------------------------------------------------------------------------- /dist/rg-tabs/rg-tabs.js: -------------------------------------------------------------------------------- 1 | riot.tag2('rg-tabs', '
{heading}
{text}
{include.responseText}
', '', '', function(opts) { 2 | if (!opts.tabs) opts.tabs = {}; 3 | this.on('mount', () => this.update()); 4 | 5 | const fetch = tab => { 6 | if (tab.raw) { 7 | return; 8 | } 9 | 10 | const req = new XMLHttpRequest(); 11 | 12 | req.onload = resp => { 13 | tab.raw = req.responseText; 14 | tab.text = undefined; 15 | this.update(); 16 | this.trigger('loaded', tab); 17 | }; 18 | 19 | req.open('get', tab.include, true); 20 | req.send(); 21 | this.trigger('loading', tab); 22 | }; 23 | 24 | this.open = e => { 25 | let tab = e.item; 26 | 27 | if (!tab.disabled && !tab.active) { 28 | opts.tabs.tabs.forEach(tab => { 29 | tab.active = false; 30 | }); 31 | this.trigger('open', tab); 32 | tab.active = true; 33 | } 34 | }; 35 | 36 | this.on('update', () => { 37 | if (!Array.isArray(opts.tabs.tabs)) return; 38 | opts.tabs.tabs.forEach(tab => { 39 | if (!tab.disabled && tab.active && tab.include) { 40 | fetch(tab); 41 | } 42 | }); 43 | }); 44 | }); 45 | -------------------------------------------------------------------------------- /dist/rg-tags/rg-tags.js: -------------------------------------------------------------------------------- 1 | riot.tag2('rg-tags', '
', 'rg-tags .menu,[data-is="rg-tags"] .menu{ position: absolute; }', '', function(opts) { 2 | this.on('mount', () => this.update()); 3 | if (!opts.tags) opts.tags = { 4 | options: [], 5 | tags: [] 6 | }; 7 | if (!opts.tags.options) opts.tags.options = []; // options for rg-select 8 | 9 | if (!opts.tags.tags) opts.tags.tags = []; 10 | this.select_opts = Object.assign({ 11 | filter: true 12 | }, opts.tags); 13 | 14 | this.select = (item, tag) => { 15 | this.addTag(item); 16 | this.trigger('select', item); 17 | this.root.querySelector('input').value = ''; 18 | this.update(); 19 | }; 20 | 21 | this.addTag = item => { 22 | if (opts.tags.tags.indexOf(item) == -1) { 23 | opts.tags.tags.push(item); 24 | } 25 | }; 26 | 27 | this.removeTag = e => { 28 | opts.tags.tags = opts.tags.tags.filter(tag => { 29 | if (tag._id != e.item._id) return tag; 30 | }); 31 | }; 32 | 33 | this.on('update', () => { 34 | opts.tags.options.forEach(item => { 35 | item._id = item._id || (Math.floor(Math.random() * 60466175) + 1679615).toString(36); 36 | }); 37 | opts.tags.tags.forEach(tag => { 38 | tag._id = tag._id || (Math.floor(Math.random() * 60466175) + 1679615).toString(36); 39 | }); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /dist/rg-toast/rg-toasts.js: -------------------------------------------------------------------------------- 1 | riot.tag2('rg-toasts', '
{text}
', '', '', function(opts) { 2 | opts.toasts = opts.toasts || {}; 3 | if (!Array.isArray(opts.toasts.toasts)) opts.toasts.toasts = []; 4 | this.on("mount", () => this.update()); 5 | 6 | this.toastClicked = e => { 7 | let toast = e.item; 8 | window.clearTimeout(toast.timer); 9 | toast.isvisible = false; 10 | this.trigger('select', toast); 11 | }; 12 | 13 | let _uid = 1; 14 | 15 | const uid = () => _uid++; 16 | 17 | this.on('update', () => { 18 | opts.toasts.position = opts.toasts.position || 'bottomright'; 19 | opts.toasts.toasts.forEach(toast => { 20 | if (typeof toast.isvisible == 'undefined') toast.isvisible = true; 21 | toast.id = toast.id || uid(); 22 | 23 | if (!toast.timer && !toast.sticky) { 24 | toast.startTimer = () => { 25 | toast.timer = window.setTimeout(() => { 26 | toast.isvisible = false; 27 | this.trigger('close', toast); 28 | this.update(); 29 | }, toast.timeout || 6000); 30 | }; 31 | 32 | toast.startTimer(); 33 | } 34 | }); 35 | opts.toasts.isvisible = opts.toasts.toasts.filter(toast => toast.isvisible).length > 0; 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /dist/rg-toggle/rg-toggle.js: -------------------------------------------------------------------------------- 1 | riot.tag2('rg-toggle', '
', '', '', function(opts) { 2 | opts.toggle = opts.toggle || {}; 3 | 4 | this.toggle = () => { 5 | opts.toggle.checked = !opts.toggle.checked; 6 | this.trigger('toggle', opts.toggle.checked); 7 | }; 8 | }); 9 | -------------------------------------------------------------------------------- /dist/rg-unsplash/rg-unsplash.js: -------------------------------------------------------------------------------- 1 | riot.tag2('rg-unsplash', '', '', '', function(opts) { 2 | this.on("mount", () => this.update()); 3 | this.on('update', () => { 4 | if (!opts.unsplash) opts.unsplash = {}; 5 | const { 6 | greyscale, 7 | width, 8 | height 9 | } = opts.unsplash; 10 | this.path = `${greyscale ? 'g/' : ''}${width || 450}/${height || 250}`; 11 | this.options = ''; 12 | if (opts.unsplash.random) this.options += 'random&'; 13 | if (opts.unsplash.blur) this.options += 'blur&'; 14 | if (opts.unsplash.image) this.options += 'image=' + opts.unsplash.image + '&'; 15 | if (typeof opts.unsplash.gravity !== 'undefined') this.options += 'gravity=' + opts.unsplash.gravity; 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /dist/rg.min.js: -------------------------------------------------------------------------------- 1 | riot.tag2("rg-alerts",'
{text}
',"","",function(t){this.on("mount",()=>this.update()),this.on("update",()=>{t.alerts&&t.alerts.forEach(t=>{void 0===t.isvisible&&(t.isvisible=!0),t.timeout&&(t.startTimer=(()=>{t.timer=setTimeout(()=>{this.dismiss({item:t})},t.timeout)}),t.startTimer())})}),this.dismiss=(t=>{const a=t.item;a.isvisible=!1,clearTimeout(a.timer),this.trigger("dismiss",a),this.update()}),this.select=(t=>{const a=t.item;a.onclick&&a.onclick(a),this.trigger("select",a)})}),riot.tag2("rg-bubble",'
{opts.bubble.text}
','rg-bubble .context,[data-is="rg-bubble"] .context,rg-bubble .content,[data-is="rg-bubble"] .content{ display: inline-block; position: relative; } rg-bubble .bubble,[data-is="rg-bubble"] .bubble{ position: absolute; top: -70px; left: 50%; transform: translate3d(-50%, 0, 0); }',"",function(t){this.showBubble=(()=>{clearTimeout(this._timer),this.isvisible=!0}),this.hideBubble=(()=>{this._timer=setTimeout(()=>{this.isvisible=!1,this.update()},1e3)}),this.toggleBubble=(()=>{this.isvisible=!this.isvisible})}),riot.tag2("rg-chart","",'rg-chart,[data-is="rg-chart"]{ display: inline-block; width: 100%; }',"",function(t){Chart.defaults.global.responsive=!0,this.on("mount",()=>{a()}),this.on("loaded",t=>{this.on("unmount",()=>{t.destroy()})});const a=()=>{if(!t.chart)return;let a=this.root.querySelector("canvas").getContext("2d"),e=new Chart(a),i=null;switch(t.chart.type){case"line":i=e.Line(t.chart.data,t.chart.options);break;case"radar":i=e.Radar(t.chart.data,t.chart.options);break;case"polar":i=e.PolarArea(t.chart.data,t.chart.options);break;case"pie":i=e.Pie(t.chart.data,t.chart.options);break;case"doughnut":i=e.Doughnut(t.chart.data,t.chart.options);break;default:i=e.Bar(t.chart.data,t.chart.options)}this.trigger("loaded",i)}}),riot.tag2("rg-code",'
','rg-code .editor,[data-is="rg-code"] .editor{ position: absolute; top: 0; right: 0; bottom: 0; left: 0; }',"",function(t){let a;t.editor||(t.editor={code:""});this.on("update",()=>{this.isMounted&&(a.setTheme(`ace/theme/${t.editor.theme||"monokai"}`),a.getSession().setMode(`ace/mode/${t.editor.mode||"html"}`),a.getSession().setTabSize(t.editor.tabsize||2),a.getSession().setUseSoftTabs(t.editor.softtabs),a.getSession().setUseWrapMode(t.editor.wordwrap),a.setReadOnly(t.editor.readonly),t.editor.code!=a.getValue()&&a.setValue(t.editor.code,1))}),this.on("mount",()=>{if(t.editor.code=t.editor.code||"",this.editor=a=ace.edit(this.root.querySelector(".editor")),a.$blockScrolling=1/0,t.editor.url){const a=new XMLHttpRequest;a.onload=(a=>{t.editor.code=a,this.update()}),a.open("get",t.editor.url,!0),a.send()}a.setValue(t.editor.code,1),a.getSession().on("change",e=>{t.editor.code=a.getValue(),this.trigger("onchange",a.getValue())}),this.update()})}),riot.tag2("rg-credit-card-number",'','rg-credit-card-number .card-no,[data-is="rg-credit-card-number"] .card-no{ padding-right: 60px; background-repeat: no-repeat; background-position: right center; background-size: 60px; } rg-credit-card-number .amex,[data-is="rg-credit-card-number"] .amex{ background-image: url(img/amex.png); } rg-credit-card-number .diners_club,[data-is="rg-credit-card-number"] .diners_club{ background-image: url(img/diners_club.png); } rg-credit-card-number .discover,[data-is="rg-credit-card-number"] .discover{ background-image: url(img/discover.png); } rg-credit-card-number .jcb,[data-is="rg-credit-card-number"] .jcb{ background-image: url(img/jcb.png); } rg-credit-card-number .mastercard,[data-is="rg-credit-card-number"] .mastercard{ background-image: url(img/mastercard.png); } rg-credit-card-number .visa,[data-is="rg-credit-card-number"] .visa{ background-image: url(img/visa.png); }',"",function(t){this.on("mount",()=>{this.input=this.root.querySelector("input"),this.input.value=t.card.cardnumber,this.update()}),this.oninput=(()=>{}),t.card||(t.card={cardnumber:""}),this.on("update",()=>{if(!this.isMounted)return;t.card.cardnumber=this.input.value;const a=function(t){var a,e,i,s,o,n,r;(e=[{name:"amex",icon:"images/amex.png",pattern:/^3[47]/,valid_length:[15]},{name:"diners_club",icon:"images/diners_club.png",pattern:/^30[0-5]/,valid_length:[14]},{name:"diners_club",icon:"images/diners_club.png",pattern:/^36/,valid_length:[14]},{name:"jcb",icon:"images/jcb.png",pattern:/^35(2[89]|[3-8][0-9])/,valid_length:[16]},{name:"laser",pattern:/^(6304|670[69]|6771)/,valid_length:[16,17,18,19]},{name:"visa_electron",pattern:/^(4026|417500|4508|4844|491(3|7))/,valid_length:[16]},{name:"visa",icon:"images/visa.png",pattern:/^4/,valid_length:[16]},{name:"mastercard",icon:"images/mastercard.png",pattern:/^5[1-5]/,valid_length:[16]},{name:"maestro",pattern:/^(5018|5020|5038|6304|6759|676[1-3])/,valid_length:[12,13,14,15,16,17,18,19]},{name:"discover",icon:"images/discover.png",pattern:/^(6011|622(12[6-9]|1[3-9][0-9]|[2-8][0-9]{2}|9[0-1][0-9]|92[0-5]|64[4-9])|65)/,valid_length:[16]}]).map(t=>t.name);return i=function(t){return e.find(a=>t.match(a.pattern))||null},o=function(t){var a,e,i,s,o,n;for(i=0,e=s=0,o=(n=t.split("").reverse()).length;s
{opts.date.date.format(yearFormat)}
{opts.date.date.format(monthFormat)}
Mo
Tu
We
Th
Fr
Sa
Su
','rg-date .container,[data-is="rg-date"] .container{ position: relative; display: inline-block; cursor: pointer; } rg-date .calendar,[data-is="rg-date"] .calendar{ position: absolute; min-width: 300px; margin-top: .5em; left: 0; }',"",function(t){const a=t=>(moment.isMoment(t)||(t=moment(t)),t.isValid()?t:moment()),e=t=>{this.root.contains(t.target)||this.close(),this.update()};this.dayObj=(a=>{return{date:a||moment(),selected:t.date.date.isSame(a,"day"),today:moment().isSame(a,"day"),disabled:t.date.min&&t.date.min.isAfter(a)||t.date.max&&t.date.max.isBefore(a)}});const i=()=>{this.format="LL",this.yearFormat="YYYY",this.monthFormat="MMMM",this.dayFormat="DD",this.days=[],this.startBuffer=[],this.endBuffer=[];const a=moment(t.date.date).startOf("month"),e=moment(t.date.date).daysInMonth(),i=moment(t.date.date).endOf("month");for(let t=a.isoWeekday()-1;t>0;t-=1){const e=moment(a).subtract(t,"days");this.startBuffer.push(this.dayObj(e))}for(let t=0;t{t.date||(t.date={date:moment()}),t.date.date||(t.date.date=moment()),t.date.date=a(t.date.date),t.date.min=a(t.date.min||-864e13),t.date.min.isAfter(t.date.date,"day")&&(t.date.date=moment(t.date.min)),t.date.max=a(t.date.max||864e13),t.date.max.isBefore(t.date.date,"day")&&(t.date.date=moment(t.date.max)),document.addEventListener("click",e),this.update()}),this.on("update",()=>{this.isMounted&&(t.date.date=a(t.date.date),i(),this.value=t.date.date.format(this.format))}),this.on("unmount",()=>{document.removeEventListener("click",e)}),this.open=(()=>{this.isvisible=!0,this.trigger("open")}),this.close=(()=>{this.isvisible&&(this.isvisible=!1,this.trigger("close"))}),this.select=(a=>{t.date.date=a.item.day.date,this.trigger("select",t.date.date)}),this.setToday=(()=>{t.date.date=moment(),this.trigger("select",t.date.date)}),this.prevYear=(()=>{t.date.date=t.date.date.subtract(1,"year")}),this.nextYear=(()=>{t.date.date=t.date.date.add(1,"year")}),this.prevMonth=(()=>{t.date.date=t.date.date.subtract(1,"month")}),this.nextMonth=(()=>{t.date.date=t.date.date.add(1,"month")})}),riot.tag2("rg-drawer",'

{opts.drawer.header}

',"","",function(t){t.drawer||(t.drawer={}),this.close=(()=>{t.drawer.isvisible=!1,this.trigger("close")}),this.select=(a=>{t.drawer.items.forEach(t=>t.active=!1),a.item.active=!0,this.trigger("select",a.item)})}),riot.tag2("rg-ga","","","",function(t){var a,e,i,s,o,n;a=window,e=document,i="script",s="ga",a.GoogleAnalyticsObject=s,a.ga=a.ga||function(){(a.ga.q=a.ga.q||[]).push(arguments)},a.ga.l=1*new Date,o=e.createElement(i),n=e.getElementsByTagName(i)[0],o.async=1,o.src="//www.google-analytics.com/analytics.js",n.parentNode.insertBefore(o,n),ga("create",t.property,"auto"),ga("send","pageview")}),riot.tag2("rg-iframify",'
','rg-iframify .iframify,[data-is="rg-iframify"] .iframify{ margin: 0; padding: 0; } rg-iframify iframe,[data-is="rg-iframify"] iframe{ position: relative; width: 100%; border: 0; }',"",function(t){this.on("mount",()=>{iframify(this.root.querySelector(".frame"),this.opts)})}),riot.tag2("rg-include","
{responseText}
","","",function(t){const a=()=>{const a=new XMLHttpRequest;a.onload=(e=>{t.include.unsafe?this.root.innerHTML=a.responseText:this.responseText=a.responseText,this.update(),this.trigger("loaded")}),a.open("get",t.include.url,!0),a.send(),this.trigger("loading")};this.on("mount",()=>{a()})}),riot.tag2("rg-map",'
','rg-map .rg-map,[data-is="rg-map"] .rg-map{ margin: 0; padding: 0; width: 100%; height: 100%; } rg-map .rg-map img,[data-is="rg-map"] .rg-map img{ max-width: inherit; }',"",function(t){window.rg=window.rg||{},window.rg.gmap=riot.observable({initialize:()=>{window.rg.gmap.trigger("initialize")}}),this.on("mount",()=>{if(t.map||(t.map={center:{lat:53.806,lng:-1.535},zoom:7}),rg.gmap.on("initialize",()=>{t.map.mapObj=new google.maps.Map(this.root.querySelector(".rg-map"),t.map),this.trigger("loaded",t.map.mapObj)}),!document.getElementById("gmap_script")){let t=document.createElement("script");t.setAttribute("id","gmap_script"),t.type="text/javascript",t.src="https://maps.googleapis.com/maps/api/js?callback=window.rg.gmap.initialize",document.body.appendChild(t)}})}),riot.tag2("rg-markdown","","","",function(t){this.on("mount",()=>this.update()),this.reader=new commonmark.Parser,this.writer=new commonmark.HtmlRenderer,this.on("update",()=>{if(t.markdown||(t.markdown={}),t.markdown.content)this.root.innerHTML=this.writer.render(this.reader.parse(t.markdown.content));else if(t.markdown.url){const a=new XMLHttpRequest;a.onload=(t=>{this.root.innerHTML=this.writer.render(this.reader.parse(a.responseText)),this.trigger("loaded")}),a.open("get",t.markdown.url,!0),a.send(),this.trigger("loading")}})}),riot.tag2("rg-modal",'
','rg-modal .modal--ghost .modal__footer .button,[data-is="rg-modal"] .modal--ghost .modal__footer .button{ margin: 0 .5em 0 0; }',"",function(t){t.modal||(t.modal={}),this.close=(()=>{t.modal.dismissable&&(t.modal.isvisible=!1,this.trigger("close"))})}),riot.tag2("rg-pagination",'',"","",function(t){t.pagination||(t.pagination={pages:1,page:1}),this.on("page",()=>{const t=this.root.querySelectorAll("button");for(let a=0;a{t.pagination.page++,this.trigger("page",t.pagination.page)}),this.back=(()=>{t.pagination.page--,this.trigger("page",t.pagination.page)}),this.first=(()=>{t.pagination.page=1,this.trigger("page",t.pagination.page)}),this.last=(()=>{t.pagination.page=t.pagination.pages,this.trigger("page",t.pagination.page)})}),riot.tag2("rg-phone-sim",'
','rg-phone-sim .emulator,[data-is="rg-phone-sim"] .emulator{ position: relative; width: 365px; height: 792px; background-image: url(\'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAW0AAAMYCAMAAAA3r0ZLAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAwBQTFRFMDk6+vr6KTM0lJucMz4/PklKJS8wLTg5Qk1OxsjILzo7gomJ2NvbdH5/ho2O9fb2KzY3ztHRPEdIOkVGZWxtjJSVOEJDkpeYWGRluL2+KTQ1vcHBoaWlPUZHcnp6nKKjOkRF1NfXqa2tp62tZnBxanV2VmFiZ29wVl1eaXJzbXR04uTktbq7QElK1tnZipKTi5CRTlZXpKioo6mqXmlqUVlaOEFCSVFSUFxdISssT1tcTlpbJC4vIiwtTVlaJjAxIy0uTFhZS1dYJzEyKDIzSlZXPUhJOURFO0ZHSVVWKzU2P0pLKjQ1OENEND0+QEtMLDY3SFRVN0JDQ05PLTc4ND9ANUBBQUxNNkFCR1NUMTo7RE9QLjg5N0BBR1JTRlJTLzk6RVFSMjs8RVBRRlFSNj9AMzw9SFNUMj0+IissMTs8MDo7SVRVRFBRMDs8MTw9IiwsMz0+Mjw9SlVWQ09QLjk6NT4/S1ZXND4/JC4uQU1OIy0tQk5PTFdYTVhZQExNTllaJS8vJzIyP0tMLzg5LDc4KDMzNT9AKjU1N0FCNkBBJjAwIywtMDs7Mj09NkFBJjExLjk5LDc3N0JCNUBAKjU2MTw8LDU2Ljc4OUNEKDEyQU1NPEhIPEhJO0dHOkZGND8/Qk5ORFBQQ09PLTY3OUREPkpKPkpLPUlJT1pbP0tLJTAwPUlKJzAxKjM07u/vKTIzsbW2YGprtLm50tXWPkhJo6endn+A3d/f6uvreoOEg4yN2tvc/Pz8n6am8/T0VFtcm6CgJS4v4OLi5ufnYGdncnt8dHp7gYaHJC0uu8DAjJGRQkxNxMfHKzQ1YGtsS1NUaXN0bnh5yMzMyszMy83Oy8/PdoCAKDIy7O3tT1dYuLu70NTUbXd46Onq6erreoCA2dzc8PHx8vPz5OXlnaSkn6Wmqq6ucHZ2t7y8o6eoeoSEkJaWm5+gW2ZnZG5vqa+wOEFB09bWtru7qrCwcXd4t7u83eDgzM7O7/DwNT4+7e7uwMPDwcPEeH5/////70wnUQAAAQB0Uk5T////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AFP3ByUAAA+NSURBVHja7N13nBTlGcDxEQI5AmJQBAkcnqhEDIhoWMt5iogmQbOaYNrqYrJh16gplmTVkILJpYCmF+DSE1JIcjRR7L333ntPYjQxvTl55tnr7N7t7uw+vDP3+/0x3G3hs5+vr++8M7s7eH75Xb5x+rOjN017aeq+tO++U1+atmn0s9M3Xl6BoFfm466ZOPROhIt259CJ19RS++7LdgW133a97O7aaI/a+VE0y+jRnUeF1p6wqfvvaz6+YVjT0jMyJ3rkeSdmzljaNKzh+OZuoE0TQmmvv67zLzrwmMY8wkXLNx5zYCfTdeur1p6wdeegblgKar8tbegc4lv/rirtjTMLT99/UVMKzgFLNS3avwA2c2Pl2n8tPHV1QxLJMks2rC6g/alC7ScvKozrhhyIFZRrKIzvi56sRHt94b/RIsZ1xeN7UYFuffna4/UJB68Er4rGHax648vUfmqkPnxBBrmqyixQv5FPlaP9Dz2eWdIEW9U1LdFjnQsG1n5ETz4dyowdavY+VE9XPTKQ9phddPfICjvk6lt3lruM6V97j132l26BK3S3BJAv79Gf9jN3BY85HKsadHhAedebSmtf+ofgEcOQqknDAsyLLi2pPTq4/0icatSRAefoUto7Bvc2oFSzGgLQHYtr3xTct5DVSA1XJgsD0puKaa99s9wzlwPImh5WzhXTl/5TRHt7uaN5GUI1bVmzqL64ufZfgkF/GD417rCA9e99tf8VzCPHoVPzjhPXaVv10d5bblzCyZE6nDIJ5pKde2u/Egz487Cp1zHlHr20h8otp50ETT2WgaeL7dCe2vcF/uOQqUsrA9z7emgHQ3thdEZLLpeL0kHYwq7BrdqjAv2ofEAnlU0EZaPjvTTgHdWlvXeEhnYu0VkuUoN7707tbW6X35oiciyc6C4yZxmaxPf2bTq0z5VfTo/IC8/20M5GZnAHy5JzO7Tvj85bCKlEzyIzdQdvLNxf0L4wmMQjMgnmemlHZubOBcQXqvb0CO0jk720o3OmIdhPTlft4FTrth5ju55tK8bbq/YG+emUiLzqTC/t6Lz1cYoYbwi0r47QisTz0j2w0xE6ngxWJVeLdrD+WxCZVx3J9ba0QNeAnj9T/twuOi87GcF9pLSdKM8U7Q2rV6+O0jcQMoXJJB2t96tzorzB99Y2NzfPjdQL9zLJZDJynw2YK85rvZ1ku9Cjuq+4xXknb4Js+XxU/WsQ5wnec7LlDcn6d544P+ddLFu+zlT/Vorzxd5k2fIJqfq3TJwney/Lls+RGBwniPPL3g6y5aOWBstWcd7BmypbLjhS/1LiPNWTTTMWBik02mijTWijTWijjTbFVTuZTqSTRW8OUzqJdpGyxT89mU2ELYv25kO4+LvnyUT4kmj3LV38YzjpGmin3dReIm2pF9BlU+LmMDmnrdBbUntQje0trj2o5m2FPlBiTWKQQm9R7cG03nZAexCFNtpoE9poE9poo01oo01oo01oo4021VT7MxIUBik02mijTeG1D5agMEih0UYbbUIbbUIbbbQJbbQJbbQJbbTRplppf1qCwiCFRhtttCm89lwJCoMUGm200Sa00Sa00Uab0Eab0Eab0EY73tqnS1AYpNBoo402hdc+VILCIIVGG220CW20CW200Sa00Sa00aYC9GkSFAYpNNpoo01oR0v7bRIUBik02mijTWijTWijjTahjTah7bL2hyUoDFJotNFGm9BGm0ppv0OCwiCFRhtttAlttAlttNEmtOOhfbwEhUEKjTbaaBPaaBPaLmi/T4LCIIVGG220CW20CW200ab6aS+UoDBIodFGG21CG21C2wXt4yQoDFJotNFGm9BGm9BGe7BpL5KgMEih0UYbbUIbbULbBe0PSFAYpNBoo402oY02oY32YNP+oASFQQqNNtpoE9poE9poDzbtj0hQGKTQaKONNqGNNpXS/qkEhUEKfYwEhUEKjTbaaBPaaBPaaA827Y9LUBik0GijjTahHS3tn0lQGKTQCyQoDFJotNFGm9BGm9BGG22qn/anJCgMUmi00Uabwmv/RILCIIVukKAwSKHRRhttQhttQhtttKl+2p+UoDBIodFGG20Kr/09CQqDFPo9EhQGKTTaaKNNaKNNaKONNtVP+7MSFAYpNNpoo03htY+UoDBIodFGG21CG21CG220Ce14aH9egsIghUYb7bhq/1qCwiCFPlyCwiCFRhtttAlttAlttNEmtNGmSrV/KUFhkEL/QoLCIIUeJkFhkEKjjTbahDbahDbaaBPaaFOl2r+VoDBIoX8lQWGQQh8mQWGQQqONNtqENtqENtpoE9poE9oua/9AgsIghf6+BIVBCr2tBIVBCo022mgT2mgT2mijTWijTWi7rP1DCQqDFPqtEhQGKTTaaKNNaKNNaKONNqGNNqHtsvaPJCgMUujtJCgMUmi00Uab0Eab0EYbbUIbbUIbbSpAv0WCwiCFRhtttAlttAlttNEmtNEmtF3W/rkEhUEKvVKCwiCFfrsEhUEKjTbaaBPaaBPaaKNNaKNNaLusPU6CwiCFfqcEhUEKjTbaaBPaaBPaaKNNaMdD+1sSFAYpNNqW2kslKAxSaLQttd8rQWGQQqONNtqENtqENtpoU/20vyZBYZBCo22pvUyCwiCFRttS+90SFAYpNNpoo01oo01oo4021U/72xIUBik02pbaX5KgMEih0UY7rtrvkqAwSKHRRhttQhttQhtttKl+2j+WoDBIoc+QoDBIodFGG20Kr/0aCQqDFBpttNEmtNEmtNFGm+qnfYoEhUEKjTbaaBPa0dL+kASFQQqNNtpoE9poE9ouaH9VgsIghUbbUvtUCQqDFBpttNEmtKOl/TEJCoMUGm200Sa00aZS2t+VoDBIodG21D5RgsIghUYbbbQJbbSplPZHJSgMUmi00Uab0EabSml/RYLCIIVG21L7JAkKgxQabbTRJrTRplLar5OgMEih0UYbbUIbbULbBe33S1AYpNBoo402oY02oY32YNP+hASFQQqNNtpoE9rR0v6GBIVBCo22pfaxEhQGKTTaaKNNaKNNaKM92LRfK0FhkEKjjTbahDbaVEr7aAkKgxQabbTRJrTRJrTRRpvqp/0FCQqDFBpttOOq/U0JCoMUGm1L7aMkKAxSaLTRRpvQRpvQRhttQjse2q+XoDBIodFGG21CO1ra8yUoDFJotNFGm9BGm9BGG21CG22qVPs7EhQGKTTaltpflqAwSKHRRjuu2kdIUBik0GijjTahjTahjTbahDbaVKn2GyQoDFJotNFGm8JrD5GgMEih0UYbbUIbbUIbbbQJbbQJbbSpAP1FCQqDFBpttNGm8NrzJCgMUmi00Uab0Eab0EYbbUIbbUIbbULbXvtzEhQGKTTaaMdV+xAJCoMUGm200Sa00Sa00Uab0Eab0Eab0EY73tpfl6AwSKHRttQ+SILCIIVGG220CW20CW200Sa00Sa00Sa00UabaqV9tgSFQQqNtqX2byQoDFLo4RIUBik02mijTWijTWijjTahjTahjTZFVTuVymQyqRTa9S6TzGcTnaWz+VwK7TqVyyc2L5tMoV376SOZTpQom4uO9lmS+9b5RH+lo+Ct0FHQTiYGKptCu0a7xj5zSDqdzmbTfSeWZCS0D5AiM7DT+Vyme3rJJLMRGt4K7bp2D9B8psjOs8f9GbRD7h67MUst9TLdD8mhHQq7a3bO9zNP5CIxebuvnS5v1HYvEHNoh56z8wPuAHPuz92ua+crmB+6uFNoV3depKLJuPPRabSr2kNWuOfrfHwe7eon7WTF/y9k0K52HslW/pQ02tUu/ira6SVdXnW7rJ2sav2cdnhwu6ydrnge0aN4hwe3w9q5Knd4eXcHt8Pa2SoXcxl3lyXuaqeqRss7u+Z2VztZ1azdY3C7qn2m5OhEUtUJvbSrU4lCO6kd4gRT3tVVibPamaonknDPHZzayTDj09WJW6HnSK69sHyY92HSjp7mVmgXtbNh9nRZR3eTzmqHGp55R9+gRBvtsDu6pKNLQLTRRjt687aj2kfJppW9ZN1rFeflau6adhzX2606hzTKdgXHknXvWHFu9GbJ9mjOk9S9o8V5lje2MJ84VRzPAS4X57HeaNmucXMJGKvz22vEebQ3RbbzXHtpMXzvZp44T/Huka1zl82N4fuSB4nzPd7jsnXubeAYvud+gDg/7vnjHFxwx+/zJMFye5zv+bvLn/Nde3Gx+6zUfFHeXbQnLV68+AHnXl3cPgf4gChPEu1R8qd7372O22dczxLlUaLt/1l+aHV0cMfl89utYvxvP9B+QX66zbnXF6/vJtwmxrur9vnyk4MX84/V927O1mk70H7mHMm9qSRO3ylrDYifUW3/CvlxjefqXBKH70uuEeEr/IL2pJaWFhe/DVLVd4Gd/P7eASI8qUP76YT8stzBF1nF99ydvKzAcvFNPN2h7d8sv7l44bRUxddwcPPLe8PF92a/U3uM/NayymnuKF+fZFXAO6ZL23/C0cEdj2vvBEP7Cb9be2KLozN3HK4rFczaLRN7aPuvOros8WJwzbRgQfKq31N7ROC/xs1Xu/n1ALNRuh7gkID23l7a/p5y05xjPfeHd9Sudblijsi+6PfWvjApNzr7z3pG+DquB4nrjG36aPu/d3gu8aJ7jeI1Aetefl9t/wVXF91dy+piAzzt9vW3dan9N39z7cdODdYlrS6/9shdW741WI+c+lgRbf/5FlePcfpMKtH5dxOC45qW5/1i2v7I4L42j2pVWwA60i+u7Y8N7l2HUo1aF3CO9Utpb7VbcP8QnGp3WLPbViW1/Uv2gbum2Ptc4pfW9v/ZGDxmHlahmxdANt7r96ft/0+521vhCrf0a1fs//r9a/u3zjhZumoFYmFOjlwVIM641R9I239ldvDIxcsxq7rliwPC2a/4A2v7D14bPPbkNmaTKmeRNvW79kG/HG3fn6wPP5PhXdXAPlP1JheDLartX6lPOPlsZu+KZ+z2At2Vfvna/pjdTtCYTiqcRApsV6z3K9H2/fGF553Txvgue1y3nVNAG18KtaS2P2Ja4akntDN/lzVft3d4vXGEX7m27+81q+P5N7atQrPfVrXd2GE1a69+RPvTlr3lHft11NJ+BFNKiQnkiPaWTqY7/tivZ//avn/+7P26ahl+yJD5q1a0sufUPWLrilXzhxwyvKUbaPb5A2gOpC3z956N+9HANe05YkDLgbWlh0fOQLPfZox8uBzIsrSlC6Zcj3gJ6eunXFCmYrnaQWtHTLph7EONresQlta1Nj409oZJI9ZWIPh/AQYA2whzWlA9R/cAAAAASUVORK5CYII=\'); background-repeat: no-repeat; background-position: center; background-size: cover; } rg-phone-sim .screen,[data-is="rg-phone-sim"] .screen{ position: absolute; top: 105px; left: 22px; background-color: white; width: 320px; height: 568px; border: 0; }',"",function(t){}),riot.tag2("rg-placeholdit",'',"","",function(t){t.placeholdit||(t.placeholdit={}),this.on("mount",()=>this.update()),this.on("update",()=>{t.placeholdit.width=t.placeholdit.width||450,t.placeholdit.height=t.placeholdit.height||250,t.placeholdit.background=t.placeholdit.background||"000",t.placeholdit.color=t.placeholdit.color||"fff",t.placeholdit.text=t.placeholdit.text||`${t.placeholdit.width} x ${t.placeholdit.height}`,t.placeholdit.textsize=t.placeholdit.textsize||30,t.placeholdit.format=t.placeholdit.format||"png"})}),riot.tag2("rg-raw","","","",function(t){this.on("mount",()=>this.update()),this.on("update",()=>{this.root.innerHTML=t.content||""})}),riot.tag2("rg-select",' ','rg-select .menu,[data-is="rg-select"] .menu{ position: absolute; }',"",function(t){t.select||(t.select={options:[]});const a=t=>{this.root.contains(t.target)||this.close(),this.update()};this.on("mount",()=>{document.addEventListener("click",a),this.update()}),this.on("unmount",()=>{document.removeEventListener("click",a)}),this.keydown=(t=>{const a=this.isvisible;if(this.open(),38===t.keyCode)this.navigate(-1),t.preventDefault();else if(40===t.keyCode)this.navigate(1),t.preventDefault();else if(13===t.keyCode){if(!a)return;const e=s()||this.options[0];e&&this.select({item:e}),this.close(),t.preventDefault()}else this._navigate(0)}),this.select=(a=>{a.item.text;i().value=a.item.text,this.trigger("select",a.item.text),t.onselect&&t.onselect(a.item,this),t.select.options.forEach(t=>t.selected=!1),a.item.selected=!0,this.close()}),this.navigate=(t=>{const{options:a}=this;let e=(a.findIndex(t=>t.active)+t)%a.length;e<0&&(e=a.length-1),this._navigate(e)}),this._navigate=(a=>{t.select.options.forEach(t=>t.active=!1);const e=this.options[a||0];e&&(e.active=!0)}),this.on("update",()=>{if(!this.isMounted)return;const a=e();if(this.options=t.select.options,t.select.filter&&a){const t=new RegExp(a,"i");this.options=this.options.filter(a=>a.text.match(t)),this.trigger("filter")}});const e=()=>i().value,i=()=>this.root.querySelector("input"),s=()=>this.options.find(t=>t.active);this.open=(t=>{this.isvisible=!0,this.trigger("open")}),this.close=(t=>{this.isvisible=!1,this.trigger("close")})}),riot.tag2("rg-tabs",'
{heading}
{text}
{include.responseText}
',"","",function(t){t.tabs||(t.tabs={}),this.on("mount",()=>this.update());const a=t=>{if(t.raw)return;const a=new XMLHttpRequest;a.onload=(e=>{t.raw=a.responseText,t.text=void 0,this.update(),this.trigger("loaded",t)}),a.open("get",t.include,!0),a.send(),this.trigger("loading",t)};this.open=(a=>{let e=a.item;e.disabled||e.active||(t.tabs.tabs.forEach(t=>{t.active=!1}),this.trigger("open",e),e.active=!0)}),this.on("update",()=>{Array.isArray(t.tabs.tabs)&&t.tabs.tabs.forEach(t=>{!t.disabled&&t.active&&t.include&&a(t)})})}),riot.tag2("rg-tags",'
','rg-tags .menu,[data-is="rg-tags"] .menu{ position: absolute; }',"",function(t){this.on("mount",()=>this.update()),t.tags||(t.tags={options:[],tags:[]}),t.tags.options||(t.tags.options=[]),t.tags.tags||(t.tags.tags=[]),this.select_opts=Object.assign({filter:!0},t.tags),this.select=((t,a)=>{this.addTag(t),this.trigger("select",t),this.root.querySelector("input").value="",this.update()}),this.addTag=(a=>{-1==t.tags.tags.indexOf(a)&&t.tags.tags.push(a)}),this.removeTag=(a=>{t.tags.tags=t.tags.tags.filter(t=>{if(t._id!=a.item._id)return t})}),this.on("update",()=>{t.tags.options.forEach(t=>{t._id=t._id||(Math.floor(60466175*Math.random())+1679615).toString(36)}),t.tags.tags.forEach(t=>{t._id=t._id||(Math.floor(60466175*Math.random())+1679615).toString(36)})})}),riot.tag2("rg-toasts",'
{text}
',"","",function(t){t.toasts=t.toasts||{},Array.isArray(t.toasts.toasts)||(t.toasts.toasts=[]),this.on("mount",()=>this.update()),this.toastClicked=(t=>{let a=t.item;window.clearTimeout(a.timer),a.isvisible=!1,this.trigger("select",a)});let a=1;this.on("update",()=>{t.toasts.position=t.toasts.position||"bottomright",t.toasts.toasts.forEach(t=>{void 0===t.isvisible&&(t.isvisible=!0),t.id=t.id||(()=>a++)(),t.timer||t.sticky||(t.startTimer=(()=>{t.timer=window.setTimeout(()=>{t.isvisible=!1,this.trigger("close",t),this.update()},t.timeout||6e3)}),t.startTimer())}),t.toasts.isvisible=t.toasts.toasts.filter(t=>t.isvisible).length>0})}),riot.tag2("rg-toggle",'
',"","",function(t){t.toggle=t.toggle||{},this.toggle=(()=>{t.toggle.checked=!t.toggle.checked,this.trigger("toggle",t.toggle.checked)})}),riot.tag2("rg-unsplash",'',"","",function(t){this.on("mount",()=>this.update()),this.on("update",()=>{t.unsplash||(t.unsplash={});const{greyscale:a,width:e,height:i}=t.unsplash;this.path=`${a?"g/":""}${e||450}/${i||250}`,this.options="",t.unsplash.random&&(this.options+="random&"),t.unsplash.blur&&(this.options+="blur&"),t.unsplash.image&&(this.options+="image="+t.unsplash.image+"&"),void 0!==t.unsplash.gravity&&(this.options+="gravity="+t.unsplash.gravity)})}); -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | const UNBUNDLED = { 2 | frameworks: ['mocha', 'sinon-chai'], // no riot 3 | files: [ 4 | 'node_modules/moment/min/moment.min.js', 5 | 'node_modules/commonmark/dist/commonmark.min.js', 6 | 'node_modules/chart.js/Chart.min.js', 7 | 'node_modules/ace-builds/src-min-noconflict/ace.js', 8 | 'node_modules/jquery/dist/jquery.min.js', 9 | 'node_modules/credit-card-type/dist/js/app.built.min.js', 10 | 'dependencies/js/iframify.js', 11 | `dependencies/js/riot+compiler-${process.env.RIOT_VERSION}.min.js`, 12 | 'css.js', 13 | 'demo/_charts.js', 14 | 'test-helpers.js', 15 | 'dist/rg.min.js', // use compiled RiotGear 16 | 'tags/**/*.spec.js', // no tags, only tests 17 | { pattern: 'demo/inc.html', watched: false, included: false, served: true, nocache: false } 18 | ], 19 | } 20 | 21 | module.exports = function (config) { 22 | config.set({ 23 | basePath: '', 24 | frameworks: ['mocha', 'sinon-chai', 'riot'], 25 | files: [ 26 | 'node_modules/moment/min/moment.min.js', 27 | 'node_modules/commonmark/dist/commonmark.min.js', 28 | 'node_modules/chart.js/Chart.min.js', 29 | 'node_modules/ace-builds/src-min-noconflict/ace.js', 30 | 'node_modules/jquery/dist/jquery.min.js', 31 | 'node_modules/credit-card-type/dist/js/app.built.min.js', 32 | 'dependencies/js/iframify.js', 33 | 'css.js', 34 | 'demo/_charts.js', 35 | 'test-helpers.js', 36 | 'tags/**/*', 37 | { pattern: 'demo/inc.html', watched: false, included: false, served: true, nocache: false } 38 | ], 39 | preprocessors: { 40 | 'tags/**/*.spec.js': ['babel'], 41 | 'tags/**/*.tag': ['riot', 'coverage'] 42 | }, 43 | riotPreprocessor: { 44 | options: { 45 | type: 'es6' 46 | } 47 | }, 48 | logLevel: config.LOG_ERROR, 49 | reporters: ['mocha', 'coverage'], 50 | coverageReporter: { 51 | reporters: [{ 52 | type: 'html', 53 | dir: 'coverage/' 54 | }, { 55 | type: 'text-summary' 56 | }], 57 | }, 58 | browsers: ['ChromeHeadless'], 59 | singleRun: true 60 | }) 61 | 62 | if (process.env.RIOT_VERSION) { 63 | config.set(UNBUNDLED) 64 | } 65 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "riotgear", 3 | "version": "3.6.0", 4 | "description": "The open source component library for RiotJS", 5 | "main": "dist/rg.min.js", 6 | "files": [ 7 | "dist" 8 | ], 9 | "scripts": { 10 | "preriot": "rm -rf dist", 11 | "riot": "riot tags dist --type es6", 12 | "postriot": "riot demo --type es6", 13 | "minify": "uglifyjs --output dist/rg.js dist/**/*", 14 | "uglify": "uglifyjs --compress --mangle --screw-ie8 --comment false --output dist/rg.min.js dist/**/*", 15 | "test": "karma start", 16 | "_test2": "RIOT_VERSION=2.6.9 yarn test", 17 | "_test3": "RIOT_VERSION=3.13.2 yarn test", 18 | "_test-all": "yarn test && yarn _test2 && yarn _test3", 19 | "test2": "yarn run dev && yarn _test2", 20 | "test3": "yarn run dev && yarn _test3", 21 | "dev": "npm run riot && npm run minify && npm run uglify", 22 | "build": "npm run dev && npm run _test-all", 23 | "demo": "mkdir -p _dist; cp -r demo/static/* _dist; yarn parcel serve demo/index.html --out-dir _dist" 24 | }, 25 | "repository": { 26 | "type": "git", 27 | "url": "https://github.com/RiotGear/rg.git" 28 | }, 29 | "keywords": [ 30 | "riotjs", 31 | "riot", 32 | "webcomponents", 33 | "html5", 34 | "es6", 35 | "javascript", 36 | "tags", 37 | "components", 38 | "riotgear" 39 | ], 40 | "author": "Gregory Pratt", 41 | "license": "MIT", 42 | "bugs": { 43 | "url": "https://github.com/RiotGear/rg/issues" 44 | }, 45 | "homepage": "https://riotgear.js.org/", 46 | "devDependencies": { 47 | "@babel/core": "^7.5.5", 48 | "@babel/preset-env": "^7.5.5", 49 | "ace-builds": "^1.2.2", 50 | "chai": "^4.2.0", 51 | "chart.js": "1.0.2", 52 | "commonmark": "^0.29.0", 53 | "jquery": "^3.4.1", 54 | "karma": "^4.2.0", 55 | "karma-babel-preprocessor": "^8.0.1", 56 | "karma-chrome-launcher": "^3.0.0", 57 | "karma-coverage": "^1.1.2", 58 | "karma-mocha": "^1.3.0", 59 | "karma-mocha-reporter": "^2.2.5", 60 | "karma-riot": "^2.0.0", 61 | "karma-sinon-chai": "^2.0.2", 62 | "mocha": "^6.2.0", 63 | "mocha-snapshot": "^1.0.0", 64 | "moment": "^2.24.0", 65 | "normalize.css": "^8.0.1", 66 | "parcel": "^1.12.3", 67 | "parcel-plugin-riot": "^2.1.0", 68 | "puppeteer": "^1.19.0", 69 | "riot": "3.13.2", 70 | "sinon": "^7.3.2", 71 | "sinon-chai": "2.8.0", 72 | "uglify-es": "^3.3.9" 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /tags/rg-alerts/rg-alerts.blank.spec.js: -------------------------------------------------------------------------------- 1 | describe('rg-alerts blank', function() { 2 | let tag 3 | 4 | beforeEach(function() { 5 | 6 | $('body').append('') 7 | tag = riot.mount('rg-alerts')[0] 8 | }) 9 | 10 | after(function() { 11 | tag.unmount() 12 | }) 13 | 14 | it('is mounted', function() { 15 | tag.isMounted.should.be.true 16 | }) 17 | }) 18 | -------------------------------------------------------------------------------- /tags/rg-alerts/rg-alerts.spec.js: -------------------------------------------------------------------------------- 1 | describe('rg-alerts', function () { 2 | let tag, oncloseSpy, onclickSpy 3 | const seconds = 500 4 | 5 | beforeEach(function () { 6 | oncloseSpy = sinon.spy() 7 | onclickSpy = sinon.spy() 8 | $('body').append('') 9 | let alerts = [{ 10 | type: 'error', 11 | content: 'Error! Something bad happened.', 12 | onclick: onclickSpy, 13 | dismissable: true 14 | }, { 15 | type: 'secondary', 16 | content: 'Warning! Something sort of bad happened.', 17 | dismissable: false 18 | }, { 19 | type: 'primary', 20 | content: 'Look! Something you should know about.', 21 | timeout: seconds 22 | }, { 23 | type: 'success', 24 | content: 'Success! Well done.', 25 | timeout: seconds 26 | }] 27 | 28 | tag = riot.mount('rg-alerts', { 29 | alerts 30 | })[0] 31 | 32 | tag.on('dismiss', oncloseSpy) 33 | }) 34 | 35 | afterEach(function () { 36 | tag.unmount() 37 | }) 38 | 39 | it('is mounted', function () { 40 | tag.isMounted.should.be.true 41 | }) 42 | 43 | it('displays correct number of alerts', function () { 44 | $('rg-alerts .alerts__alert').length.should.equal(4) 45 | }) 46 | 47 | it('displays correct type of alerts', function () { 48 | $('rg-alerts .alerts__alert:nth-child(1)').is('.alerts__alert--error').should.be.true 49 | $('rg-alerts .alerts__alert:nth-child(2)').is('.alerts__alert--secondary').should.be.true 50 | $('rg-alerts .alerts__alert:nth-child(3)').is('.alerts__alert--primary').should.be.true 51 | $('rg-alerts .alerts__alert:nth-child(4)').is('.alerts__alert--success').should.be.true 52 | }) 53 | 54 | it('can not be dismissed if set', function () { 55 | $('rg-alerts .alerts__alert:nth-child(2)').find('.button--close').length.should.equal(0) 56 | }) 57 | 58 | it('can be dismissed', function () { 59 | $('rg-alerts .alerts__alert:nth-child(3)').find('.button--close').click() 60 | $('rg-alerts .alerts__alert').length.should.equal(3) 61 | oncloseSpy.should.have.been.called 62 | }) 63 | 64 | it('calls the onclose function when dismissed', function () { 65 | $('rg-alerts .alerts__alert:nth-child(1)').find('.button--close').click() 66 | oncloseSpy.should.have.been.called 67 | onclickSpy.should.have.been.called 68 | }) 69 | 70 | it('disappears after timer runs down', function (done) { 71 | setTimeout(function () { 72 | $('rg-alerts .alerts__alert').length.should.equal(2) 73 | done() 74 | }, seconds) 75 | }) 76 | 77 | it('calls the onclose function when automatically dismissed', function (done) { 78 | setTimeout(function () { 79 | oncloseSpy.should.have.been.called 80 | done() 81 | }, seconds) 82 | }) 83 | }) 84 | 85 | describe('rg-alerts no opts', function () { 86 | let tag 87 | 88 | beforeEach(function () { 89 | 90 | $('body').append('') 91 | tag = riot.mount('rg-alerts')[0] 92 | }) 93 | 94 | after(function () { 95 | tag.unmount() 96 | }) 97 | 98 | it('is mounted', function () { 99 | tag.isMounted.should.be.true 100 | }) 101 | }) 102 | -------------------------------------------------------------------------------- /tags/rg-alerts/rg-alerts.tag: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |
5 | 8 | { text } 9 |
10 |
11 | 12 | 46 |
47 | -------------------------------------------------------------------------------- /tags/rg-audio/rg-audio.tag: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 |
-------------------------------------------------------------------------------- /tags/rg-bubble/rg-bubble.spec.js: -------------------------------------------------------------------------------- 1 | describe('rg-bubble', function() { 2 | let tag, bubble 3 | const text = 'This is a bubble' 4 | 5 | beforeEach(function() { 6 | $('body').append(``) 7 | tag = riot.mount('rg-bubble', { 8 | bubble: { 9 | text 10 | } 11 | })[0] 12 | }) 13 | 14 | afterEach(function () { 15 | tag.unmount() 16 | }) 17 | 18 | it('is mounted', function() { 19 | tag.isMounted.should.be.true 20 | }) 21 | 22 | describe('displays tooltip with correct text', function() { 23 | it('on click', function() { 24 | $('rg-bubble .content').trigger('click') 25 | $('rg-bubble .bubble').length.should.equal(1) 26 | $('rg-bubble .bubble').html().should.contain(text) 27 | }) 28 | 29 | it('on mouse over', function() { 30 | $('rg-bubble .content')[0].dispatchEvent(new Event("mouseover")) 31 | $('rg-bubble .bubble').length.should.equal(1) 32 | $('rg-bubble .bubble').html().should.contain(text) 33 | }) 34 | }) 35 | 36 | describe('hides tooltip', function() { 37 | beforeEach(function() { 38 | $('rg-bubble .content').trigger('click') 39 | }) 40 | 41 | it('on click', function() { 42 | $('rg-bubble .content').trigger('click') 43 | $('rg-bubble .bubble').length.should.equal(0) 44 | }) 45 | 46 | describe('after 1 second', function() { 47 | it('on mouse out', function(done) { 48 | $('rg-bubble .content')[0].dispatchEvent(new Event("mouseout")) 49 | setTimeout(function() { 50 | $('rg-bubble .bubble').length.should.equal(0) 51 | done() 52 | }, 1000) 53 | }) 54 | }) 55 | }) 56 | }) 57 | 58 | describe('rg-bubble no opts', function() { 59 | let tag 60 | 61 | beforeEach(function() { 62 | 63 | $('body').append('') 64 | tag = riot.mount('rg-bubble')[0] 65 | }) 66 | 67 | after(function() { 68 | tag.unmount() 69 | }) 70 | 71 | it('is mounted', function() { 72 | tag.isMounted.should.be.true 73 | }) 74 | }) 75 | -------------------------------------------------------------------------------- /tags/rg-bubble/rg-bubble.tag: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |
5 | { opts.bubble.text } 6 |
7 |
8 | 9 |
10 |
11 | 12 | 29 | 30 | 44 |
45 | -------------------------------------------------------------------------------- /tags/rg-chart/rg-chart.spec.js: -------------------------------------------------------------------------------- 1 | // not the most thorough test. It only verifies that the charts in the demo don't throw errors 2 | 3 | describe('rg-chart', function () { 4 | $('body').append('') 5 | it('is mounted', function () { 6 | const tag2 = newTag("rg-chart") 7 | tag2.isMounted.should.be.true 8 | }) 9 | 10 | Object.keys(window._charts).forEach( key => { 11 | it('is mounted: '+key, function () { 12 | const tag = riot.mount("rg-chart", { chart: window._charts[key] })[0] 13 | tag.isMounted.should.be.true 14 | }) 15 | }) 16 | }) -------------------------------------------------------------------------------- /tags/rg-chart/rg-chart.tag: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 48 | 49 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /tags/rg-code/rg-code.spec.js: -------------------------------------------------------------------------------- 1 | describe('rg-code', function() { 2 | let tag, spy, editor 3 | 4 | const getOpts = extra => { 5 | const _default = { 6 | theme: 'monokai', 7 | mode: 'javascript', 8 | tabsize: '2', 9 | softtabs: 'true', 10 | wordwrap: 'true', 11 | readonly: 'true', 12 | onchange: spy 13 | } 14 | return Object.assign(_default, extra) 15 | } 16 | 17 | beforeEach(function() { 18 | spy = sinon.spy() 19 | }) 20 | 21 | afterEach(function() { 22 | tag.unmount() 23 | }) 24 | 25 | it('allows code for opts', function() { 26 | tag = newTag('rg-code', { 27 | editor: getOpts({ code: '

Hello world!

' }) 28 | }) 29 | tag.isMounted.should.be.true 30 | spy.should.not.have.been.called 31 | }) 32 | 33 | it('allows url for opts', function(done) { 34 | mockAjax() 35 | tag = newTag('rg-code', { 36 | editor: getOpts({ url: 'yay.html' }) 37 | }) 38 | tag.isMounted.should.be.true 39 | setTimeout(() => { 40 | // gotta kick this into another thread to catch the faked ajax 41 | tag.root.innerText.should.equal('1\nYay!') 42 | unmockAjax() 43 | done() 44 | },0) 45 | }) 46 | }) 47 | 48 | describe('rg-code no opts', function() { 49 | let tag 50 | 51 | beforeEach(function() { 52 | $('body').append('') 53 | tag = riot.mount('rg-code')[0] 54 | }) 55 | 56 | afterEach(function() { 57 | tag.unmount() 58 | }) 59 | 60 | it('is mounted', function() { 61 | tag.isMounted.should.be.true 62 | }) 63 | }) 64 | -------------------------------------------------------------------------------- /tags/rg-code/rg-code.tag: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 50 | 51 | 61 |
62 | -------------------------------------------------------------------------------- /tags/rg-credit-card/rg-credit-card-number.tag: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 145 | 146 | 179 | 180 | 181 | -------------------------------------------------------------------------------- /tags/rg-credit-card/rg-credit-card.spec.js: -------------------------------------------------------------------------------- 1 | // NOTE: No need to test the validator, its already done 2 | // https://github.com/PawelDecowski/jquery-creditcardvalidator 3 | 4 | describe('rg-credit-card-number', function () { 5 | let tag, cardNoVisa, cardNoMaestro, placeholder, card 6 | cardNoVisa = '4000 0000 0000 0002' 7 | cardNoMaestro = '5018 0000 0009' 8 | placeholder = '0123 4567 8910 1112' 9 | 10 | beforeEach(function () { 11 | card = { 12 | placeholder: placeholder, 13 | cardnumber: cardNoVisa 14 | } 15 | 16 | $('body').append('') 17 | tag = riot.mount('rg-credit-card-number', { 18 | card 19 | })[0] 20 | }) 21 | 22 | afterEach(function () { 23 | tag.unmount() 24 | }) 25 | 26 | it('is mounted', function () { 27 | tag.isMounted.should.be.true 28 | }) 29 | 30 | it('populates textbox with provided value', function () { 31 | const textbox = $('rg-credit-card-number .card-no') 32 | textbox.val().should.equal(cardNoVisa) 33 | }) 34 | 35 | it('sets the placeholder text correctly', function () { 36 | const textbox = $('rg-credit-card-number .card-no') 37 | textbox.attr('placeholder').should.equal(placeholder) 38 | }) 39 | 40 | it('sets validation result', function () { 41 | card.valid.should.be.true 42 | }) 43 | 44 | it('sets validation result on input', function () { 45 | $('rg-credit-card-number .card-no').val(cardNoMaestro).trigger('input') 46 | card.valid.should.be.true 47 | }) 48 | 49 | describe('sets validation css classes', function () { 50 | it('for the icon', function () { 51 | const textbox = $('rg-credit-card-number .card-no') 52 | textbox.val(cardNoMaestro) 53 | tag.update() 54 | textbox.hasClass('maestro').should.be.true 55 | textbox.val(cardNoVisa) 56 | tag.update() 57 | textbox.hasClass('visa').should.be.true 58 | }) 59 | 60 | it('for a valid number', function () { 61 | const textbox = $('rg-credit-card-number .card-no') 62 | textbox.val(cardNoVisa).trigger('input') 63 | textbox.hasClass('field--success').should.be.true 64 | }) 65 | }) 66 | 67 | it('has no icon for invalid number', function () { 68 | const textbox = $('rg-credit-card-number .card-no') 69 | textbox.hasClass('visa').should.be.true 70 | textbox.val('moekoaersntoeanrstoen') 71 | tag.update() 72 | textbox.trigger("input") 73 | textbox.hasClass('visa').should.be.false 74 | }) 75 | }) 76 | 77 | describe('rg-credit-card-number no opts', function () { 78 | let tag 79 | 80 | beforeEach(function () { 81 | $('body').append('') 82 | tag = riot.mount('rg-credit-card-number')[0] 83 | }) 84 | 85 | afterEach(function () { 86 | tag.unmount() 87 | }) 88 | 89 | it('is mounted', function () { 90 | tag.isMounted.should.be.true 91 | }) 92 | 93 | it('is blank when no cardNo is specified', function () { 94 | const textbox = $('rg-credit-card-number .card-no') 95 | textbox.val().should.equal('') 96 | }) 97 | }) 98 | -------------------------------------------------------------------------------- /tags/rg-date/rg-date.spec.js: -------------------------------------------------------------------------------- 1 | describe('rg-date', function () { 2 | let tag 3 | const DATE = "YYYY-MM-DD" 4 | 5 | afterEach(function() { 6 | tag.unmount() 7 | window.BEES = false 8 | }) 9 | 10 | it('no opts', function () { 11 | tag = newTag('rg-date') 12 | tag.isMounted.should.be.true 13 | 14 | const dayObj = tag.dayObj() 15 | dayObj.today.should.be.true 16 | dayObj.selected.should.be.true 17 | should.equal(dayObj.disabled || false, false) 18 | }) 19 | 20 | it('June 20th, 1999', function() { 21 | tag = newTag('rg-date', { 22 | date: { 23 | date: '1999-06-20', 24 | min: '1999-01-01', 25 | max: '1999-12-31', 26 | } 27 | }) 28 | 29 | const dayObj = tag.dayObj() 30 | dayObj.today.should.be.true 31 | dayObj.selected.should.be.false 32 | dayObj.disabled.should.be.true // note: this test will fail if run in 1999 33 | 34 | const day2 = tag.dayObj('1999-06-20') 35 | day2.selected.should.be.true 36 | day2.disabled.should.be.false 37 | tag.dayObj('1998-12-31').disabled.should.be.true 38 | tag.dayObj('2000-01-01').disabled.should.be.true 39 | }) 40 | 41 | it('detect triggers', function() { 42 | tag = newTag('rg-date', { date: { date: '1999-06-20'}}) 43 | const validate = mySpy(tag, ['open','close','select']) 44 | tag.root.querySelector('input').click() 45 | validate({ open: 1}) 46 | tag.root.querySelector(".calendar__date:nth-child(30)").click() 47 | validate({ select: 1, close: 1}) 48 | 49 | // calling close again doesn't retrigger close event 50 | tag.close() 51 | validate() 52 | }) 53 | 54 | it('other functions', function() { 55 | tag = newTag('rg-date', { date: { date: "1999-06-20" } }) 56 | tag.prevYear() 57 | tag.opts.date.date.format(DATE).should.equal("1998-06-20") 58 | tag.nextYear() 59 | tag.opts.date.date.format(DATE).should.equal("1999-06-20") 60 | tag.prevMonth() 61 | tag.opts.date.date.format(DATE).should.equal("1999-05-20") 62 | tag.nextMonth() 63 | tag.opts.date.date.format(DATE).should.equal("1999-06-20") 64 | tag.setToday() 65 | tag.opts.date.date.format(DATE).should.equal(moment().format(DATE)) 66 | }) 67 | 68 | it('works with random defaults', function() { 69 | const today = moment().format(DATE) 70 | const ogwarn = console.warn 71 | console.warn = () => {} //suppress annoying moment output over the following diaster 72 | tag = newTag('rg-date', { date: { date: 'bees!' }}) 73 | tag.opts.date.date.format(DATE).should.equal(today) 74 | console.warn = ogwarn 75 | tag.unmount() 76 | 77 | // no day (like today!) 78 | tag = newTag('rg-date', { date: { }}) 79 | tag.opts.date.date.format(DATE).should.equal(today) 80 | tag.unmount() 81 | 82 | // date after max, will fail after the year 9000 83 | tag = newTag('rg-date', { date: { date: "9000-01-01", max: today }}) 84 | tag.opts.date.date.format(DATE).should.equal(today) 85 | tag.unmount() 86 | 87 | // date before min, will fail before the year 1999 88 | tag = newTag('rg-date', { date: { date: "1999-01-01", min: today }}) 89 | tag.opts.date.date.format(DATE).should.equal(today) 90 | tag.unmount() 91 | }) 92 | }) 93 | -------------------------------------------------------------------------------- /tags/rg-date/rg-date.tag: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 |
7 | 8 |
{ opts.date.date.format(yearFormat) }
9 | 10 | 11 | 12 |
{ opts.date.date.format(monthFormat) }
13 | 14 | 15 |
Mo
16 |
Tu
17 |
We
18 |
Th
19 |
Fr
20 |
Sa
21 |
Su
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 |
30 | 31 | 158 | 159 | 174 | 175 |
176 | -------------------------------------------------------------------------------- /tags/rg-drawer/rg-drawer.spec.js: -------------------------------------------------------------------------------- 1 | describe('rg-drawer', function () { 2 | let tag, drawer 3 | let onClickSpy = sinon.spy() 4 | let onCloseSpy = sinon.spy() 5 | 6 | beforeEach(function () { 7 | $('body').append('') 8 | drawer = { 9 | header: 'Side Menu', 10 | isvisible: true, 11 | items: [{ 12 | text: 'Item 1' 13 | }, { 14 | text: 'Item 2' 15 | }] 16 | } 17 | 18 | tag = riot.mount('rg-drawer', { 19 | drawer 20 | })[0] 21 | 22 | tag.on('select', onClickSpy) 23 | .on('close', onCloseSpy) 24 | }) 25 | 26 | afterEach(function () { 27 | tag.unmount() 28 | }) 29 | 30 | it('is mounted', function () { 31 | tag.isMounted.should.be.true 32 | const tag2 = newTag("rg-drawer") 33 | tag2.isMounted.should.be.true 34 | tag2.unmount() 35 | }) 36 | 37 | it('has an overlay', function () { 38 | $('rg-drawer .overlay').length.should.equal(1) 39 | $('rg-drawer .drawer').is('.drawer--visible').should.be.true 40 | }) 41 | 42 | it('header is set correctly', function () { 43 | $('rg-drawer .heading').text().should.contain('Side Menu') 44 | }) 45 | 46 | it('has items', function () { 47 | $('rg-drawer .menu__item').length.should.equal(2) 48 | $('rg-drawer .menu__item:nth-child(1)').text().should.contain('Item 1') 49 | $('rg-drawer .menu__item:nth-child(2)').text().should.contain('Item 2') 50 | }) 51 | 52 | it('clicking an item activates it', function () { 53 | $('rg-drawer .menu__item:nth-child(1)').is('.menu__item--active').should.be.false 54 | $('rg-drawer .menu__item:nth-child(2)').is('.menu__item--active').should.be.false 55 | $('rg-drawer .menu__item:nth-child(1)').click() 56 | $('rg-drawer .menu__item:nth-child(1)').is('.menu__item--active').should.be.true 57 | $('rg-drawer .menu__item:nth-child(2)').is('.menu__item--active').should.be.false 58 | $('rg-drawer .menu__item:nth-child(2)').click() 59 | $('rg-drawer .menu__item:nth-child(1)').is('.menu__item--active').should.be.false 60 | $('rg-drawer .menu__item:nth-child(2)').is('.menu__item--active').should.be.true 61 | }) 62 | 63 | it('clicking overlay closes draw', function () { 64 | $('rg-drawer .overlay').click() 65 | $('rg-drawer .overlay').length.should.equal(0) 66 | $('rg-drawer .drawer').is('.drawer--visible').should.be.false 67 | }) 68 | }) 69 | -------------------------------------------------------------------------------- /tags/rg-drawer/rg-drawer.tag: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |
6 |

{ opts.drawer.header }

7 | 8 | 13 | 14 |
15 | 16 |
17 |
18 | 19 | 34 | 35 |
36 | -------------------------------------------------------------------------------- /tags/rg-ga/rg-ga.spec.js: -------------------------------------------------------------------------------- 1 | describe('rg-ga', function() { 2 | let tag 3 | 4 | beforeEach(function() { 5 | window.ga = sinon.spy() 6 | $('body').append('') 7 | tag = riot.mount('rg-ga')[0] 8 | }) 9 | 10 | afterEach(function() { 11 | tag.unmount() 12 | }) 13 | 14 | it('is mounted', function() { 15 | tag.isMounted.should.be.true 16 | }) 17 | 18 | it('ga should have been called twice', function () { 19 | window.ga.should.have.been.calledTwice 20 | window.ga.should.have.been.calledWith('create', 'a1b2c3d4', 'auto') 21 | window.ga.should.have.been.calledWith('send', 'pageview') 22 | }) 23 | }) 24 | -------------------------------------------------------------------------------- /tags/rg-ga/rg-ga.tag: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /tags/rg-iframify/rg-iframify.spec.js: -------------------------------------------------------------------------------- 1 | describe('rg-iframify', function () { 2 | it('mounts', function() { 3 | const tag = newTag('rg-iframify') 4 | tag.isMounted.should.be.true 5 | }) 6 | }) -------------------------------------------------------------------------------- /tags/rg-iframify/rg-iframify.tag: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |
5 | 6 |
7 |
8 | 9 | 14 | 15 | 27 | 28 |
29 | -------------------------------------------------------------------------------- /tags/rg-include/rg-include.spec.js: -------------------------------------------------------------------------------- 1 | describe('rg-include', function() { 2 | let tag, include 3 | 4 | beforeEach(function() { 5 | include = { 6 | url: 'inc.html' 7 | } 8 | 9 | $('body').append('') 10 | tag = riot.mount('rg-include', { 11 | include 12 | })[0] 13 | }) 14 | 15 | afterEach(function() { 16 | tag.unmount() 17 | }) 18 | 19 | it('is mounted', function() { 20 | tag.isMounted.should.be.true 21 | }) 22 | 23 | it('handles unsafe', function(done) { 24 | setTimeout(function () { 25 | tag.responseText.should.equal('NOT FOUND') 26 | done() 27 | }, 1000) 28 | }) 29 | }) 30 | 31 | describe('rg-include unsafe', function() { 32 | let tag, include 33 | 34 | beforeEach(function() { 35 | include = { 36 | url: 'inc.html', 37 | unsafe: true 38 | } 39 | 40 | $('body').append('') 41 | tag = riot.mount('rg-include', { 42 | include 43 | })[0] 44 | }) 45 | 46 | afterEach(function() { 47 | tag.unmount() 48 | }) 49 | 50 | it('is mounted', function() { 51 | tag.isMounted.should.be.true 52 | }) 53 | 54 | it('handles unsafe', function(done) { 55 | setTimeout(function () { 56 | tag.root.innerHTML.should.equal('NOT FOUND') 57 | expect(tag.responseText).to.not.exist 58 | done() 59 | }, 1000) 60 | }) 61 | }) 62 | -------------------------------------------------------------------------------- /tags/rg-include/rg-include.tag: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | { responseText } 5 |
6 | 7 | 25 | 26 |
27 | -------------------------------------------------------------------------------- /tags/rg-map/rg-map.spec.js: -------------------------------------------------------------------------------- 1 | describe('rg-map', function () { 2 | let tag 3 | 4 | afterEach(function () { 5 | tag.unmount() 6 | }) 7 | 8 | it('is mounted', function () { 9 | $('body').append('') 10 | tag = riot.mount('rg-map')[0] 11 | tag.isMounted.should.be.true 12 | const tag2 = newTag('rg-map', { map: {}}) 13 | tag2.isMounted.should.be.true 14 | tag2.unmount() 15 | }) 16 | 17 | it('doesnt add map script tag twice', function () { 18 | $('body').append('') 19 | $('body').append('') 20 | tag = riot.mount('rg-map')[0] 21 | $('#gmap_script').length.should.equal(1) 22 | }) 23 | }) 24 | -------------------------------------------------------------------------------- /tags/rg-map/rg-map.tag: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 38 | 39 | 52 | 53 |
54 | -------------------------------------------------------------------------------- /tags/rg-markdown/rg-markdown.spec.js: -------------------------------------------------------------------------------- 1 | describe('rg-markdown', function() { 2 | let tag, markdown 3 | let spy = sinon.spy() 4 | 5 | afterEach(function() { 6 | tag.unmount() 7 | }) 8 | 9 | it('is mounted', function() { 10 | tag = newTag('rg-markdown') 11 | tag.isMounted.should.be.true 12 | }) 13 | 14 | it('renders HTML', function () { 15 | tag = newTag('rg-markdown', { 16 | markdown: { content: '**Some** other content' } 17 | }) 18 | $('rg-markdown').html().should.contain('

Some other content

') 19 | }) 20 | 21 | it('renders url', function (done) { 22 | mockAjax() 23 | tag = newTag('rg-markdown') 24 | tag.opts.markdown.url = 'yay.html' 25 | tag.on('loaded', () => { 26 | $('rg-markdown').html().should.contain("

Yay!

") 27 | unmockAjax() 28 | done() 29 | }) 30 | tag.update() 31 | }) 32 | }) 33 | -------------------------------------------------------------------------------- /tags/rg-markdown/rg-markdown.tag: -------------------------------------------------------------------------------- 1 | 2 | 3 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /tags/rg-modal/rg-modal.spec.js: -------------------------------------------------------------------------------- 1 | describe('rg-modal', function() { 2 | let tag 3 | let spyOnClose = sinon.spy() 4 | let spyOnClick = sinon.spy() 5 | let modal = { 6 | heading: 'Modal heading', 7 | isvisible: true, 8 | ghost: true, 9 | dismissable: false, 10 | buttons: [{ 11 | action: spyOnClick, 12 | text: 'Save' 13 | }, { 14 | text: 'Cancel', 15 | style: 'color: cornflowerblue;' 16 | }] 17 | } 18 | 19 | beforeEach(function() { 20 | $('body').append('This is the body') 21 | tag = riot.mount('rg-modal', { modal: deepClone(modal) })[0] 22 | tag.on('close', spyOnClose) 23 | }) 24 | 25 | afterEach(function() { 26 | spyOnClick.resetHistory() 27 | spyOnClose.resetHistory() 28 | tag.unmount() 29 | }) 30 | 31 | it('is mounted', function() { 32 | tag.isMounted.should.be.true 33 | }) 34 | 35 | it('has correct heading', function() { 36 | $('rg-modal .heading').text().should.equal(modal.heading) 37 | }) 38 | 39 | it('has the correct body', function() { 40 | $('rg-modal .modal__body').html().should.contain('This is the body') 41 | }) 42 | 43 | it('can be a ghost modal', function() { 44 | $('rg-modal .modal').is('.modal--ghost').should.be.true 45 | }) 46 | 47 | it('close button can be turned off', function() { 48 | $('rg-modal .button--close').length.should.equal(0) 49 | }) 50 | 51 | it('has a footer with two buttons', function() { 52 | $('rg-modal .modal__footer button').length.should.equal(2) 53 | $('rg-modal .modal__footer button:nth-child(1)').text().should.contain(modal.buttons[0].text) 54 | $('rg-modal .modal__footer button:nth-child(2)').text().should.contain(modal.buttons[1].text) 55 | }) 56 | 57 | it('buttons can be styled', function() { 58 | $('rg-modal .modal__footer button:nth-child(2)').css('color').should.equal('rgb(100, 149, 237)') 59 | }) 60 | 61 | it('calls the action on button click', function() { 62 | $('rg-modal .modal__footer button:nth-child(1)').click() 63 | spyOnClick.should.have.been.calledOnce 64 | }) 65 | 66 | it('click the close button calls the onclose callback', function() { 67 | const _modal = deepClone(modal) 68 | _modal.dismissable = true 69 | tag = newTag("rg-modal",{ modal: _modal }) 70 | tag.on('close', spyOnClose) 71 | tag.$('.button--close').click() 72 | tag.$$('.modal').length.should.equal(0) 73 | spyOnClose.should.have.been.calledOnce 74 | }) 75 | 76 | it('is indismissible when indisimissible', function() { 77 | tag.close() 78 | spyOnClose.callCount.should.equal(0) 79 | }) 80 | 81 | it('works with no opts', function() { 82 | newTag("rg-modal") 83 | }) 84 | }) 85 | -------------------------------------------------------------------------------- /tags/rg-modal/rg-modal.tag: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 22 | 23 | 34 | 35 | 41 | 42 |
43 | -------------------------------------------------------------------------------- /tags/rg-pagination/rg-pagination.spec.js: -------------------------------------------------------------------------------- 1 | describe('rg-pagination', function() { 2 | let tag 3 | let spyOnPageChange = sinon.spy() 4 | let pagination = { 5 | pages: 100, 6 | page: 3 7 | } 8 | 9 | beforeEach(function() { 10 | $('body').append(' { 28 | tag.root.querySelector('.pagination__page--current').innerText.should.equal(i) 29 | } 30 | const getNavButtons = () => tag.root.querySelectorAll(".pagination__control") 31 | assertCurrent('3') 32 | getNavButtons()[1].click() // back one 33 | assertCurrent('2') 34 | getNavButtons()[2].click() // forward one 35 | assertCurrent('3') 36 | getNavButtons()[0].click() // start 37 | assertCurrent('1') 38 | getNavButtons()[3].click() // end 39 | assertCurrent('100') 40 | }) 41 | }) 42 | -------------------------------------------------------------------------------- /tags/rg-pagination/rg-pagination.tag: -------------------------------------------------------------------------------- 1 | 2 | 3 | 20 | 21 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /tags/rg-phone-sim/rg-phone-sim.spec.js: -------------------------------------------------------------------------------- 1 | describe('rg-phone-sim', function() { 2 | let tag, phonesim 3 | 4 | beforeEach(function() { 5 | $('body').append('') 6 | tag = riot.mount('rg-phone-sim', { 7 | phonesim: { 8 | url: 'http://riotjs.com/' 9 | } 10 | })[0] 11 | }) 12 | 13 | afterEach(function() { 14 | tag.unmount() 15 | }) 16 | 17 | it('is mounted', function() { 18 | tag.isMounted.should.be.true 19 | }) 20 | 21 | it('has an iframe in an emulator', function() { 22 | $('rg-phone-sim .emulator iframe').length.should.be.equal(1) 23 | }) 24 | 25 | it('iframe is pointed to url attribute', function() { 26 | $('rg-phone-sim iframe').attr('src').should.equal('http://riotjs.com/') 27 | }) 28 | }) 29 | -------------------------------------------------------------------------------- /tags/rg-phone-sim/rg-phone-sim.tag: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |
6 | 7 | 28 | 29 |
30 | -------------------------------------------------------------------------------- /tags/rg-placeholdit/rg-placeholdit.spec.js: -------------------------------------------------------------------------------- 1 | describe('rg-placeholdit', function() { 2 | let tag, placeholdit 3 | 4 | beforeEach(function() { 5 | $('body').append('') 6 | tag = riot.mount('rg-placeholdit')[0] 7 | }) 8 | 9 | afterEach(function() { 10 | tag.unmount() 11 | }) 12 | 13 | it('is mounted', function() { 14 | tag.isMounted.should.be.true 15 | }) 16 | 17 | it('has an img tag', function() { 18 | $('rg-placeholdit img').length.should.equal(1) 19 | }) 20 | 21 | it('defaults options', function () { 22 | $('rg-placeholdit img').attr('src').should.equal('https://placeholdit.imgix.net/~text?bg=000&txtclr=fff&txt=450 x 250&txtsize=30&w=450&h=250&fm=png') 23 | }) 24 | 25 | it('also alows specified options', function() { 26 | const tag2 = newTag("rg-placeholdit",{ 27 | placeholdit: { 28 | width: 50, 29 | height: 60, 30 | background: "pink", 31 | color: "blue", 32 | text: "BOATS!", 33 | textsize: 35, 34 | format: "jpg", 35 | }, 36 | }) 37 | tag2.$('img').src.should.equal('https://placeholdit.imgix.net/~text?bg=pink&txtclr=blue&txt=BOATS!&txtsize=35&w=50&h=60&fm=jpg') 38 | }) 39 | }) 40 | -------------------------------------------------------------------------------- /tags/rg-placeholdit/rg-placeholdit.tag: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /tags/rg-raw/rg-raw.spec.js: -------------------------------------------------------------------------------- 1 | describe('rg-raw', function() { 2 | it('is mounted', function() { 3 | const tag = newTag('rg-raw', {}) 4 | tag.isMounted.should.be.true 5 | }) 6 | 7 | it('contains the supplied html', function() { 8 | const tag = newTag('rg-raw', { content: 'Hello there' }) 9 | tag.root.innerHTML.should.be.equal('Hello there') 10 | }) 11 | }) 12 | -------------------------------------------------------------------------------- /tags/rg-raw/rg-raw.tag: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | -------------------------------------------------------------------------------- /tags/rg-select/rg-select.filter.spec.js: -------------------------------------------------------------------------------- 1 | describe('rg-select', function () { 2 | let tag, select 3 | let spyOnOpen = sinon.spy() 4 | let spyOnClose = sinon.spy() 5 | let spyOnSelect = sinon.spy() 6 | let spyOnFilter = sinon.spy() 7 | 8 | beforeEach(function () { 9 | select = { 10 | placeholder: 'Please select a card', 11 | filter: 'text', 12 | options: [{ 13 | id: 0, 14 | text: 'Visa' 15 | }, { 16 | id: 1, 17 | text: 'MasterCard' 18 | }, { 19 | id: 2, 20 | text: 'American Express' 21 | }, { 22 | id: 3, 23 | text: 'Discover' 24 | }] 25 | } 26 | $('body').append('') 27 | tag = riot.mount('rg-select', { 28 | select 29 | })[0] 30 | tag.on('open', spyOnOpen) 31 | .on('close', spyOnClose) 32 | .on('select', spyOnSelect) 33 | .on('filter', spyOnFilter) 34 | }) 35 | 36 | afterEach(function () { 37 | spyOnOpen.resetHistory() 38 | spyOnClose.resetHistory() 39 | spyOnSelect.resetHistory() 40 | 41 | tag.unmount() 42 | }) 43 | 44 | it('is mounted', function () { 45 | tag.isMounted.should.be.true 46 | }) 47 | 48 | it ('text input is editable', function () { 49 | should.not.exist($('rg-select .field').attr('readonly')) 50 | }) 51 | 52 | it('opens the menu on focus', function () { 53 | $('rg-select .menu').length.should.equal(0) 54 | $('rg-select .field').focus() 55 | $('rg-select .menu').length.should.equal(1) 56 | }) 57 | 58 | // skipping because jquery is no triggegin "input" events 59 | it('adding text to box filters the options list', function () { 60 | const field = tag.root.querySelector('.field') 61 | $('rg-select .menu').length.should.equal(0) 62 | field.focus() 63 | $('rg-select .menu').length.should.equal(1) 64 | $('rg-select .menu__item').length.should.equal(4) 65 | spyOnOpen.should.have.been.calledOnce 66 | field.value = 'm' 67 | tag.keydown({ keyCode: 77, preventDefault: () => {} }) 68 | tag.update() 69 | spyOnFilter.should.have.been.calledOnce 70 | $('rg-select .menu__item').length.should.equal(2) 71 | }) 72 | }) 73 | -------------------------------------------------------------------------------- /tags/rg-select/rg-select.spec.js: -------------------------------------------------------------------------------- 1 | describe('rg-select', function () { 2 | let tag, select 3 | let spyOnOpen = sinon.spy() 4 | let spyOnClose = sinon.spy() 5 | let spyOnSelect = sinon.spy() 6 | 7 | beforeEach(function () { 8 | select = { 9 | placeholder: 'Please select a card', 10 | options: [{ 11 | id: 0, 12 | text: 'Visa' 13 | }, { 14 | id: 1, 15 | text: 'MasterCard', 16 | selected: true 17 | }, { 18 | id: 2, 19 | text: 'American Express' 20 | }, { 21 | id: 4, 22 | text: 'Disabled Card', 23 | disabled: true, 24 | }, { 25 | id: 3, 26 | text: 'Discover', 27 | }] 28 | } 29 | $('body').append('') 30 | tag = riot.mount('rg-select', { 31 | select 32 | })[0] 33 | tag.on('open', spyOnOpen) 34 | .on('close', spyOnClose) 35 | .on('select', spyOnSelect) 36 | }) 37 | 38 | afterEach(function () { 39 | spyOnOpen.resetHistory() 40 | spyOnClose.resetHistory() 41 | spyOnSelect.resetHistory() 42 | tag.unmount() 43 | }) 44 | 45 | it('is mounted', function () { 46 | tag.isMounted.should.be.true 47 | }) 48 | 49 | it('text input is readonly', function () { 50 | should.exist($('rg-select .field').attr('readonly')) 51 | }) 52 | 53 | it('has no items visible on load', function () { 54 | $('rg-select .menu__item').length.should.equal(0) 55 | }) 56 | 57 | it('focusing/blurring field opens/closes dropdown and triggers open/close event', function () { 58 | $('rg-select .menu').length.should.equal(0) 59 | tag.root.querySelector('.field').focus() 60 | $('rg-select .menu').length.should.equal(1) 61 | spyOnOpen.should.have.been.calledOnce 62 | 63 | // clicking field doesn't close it 64 | tag.root.querySelector('.field').click() 65 | $('rg-select .menu').length.should.equal(1) 66 | 67 | // clicking outside rg-select does 68 | $('rg-select').parent().click() 69 | $('rg-select .menu').length.should.equal(0) 70 | spyOnClose.should.have.been.calledOnce 71 | }) 72 | 73 | it('pressing key down will highlight item', function () { 74 | const field = tag.root.querySelector(".field") 75 | field.focus() 76 | tag.keydown({ keyCode: 38, preventDefault: () => {} }) 77 | tag.update() 78 | $('rg-select .menu__item.menu__item--hover').text().should.contain('Discover') 79 | }) 80 | 81 | it('selecting an item sets it to selected and calls onselect', function () { 82 | const field = tag.root.querySelector(".field") 83 | field.focus() 84 | $('rg-select .menu__item:nth-child(3)')[0].click() 85 | field.value.should.equal('American Express') 86 | field.blur() 87 | field.focus() 88 | $('rg-select .menu__item:nth-child(3)').is('.menu__item--active').should.be.true 89 | spyOnSelect.should.have.been.calledOnce 90 | }) 91 | 92 | it('opens the dropdown on enter', function () { 93 | tag.keydown({ keyCode: 13, preventDefault: () => {} }) 94 | tag.update() 95 | $('rg-select .menu').length.should.equal(1) 96 | spyOnOpen.should.have.been.calledOnce 97 | tag.keydown({ keyCode: 13, preventDefault: () => {} }) 98 | tag.update() 99 | $('rg-select .menu').length.should.equal(0) 100 | tag.root.querySelector('input').value.should.equal("Visa") 101 | }) 102 | 103 | it('opens the dropdown on arrow up', function () { 104 | tag.keydown({ keyCode: 38, preventDefault: () => {} }) 105 | tag.update() 106 | $('rg-select .menu').length.should.equal(1) 107 | spyOnOpen.should.have.been.calledOnce 108 | }) 109 | 110 | it('opens the dropdown on arrow down', function () { 111 | tag.keydown({ keyCode: 40, preventDefault: () => {} }) 112 | tag.update() 113 | $('rg-select .menu').length.should.equal(1) 114 | spyOnOpen.should.have.been.calledOnce 115 | }) 116 | 117 | it('does not break on bad navigate', function() { 118 | tag._navigate(99999) 119 | }) 120 | }) 121 | -------------------------------------------------------------------------------- /tags/rg-select/rg-select.tag: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 17 | 18 | 118 | 119 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /tags/rg-tabs/rg-tabs.spec.js: -------------------------------------------------------------------------------- 1 | describe('rg-tabs', function() { 2 | const default_opts = { 3 | tabs: { 4 | tabs: [{ 5 | heading: 'Tab one', 6 | text: 'This is tab one' 7 | }, { 8 | heading: 'Tab two', 9 | text: 'This is tab two', 10 | active: true 11 | }, { 12 | heading: 'Disabled tab', 13 | disabled: true 14 | }, { 15 | heading: 'Tab three', 16 | include: 'yay.html' 17 | }] 18 | } 19 | } 20 | 21 | afterEach(function() { 22 | tag.unmount() 23 | }) 24 | 25 | it('is mounted (no opts)', function() { 26 | tag = newTag('rg-tabs') 27 | tag.isMounted.should.be.true 28 | }) 29 | 30 | it('has correct number of tabs', function() { 31 | tag = newTag('rg-tabs', default_opts) 32 | $('rg-tabs .tabs__tab').length.should.equal(4) 33 | }) 34 | 35 | it('can preset tab as active', function() { 36 | tag = newTag('rg-tabs', default_opts) 37 | $('rg-tabs .tab-heading:nth-child(2)').is('.tab-heading--active').should.be.true 38 | }) 39 | 40 | it('can disable tabs', function() { 41 | tag = newTag('rg-tabs', default_opts) 42 | $('rg-tabs .tab-heading:nth-child(3)').is('.tab-heading--disabled').should.be.true 43 | }) 44 | 45 | it('heading renders text', function() { 46 | tag = newTag('rg-tabs', default_opts) 47 | $('rg-tabs .tab-heading:nth-child(2)').text().should.contain('Tab two') 48 | $('rg-tabs .tab-heading:nth-child(3)').text().should.contain('Disabled tab') 49 | $('rg-tabs .tab-heading:nth-child(4)').text().should.contain('Tab three') 50 | }) 51 | 52 | it('clicking header actives tab', function() { 53 | tag = newTag('rg-tabs', default_opts) 54 | $('rg-tabs .tab-heading:nth-child(4)').click() 55 | $('rg-tabs .tab-heading:nth-child(1)').is('.tab-heading--active').should.be.false 56 | $('rg-tabs .tab-heading:nth-child(2)').is('.tab-heading--active').should.be.false 57 | }) 58 | 59 | it('tab is body is rendered', function() { 60 | tag = newTag('rg-tabs', default_opts) 61 | $('rg-tabs .tabs__tab--active').html().should.contain('This is tab two') 62 | }) 63 | 64 | it('clicking disabled tab does nothing', function() { 65 | tag = newTag('rg-tabs', default_opts) 66 | $('rg-tabs .tab-heading:nth-child(3)').click() 67 | $('rg-tabs .tab-heading:nth-child(2)').is('.tab-heading--active').should.be.true 68 | }) 69 | 70 | it('onopen callback is called on tab click', function() { 71 | tag = newTag('rg-tabs', default_opts) 72 | const spy = sinon.spy() 73 | tag.on('open', spy) 74 | $('rg-tabs .tab-heading:nth-child(1)').click() 75 | spy.should.have.been.called 76 | }) 77 | 78 | it('loads content from ajax via opts.tabs.url', function(done) { 79 | mockAjax() 80 | tag = newTag('rg-tabs', default_opts) 81 | $('rg-tabs .tab-heading:nth-child(4)').click() 82 | setTimeout(() => { 83 | tag.root.querySelector(".tabs__tab--active").innerText.should.equal('Yay!') 84 | done() 85 | },0) 86 | unmockAjax() 87 | }) 88 | }) 89 | -------------------------------------------------------------------------------- /tags/rg-tabs/rg-tabs.tag: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |
5 | { heading } 6 |
7 |
8 |
9 | { text } 10 | 11 |
12 | { include.responseText } 13 |
14 |
15 |
16 | 17 | 56 | 57 |
58 | -------------------------------------------------------------------------------- /tags/rg-tags/rg-tags.spec.js: -------------------------------------------------------------------------------- 1 | describe('rg-tags', function () { 2 | let tag, tags 3 | const default_opts = { 4 | tags: { 5 | placeholder: 'Please select a card', 6 | options: [{ 7 | id: 0, 8 | text: 'Visa' 9 | }, { 10 | id: 1, 11 | text: 'MasterCard', 12 | selected: true 13 | }, { 14 | id: 2, 15 | text: 'American Express' 16 | }, { 17 | id: 3, 18 | text: 'Discover' 19 | }] 20 | } 21 | } 22 | 23 | afterEach(function () { 24 | tag.unmount() 25 | }) 26 | 27 | it('is mounted (no opts)', function () { 28 | tag = newTag('rg-tags') 29 | tag.isMounted.should.be.true 30 | }) 31 | 32 | it('is mounted (empty opts.tags)', function () { 33 | tag = newTag('rg-tags', {tags: {}}) 34 | tag.isMounted.should.be.true 35 | }) 36 | 37 | it('has no items visible on load', function () { 38 | tag = newTag('rg-tags', default_opts) 39 | $('rg-tags .menu__item').length.should.equal(0) 40 | }) 41 | 42 | it('loads a tag via opts', function () { 43 | tag = newTag('rg-tags', {tags: { tags: [ { name: 'foo' } ]}}) 44 | tag.root.querySelectorAll('.tag').length.should.equal(1) 45 | }) 46 | 47 | it('selecting an item calls onselect and resets the menu', function () { 48 | tag = newTag('rg-tags',default_opts) 49 | $('rg-tags .field').focus() 50 | $('rg-tags .menu__item:nth-child(3)').click() 51 | tag.root.querySelectorAll('.tag').length.should.equal(1) 52 | tag.root.querySelector('.button').click() 53 | tag.root.querySelectorAll('.tag').length.should.equal(0) 54 | }) 55 | 56 | it('cannot add the same tag twice', function() { 57 | tag = newTag('rg-tags',default_opts) 58 | tag.addTag(default_opts.tags.options[0]) 59 | tag.update() 60 | tag.root.querySelectorAll('.tag').length.should.equal(1) 61 | tag.addTag(default_opts.tags.options[0]) 62 | tag.update() 63 | tag.root.querySelectorAll('.tag').length.should.equal(1) 64 | tag.addTag(default_opts.tags.options[1]) 65 | tag.update() 66 | tag.root.querySelectorAll('.tag').length.should.equal(2) 67 | tag.root.querySelectorAll('.tag')[1].click() 68 | tag.root.querySelectorAll('.tag').length.should.equal(1) 69 | }) 70 | }) 71 | -------------------------------------------------------------------------------- /tags/rg-tags/rg-tags.tag: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 9 | 10 | 11 |
12 | 13 | 50 | 51 | 57 | 58 |
59 | -------------------------------------------------------------------------------- /tags/rg-toast/rg-toasts.spec.js: -------------------------------------------------------------------------------- 1 | describe('rg-toast', function () { 2 | let tag, onClickSpy, onCloseSpy, toasts 3 | 4 | beforeEach(function () { 5 | onClickSpy = sinon.spy() 6 | onCloseSpy = sinon.spy() 7 | toasts = { 8 | position: 'bottomleft', 9 | toasts: [{ 10 | text: 'Auto disappear', 11 | timeout: 500 12 | }, { 13 | text: 'Auto disappear call onclose', 14 | }, { 15 | text: 'Sticky toast', 16 | sticky: true 17 | }] 18 | } 19 | $('body').append('') 20 | tag = riot.mount('rg-toasts', { 21 | toasts 22 | })[0] 23 | tag.on('select', onClickSpy) 24 | .on('close', onCloseSpy) 25 | }) 26 | 27 | afterEach(function () { 28 | tag.unmount() 29 | }) 30 | 31 | it('is mounted', function () { 32 | tag.isMounted.should.be.true 33 | }) 34 | 35 | it('position can be set', function () { 36 | $('rg-toasts .toasts--bottomleft').length.should.equal(1) 37 | }) 38 | 39 | it('has correct number of toasts', function () { 40 | $('rg-toasts .toast').length.should.equal(3) 41 | $('rg-toasts .toast').text().should.contain('Auto disappear') 42 | $('rg-toasts .toast').text().should.contain('Auto disappear call onclose') 43 | $('rg-toasts .toast').text().should.contain('Sticky toast') 44 | }) 45 | 46 | it('disappears on click', function () { 47 | $('rg-toasts .toast:first-child').click() 48 | $('rg-toasts .toast').length.should.equal(2) 49 | }) 50 | 51 | it('called onclick on click', function () { 52 | $('rg-toasts .toast:nth-child(3)').click() 53 | onClickSpy.should.have.been.called 54 | }) 55 | }) 56 | 57 | describe('rg-toast no position', function () { 58 | let tag, toasts 59 | 60 | beforeEach(function () { 61 | toasts = { 62 | toasts: [{ 63 | text: 'Auto disappear', 64 | timeout: 500 65 | }] 66 | } 67 | $('body').append('') 68 | tag = riot.mount('rg-toasts', { 69 | toasts 70 | })[0] 71 | }) 72 | 73 | afterEach(function () { 74 | tag.unmount() 75 | }) 76 | 77 | it('is mounted', function () { 78 | tag.isMounted.should.be.true 79 | }) 80 | 81 | it('position is defaulted', function () { 82 | $('rg-toasts .toasts--bottomright').length.should.equal(1) 83 | }) 84 | 85 | it('loses toast after timeout', function (done) { 86 | tag.root.querySelectorAll('.toast').length.should.equal(1) 87 | setTimeout( () => { 88 | tag.root.querySelectorAll('.toast').length.should.equal(0) 89 | done() 90 | },600) 91 | }) 92 | }) 93 | 94 | describe('rg-toast no events', function () { 95 | let tag, onClickSpy, onCloseSpy, toasts 96 | 97 | beforeEach(function () { 98 | toasts = { 99 | toasts: [{ 100 | text: 'Auto disappear', 101 | timeout: 500 102 | }, { 103 | text: 'Sticky toast', 104 | sticky: true 105 | }] 106 | } 107 | onClickSpy = sinon.spy() 108 | onCloseSpy = sinon.spy() 109 | $('body').append('') 110 | tag = riot.mount('rg-toasts', { 111 | toasts 112 | })[0] 113 | }) 114 | 115 | afterEach(function () { 116 | tag.unmount() 117 | }) 118 | 119 | it('is mounted', function () { 120 | tag.isMounted.should.be.true 121 | }) 122 | 123 | it('onclick and onclose not called on click', function () { 124 | $('rg-toasts .toast:nth-child(3)').click() 125 | onClickSpy.should.not.have.been.called 126 | onCloseSpy.should.not.have.been.called 127 | }) 128 | 129 | it('is fine with no opts', function() { 130 | const tag1 = newTag('rg-toasts') 131 | const tag2 = newTag('rg-toasts', {toasts: {toasts: "Bees!"}}) 132 | tag1.unmount() 133 | tag2.unmount() 134 | }) 135 | }) 136 | -------------------------------------------------------------------------------- /tags/rg-toast/rg-toasts.tag: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |
5 | { text } 6 |
7 |
8 | 9 | 44 | 45 |
46 | -------------------------------------------------------------------------------- /tags/rg-toggle/rg-toggle.spec.js: -------------------------------------------------------------------------------- 1 | describe('rg-toggle', function() { 2 | let tag, spy, toggle 3 | 4 | beforeEach(function() { 5 | spy = sinon.spy() 6 | toggle = { 7 | checked: false 8 | } 9 | $('body').append('') 10 | tag = riot.mount('rg-toggle', { 11 | toggle 12 | })[0] 13 | tag.on('toggle', spy) 14 | }) 15 | 16 | afterEach(function() { 17 | tag.unmount() 18 | }) 19 | 20 | it('is mounted', function() { 21 | tag.isMounted.should.be.true 22 | const tag2 = newTag("rg-toggle") 23 | tag2.isMounted.should.be.true 24 | tag2.unmount() 25 | }) 26 | 27 | it('has an unchecked checkbox', function() { 28 | $('rg-toggle input[type=checkbox]').is(':checked').should.be.false 29 | }) 30 | 31 | it('has a checked checkbox', function() { 32 | toggle.checked = true 33 | riot.update() 34 | $('rg-toggle input[type=checkbox]').is(':checked').should.be.true 35 | }) 36 | 37 | it('calls ontoggle when toggled', function() { 38 | tag.root.querySelector('input').click() 39 | spy.should.have.been.called 40 | }) 41 | }) 42 | -------------------------------------------------------------------------------- /tags/rg-toggle/rg-toggle.tag: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 10 |
11 | 12 | 22 | 23 |
24 | -------------------------------------------------------------------------------- /tags/rg-unsplash/rg-unsplash.spec.js: -------------------------------------------------------------------------------- 1 | describe('rg-unsplash', function() { 2 | let tag 3 | 4 | afterEach(function() { 5 | tag.unmount() 6 | }) 7 | 8 | it('is mounted', function() { 9 | tag = newTag('rg-unsplash') 10 | tag.isMounted.should.be.true 11 | }) 12 | 13 | it('compiles the correct src with all options', function() { 14 | const unsplash = {} 15 | unsplash.width = 200 16 | unsplash.height = 100 17 | unsplash.greyscale = true 18 | unsplash.random = true 19 | unsplash.blur = true 20 | unsplash.image = '491' 21 | unsplash.gravity = 'north' 22 | tag = newTag('rg-unsplash', { unsplash }) 23 | $('rg-unsplash img').length.should.equal(1) 24 | const expected = 'https://unsplash.it/g/200/100/?random&blur&image=491&gravity=north' 25 | $('rg-unsplash img').attr('src').should.equal(expected) 26 | }) 27 | 28 | it('compiles the correct src with no options', function() { 29 | tag = newTag('rg-unsplash') 30 | $('rg-unsplash img').attr('src').should.equal('https://unsplash.it/450/250/?') 31 | }) 32 | }) 33 | -------------------------------------------------------------------------------- /tags/rg-unsplash/rg-unsplash.tag: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /test-helpers.js: -------------------------------------------------------------------------------- 1 | const deepClone = obj => { 2 | if(obj===null || typeof obj !== "object"){ 3 | return obj; 4 | } 5 | 6 | if(obj instanceof Date){ 7 | return new Date(obj.getTime()); 8 | } 9 | 10 | if(Array.isArray(obj)){ 11 | var clonedArr = []; 12 | obj.forEach(function(element){ 13 | clonedArr.push(deepClone(element)) 14 | }); 15 | return clonedArr; 16 | } 17 | 18 | let clonedObj = new obj.constructor(); 19 | for(var prop in obj){ 20 | if(obj.hasOwnProperty(prop)){ 21 | clonedObj[prop] = deepClone(obj[prop]); 22 | } 23 | } 24 | return clonedObj; 25 | } 26 | 27 | const newTag = (tagName, opts) => { 28 | const element = document.createElement(tagName) 29 | document.body.appendChild(element) 30 | const tag = window.riot.mount(element, deepClone(opts))[0] 31 | 32 | // in anticipation of riot 4 33 | tag.$ = q => tag.root.querySelector(q) 34 | tag.$$ = q => tag.root.querySelectorAll(q) 35 | return tag 36 | } 37 | 38 | const OGXMLHttpRequest = XMLHttpRequest 39 | 40 | const MockXMLHttpRequest = function() { 41 | return { 42 | open(_method, url) { 43 | this.url = url 44 | this.responseText = MockXMLHttpRequest[url] 45 | if (!this.responseText) { 46 | throw `Mocked url response missing for ${url}` 47 | } 48 | }, 49 | send() { 50 | this.onload && this.onload(this.responseText) 51 | } 52 | } 53 | } 54 | 55 | 56 | MockXMLHttpRequest['yay.html'] = "Yay!" 57 | MockXMLHttpRequest.is_mock = true 58 | 59 | OGXMLHttpRequest.is_mock = false 60 | const mockAjax = () => { 61 | window.XMLHttpRequest = MockXMLHttpRequest 62 | } 63 | 64 | const unmockAjax = () => { 65 | window.XMLHttpRequest = OGXMLHttpRequest 66 | } 67 | 68 | const mySpy = (tag, events) => { 69 | let last = {} 70 | const spies = {} 71 | events.forEach( e => { 72 | spies[e] = sinon.spy() 73 | tag.on(e, spies[e]) 74 | }) 75 | const validate = (values) => { 76 | Object.assign(last,values) 77 | events.forEach(e => { 78 | spies[e].callCount.should.equal(last[e] || 0) 79 | }) 80 | } 81 | validate.reset = () => { 82 | last = {} 83 | events.forEach(e => spies[e].resetHistory()) 84 | } 85 | return validate 86 | } --------------------------------------------------------------------------------