├── .gitignore ├── .jshintignore ├── .jshintrc ├── .travis.yml ├── Gruntfile.coffee ├── LICENSE ├── README.md ├── build └── tasks │ ├── clean.coffee │ ├── compress.coffee │ ├── copy.coffee │ ├── env.coffee │ ├── es6.coffee │ ├── istanbul.coffee │ ├── jshint.coffee │ ├── mocha.coffee │ ├── shell.coffee │ ├── stylus.coffee │ └── watch.coffee ├── chrome-extension ├── _locales │ ├── en │ │ └── messages.json │ └── es │ │ └── messages.json ├── key.pem ├── manifest.json └── test │ └── configure.js ├── docs ├── Modules.md ├── NewComponent.md ├── NewPage.md ├── README.md ├── WebdriverReference.md ├── _assets │ ├── activity.png │ ├── background.png │ ├── component.png │ ├── contentscript.png │ ├── dependencies.json │ ├── dom.png │ ├── environment.png │ ├── extension.png │ ├── index.png │ ├── notifications.png │ ├── overview.png │ ├── storage.png │ ├── tabs.png │ └── watcher.png └── modules │ ├── background.md │ ├── contentscript.md │ └── lib │ ├── activity.md │ ├── component.md │ ├── components │ ├── donation-goal.md │ ├── log-table.md │ └── reminders.md │ ├── dom.md │ ├── environment.md │ ├── extension.md │ ├── index.md │ ├── notifications.md │ ├── pages │ ├── donations.md │ ├── getting-started.md │ ├── log.md │ └── settings.md │ ├── storage.md │ ├── tabs.md │ └── watcher.md ├── package.json ├── shared ├── fonts │ ├── FontAwesome.otf │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ └── fontawesome-webfont.woff ├── html │ └── index.html ├── img │ ├── bitcoin.png │ ├── bitcoin_pay.png │ ├── dwolla.png │ ├── dwolla_pay.png │ ├── logo19.png │ ├── logo48.png │ ├── logo64.png │ ├── paypal.png │ ├── settings.png │ └── stripe.png ├── scripts │ ├── background.js │ ├── contentscript.js │ └── lib │ │ ├── activity.js │ │ ├── component.js │ │ ├── components │ │ ├── donation-goal │ │ │ ├── donation-goal.html │ │ │ ├── donation-goal.js │ │ │ └── donation-goal.styl │ │ ├── log-table │ │ │ ├── entry-history.html │ │ │ ├── log-table.html │ │ │ ├── log-table.js │ │ │ └── log-table.styl │ │ ├── reminders │ │ │ ├── reminder-interval.html │ │ │ ├── reminder-interval.js │ │ │ ├── reminder-interval.styl │ │ │ ├── reminder-thresh-global.html │ │ │ ├── reminder-thresh-global.js │ │ │ ├── reminder-thresh-global.styl │ │ │ ├── reminder-thresh-local.html │ │ │ ├── reminder-thresh-local.js │ │ │ └── reminder-thresh-local.styl │ │ └── user-agreement │ │ │ ├── user-agreement.html │ │ │ ├── user-agreement.js │ │ │ └── user-agreement.styl │ │ ├── defaults.js │ │ ├── dom.js │ │ ├── environment.js │ │ ├── extension.js │ │ ├── hardcoded-doms.js │ │ ├── identifier.js │ │ ├── index.js │ │ ├── notifications.js │ │ ├── pages │ │ ├── donations │ │ │ ├── donations.html │ │ │ ├── donations.js │ │ │ ├── donations.styl │ │ │ └── entry-donation.html │ │ ├── getting-started │ │ │ ├── getting-started.html │ │ │ ├── getting-started.js │ │ │ └── getting-started.styl │ │ ├── log │ │ │ ├── log.html │ │ │ ├── log.js │ │ │ └── log.styl │ │ └── settings │ │ │ ├── settings.html │ │ │ ├── settings.js │ │ │ └── settings.styl │ │ ├── processors │ │ ├── dwolla.js │ │ └── paypal.js │ │ ├── server-requests.js │ │ ├── storage.js │ │ ├── tabs.js │ │ ├── utils │ │ ├── calculate.js │ │ ├── js-yaml.js │ │ └── tipsy-txt-parser.js │ │ └── watcher.js ├── styles │ ├── index.styl │ └── table-sorting.styl └── vendor │ ├── deparam.js │ ├── dwolla.js │ └── font-awesome.min.css ├── test ├── integration │ ├── extension-driver.js │ ├── setup.js │ └── tests │ │ ├── basic.js │ │ └── watcher.js ├── normalizePaths.js └── unit │ ├── runner.js │ └── tests │ └── storage.js └── wp-tipsy-payment-info ├── ReadMe.txt └── TipsyInjection.php /.gitignore: -------------------------------------------------------------------------------- 1 | /build/tools 2 | /bower_components 3 | /node_modules 4 | /chrome-extension/dist 5 | /cjs 6 | /test/coverage 7 | -------------------------------------------------------------------------------- /.jshintignore: -------------------------------------------------------------------------------- 1 | shared/vendor/dwolla.js 2 | shared/vendor/deparam.js 3 | shared/scripts/lib/utils/js-yaml.js 4 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "eqnull": true, 3 | "node": true, 4 | "browser": true, 5 | "esnext": true, 6 | "proto": true, 7 | "globals": { 8 | "$": true, 9 | "chrome": true, 10 | "self": true, 11 | "combyne": true, 12 | "moment": true, 13 | "deparam": true, 14 | "Tablesort": true 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Install Chrome in Travis-CI. 2 | dist: trusty 3 | sudo: required 4 | 5 | addons: 6 | apt: 7 | sources: 8 | - google-chrome 9 | packages: 10 | - google-chrome-stable 11 | 12 | before_script: 13 | - "export DISPLAY=:99.0" 14 | - "sh -e /etc/init.d/xvfb start" 15 | - "sleep 3" 16 | - "cat /etc/init.d/xvfb" 17 | script: npm run test 18 | 19 | language: node_js 20 | node_js: 21 | - "6.1" 22 | env: 23 | global: 24 | - secure: "ZUeyY/wcPM40iP7eGZxPCrOEOBjjhvW9tZJ5ZLxD8n4qB3HVdcU/tstUSuBF/GgTG7BgnLC3TMUP2l6pP6li/JOxfHXrEqVNwrG8VHhpVNMdogVaL/3d0UER/s2cT2ioU7B3bkc4YFc1vR67h235KLaVip8YhMpcF1hhR1P7SC0=" 25 | - secure: "q5oQpQRFCAfe+y6FgG7Jie48H2glHdAmatbanlYv35WVOwIk2G2SEzKrqSmMgx9mEwWhgK80+8i1bhj85x9uLCXPgJuCTqX4tjdqpL5GcQ354LDveHaXI4NjynrrUg8LF4VtEn8SOQOok7DWcI/9kcAGVfnZmlPQ3fiUdJlcXEE=" 26 | -------------------------------------------------------------------------------- /Gruntfile.coffee: -------------------------------------------------------------------------------- 1 | module.exports = -> 2 | @loadTasks 'build/tasks' 3 | 4 | @registerTask 'default', [ 5 | 'jshint' 6 | 'chrome-extension' 7 | ] 8 | 9 | @registerTask 'coverage', [ 10 | 'env:coverage' 11 | 'instrument' 12 | 'test' 13 | 'storeCoverage' 14 | 'makeReport' 15 | ] 16 | 17 | @registerTask 'test', [ 18 | 'mochaTest:chrome-extension' 19 | 'mochaTest:shared' 20 | ] 21 | 22 | @registerTask 'chrome-extension', [ 23 | 'clean:chrome-extension' 24 | 'compress:chrome-extension' 25 | 'copy:chrome-extension' 26 | 'stylus:chrome-extension' 27 | 'es6:chrome-extension' 28 | 'shell:chrome-extension' 29 | ] 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 MIT Haystack 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Tipsy 2 | ----- 3 | 4 | [![Build Status](https://travis-ci.org/haystack/tipsy.png?branch=master)](https://travis-ci.org/haystack/tipsy) 5 | 6 | 7 | ### Developing ### 8 | 9 | If you wish to work on Tipsy, you can find instructions on getting started 10 | below. It uses [Node](http://nodejs.org) to install and run the extension. 11 | 12 | At the moment the build process and tests only work in Linux. 13 | 14 | #### Installing Node and dependencies #### 15 | 16 | Go to the [Node](http://nodejs.org) homepage and install for your platform. 17 | 18 | Next, open a command line prompt and enter the project directory. You will 19 | install all development dependencies with one command: 20 | 21 | ``` bash 22 | npm install 23 | ``` 24 | 25 | ### Working on Chrome extension ### 26 | 27 | To build the Chrome extension, you will need [Google 28 | Chrome](http://chrome.com/) installed. 29 | 30 | Once it is installed and configured you can build the extension with: 31 | 32 | ``` bash 33 | npm run build-chrome 34 | ``` 35 | 36 | #### Loading the unpacked extension #### 37 | 38 | The source code necessary to run the extension as unpacked lives in the 39 | *dist/tipsy* directory and can be dragged into the Extensions tab within 40 | Chrome. 41 | 42 | #### Watching the filesystem for changes #### 43 | 44 | You can have the extension automatically recompiled with: 45 | 46 | ``` shell 47 | npm run watch-chrome 48 | ``` 49 | 50 | #### Extension url #### 51 | 52 | chrome-extension://ajcjbhihdfmefgbenbkpgalkjglcbmmp/html/index.html 53 | 54 | #### Watching the filesystem for changes #### 55 | 56 | You can have both extensions automatically recompiled with: 57 | 58 | ``` shell 59 | npm run watch 60 | ``` 61 | -------------------------------------------------------------------------------- /build/tasks/clean.coffee: -------------------------------------------------------------------------------- 1 | module.exports = -> 2 | @loadNpmTasks 'grunt-contrib-clean' 3 | 4 | @config 'clean', 5 | 'chrome-extension': ['chrome-extension/dist'] 6 | -------------------------------------------------------------------------------- /build/tasks/compress.coffee: -------------------------------------------------------------------------------- 1 | module.exports = -> 2 | @loadNpmTasks 'grunt-contrib-compress' 3 | 4 | @config 'compress', 5 | 'chrome-extension': 6 | options: 7 | archive: 'chrome-extension/dist/tipsy.zip' 8 | mode: 'zip' 9 | 10 | files: [ 11 | { src: ['node_modules/purecss/*'], dest: '.' } 12 | { src: ['**/*'], expand: true, cwd: 'shared' } 13 | { 14 | src: [ 15 | 'key.pem' 16 | '_locales/**' 17 | ] 18 | expand: true 19 | cwd: 'chrome-extension' 20 | } 21 | ] 22 | -------------------------------------------------------------------------------- /build/tasks/copy.coffee: -------------------------------------------------------------------------------- 1 | module.exports = -> 2 | @loadNpmTasks 'grunt-contrib-copy' 3 | 4 | chromeDest = 'chrome-extension/dist/tipsy' 5 | 6 | npmDeps = [ 7 | 'node_modules/jquery/dist/*', 8 | 'node_modules/purecss/build/*', 9 | 'node_modules/combyne/dist/*' 10 | 'node_modules/moment/min/*' 11 | 'node_modules/tablesort/*' 12 | ] 13 | 14 | @config 'copy', 15 | 'chrome-extension': 16 | files: [ 17 | { 18 | src: npmDeps 19 | expand: true 20 | dest: chromeDest 21 | } 22 | { 23 | src: [ 24 | '**/*' 25 | '!_assets/**' 26 | ] 27 | expand: true 28 | cwd: 'shared' 29 | dest: chromeDest 30 | } 31 | { 32 | src: [ 33 | 'manifest.json' 34 | '_locales/**' 35 | ] 36 | expand: true 37 | cwd: 'chrome-extension' 38 | dest: chromeDest 39 | } 40 | ] 41 | -------------------------------------------------------------------------------- /build/tasks/env.coffee: -------------------------------------------------------------------------------- 1 | module.exports = -> 2 | @loadNpmTasks 'grunt-env' 3 | 4 | @config 'env', 5 | coverage: 6 | CODE_COV: true 7 | -------------------------------------------------------------------------------- /build/tasks/es6.coffee: -------------------------------------------------------------------------------- 1 | transpiler = require 'es6-module-transpiler' 2 | 3 | buildES6 = (options) -> 4 | container = new transpiler.Container( 5 | resolvers: [new transpiler.FileResolver([options.path])] 6 | formatter: new transpiler.formatters.bundle 7 | ) 8 | 9 | container.getModule options.module 10 | 11 | if options.target is "chrome-extension" 12 | container.write "chrome-extension/dist/tipsy/" + options.chrome 13 | 14 | module.exports = -> 15 | @registerTask 'es6', 'Compiles ES6 modules.', -> 16 | 17 | target = @args[0] 18 | 19 | # Extension. 20 | buildES6 21 | target: target 22 | path: 'shared/scripts/lib' 23 | module: 'index' 24 | chrome: 'js/tipsy.js' 25 | 26 | # Background. 27 | buildES6 28 | target: target 29 | path: 'shared/scripts' 30 | module: 'background' 31 | chrome: 'js/background.js' 32 | 33 | # ContentScript. 34 | buildES6 35 | target: target 36 | path: 'shared/scripts' 37 | module: 'contentscript' 38 | chrome: 'js/contentscript.js' 39 | -------------------------------------------------------------------------------- /build/tasks/istanbul.coffee: -------------------------------------------------------------------------------- 1 | istanbulTraceur = require 'istanbul-traceur' 2 | 3 | module.exports = -> 4 | @loadNpmTasks 'grunt-istanbul' 5 | 6 | # Inject the Istanbul Traceur version to provide proper ES6 coverage. 7 | task = require.cache[require.resolve('istanbul')] 8 | task.exports.Instrumenter = istanbulTraceur.Instrumenter 9 | 10 | @config 'instrument', 11 | options: 12 | basePath: 'test/coverage/instrument' 13 | 14 | files: 'shared/**/*.js' 15 | 16 | @config 'storeCoverage', 17 | options: 18 | dir: 'test/coverage/reports' 19 | 20 | @config 'makeReport', 21 | options: 22 | type: 'lcov' 23 | dir: 'test/coverage/reports' 24 | 25 | src: 'test/coverage/reports/**/*.json' 26 | -------------------------------------------------------------------------------- /build/tasks/jshint.coffee: -------------------------------------------------------------------------------- 1 | module.exports = -> 2 | @loadNpmTasks 'grunt-contrib-jshint' 3 | 4 | # Run your source code through JSHint's defaults. 5 | @config 'jshint', 6 | options: 7 | jshintrc: '.jshintrc' 8 | 9 | files: [ 10 | 'shared/**/*.js' 11 | ] 12 | -------------------------------------------------------------------------------- /build/tasks/mocha.coffee: -------------------------------------------------------------------------------- 1 | module.exports = -> 2 | @loadNpmTasks 'grunt-mocha-test' 3 | 4 | @config 'mochaTest', 5 | options: 6 | clearRequireCache: true 7 | 8 | 'chrome-extension': 9 | src: [ 10 | 'test/integration/setup.js' 11 | 'test/integration/extension-driver.js' 12 | 'chrome-extension/test/configure.js' 13 | 'test/integration/tests/**/*.js' 14 | ] 15 | 16 | 'shared': 17 | src: [ 18 | 'test/unit/runner.js' 19 | 'test/unit/tests/**/*.js' 20 | ] 21 | -------------------------------------------------------------------------------- /build/tasks/shell.coffee: -------------------------------------------------------------------------------- 1 | path = require 'path' 2 | fs = require 'fs' 3 | 4 | module.exports = -> 5 | @loadNpmTasks 'grunt-shell' 6 | 7 | env = process.env 8 | 9 | chrome = 'echo Skipping Chrome' 10 | python2 = 'echo Skipping Python2' 11 | 12 | # https://code.google.com/p/selenium/wiki/ChromeDriver#Requirements 13 | if process.platform is 'linux' 14 | chrome = '/usr/bin/google-chrome' 15 | if not fs.existsSync chrome 16 | chrome = '/usr/bin/chromium' 17 | else if process.platform is 'darwin' 18 | chrome = '"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"' 19 | else if process.platform is 'win32' 20 | chrome = '"' + 'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe' + '"' 21 | 22 | if not fs.existsSync chrome 23 | chrome = '"' + 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe' + '"' 24 | 25 | if process.platform is 'linux' 26 | python2 = 'cd build/tools ; grep -Rl python . | xargs sed -ri "s/([^!]|^)python(\\s|$)/\\1python2\\2/g"' 27 | 28 | @config 'shell', 29 | 'chrome-extension': 30 | command: [ 31 | chrome 32 | '--pack-extension=' + path.resolve('chrome-extension/dist/tipsy') 33 | '--pack-extension-key=' + path.resolve('chrome-extension/key.pem') 34 | '--no-message-box' 35 | ].join(' ') 36 | 37 | 'python2': 38 | command: python2 39 | -------------------------------------------------------------------------------- /build/tasks/stylus.coffee: -------------------------------------------------------------------------------- 1 | module.exports = -> 2 | @loadNpmTasks 'grunt-contrib-stylus' 3 | 4 | @config 'stylus', 5 | 'chrome-extension': 6 | files: 7 | 'chrome-extension/dist/tipsy/css/tipsy.css': 'shared/styles/index.styl' 8 | -------------------------------------------------------------------------------- /build/tasks/watch.coffee: -------------------------------------------------------------------------------- 1 | module.exports = -> 2 | @loadNpmTasks 'grunt-contrib-watch' 3 | 4 | @config 'watch', 5 | 'chrome-extension': 6 | files: [ 7 | 'chrome-extension/**/*' 8 | '!chrome-extension/dist/**/*' 9 | 'shared/**/*' 10 | ] 11 | 12 | tasks: [ 13 | 'chrome-extension' 14 | 'es6' 15 | ] 16 | -------------------------------------------------------------------------------- /chrome-extension/_locales/en/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extName": { 3 | "message": "Tipsy", 4 | "description": "Text string (no longer than 45 characters) extension name" 5 | }, 6 | "extDescription": { 7 | "message": "Support the creators of the content you love!", 8 | "description": "Text string (no longer than 132 characters) describing the extension. Description appears in chrome://extensions." 9 | }, 10 | "browserActionTitle": { 11 | "message": "Tipsy", 12 | "description": "Browser action default_title text string" 13 | } 14 | } -------------------------------------------------------------------------------- /chrome-extension/_locales/es/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extName": { 3 | "message": "Chrome Extension Base", 4 | "description": "Text string (no longer than 45 characters) extension name" 5 | }, 6 | "extDescription": { 7 | "message": "Use as the basis for new extensions!", 8 | "description": "Text string (no longer than 132 characters) describing the extension. Description appears in chrome://extensions." 9 | }, 10 | "browserActionTitle": { 11 | "message": "Chrome Extension Base", 12 | "description": "Browser action default_title text string" 13 | } 14 | } -------------------------------------------------------------------------------- /chrome-extension/key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDdLQrbsHbaohtU 3 | GgB5F3QR6X0ofI6y8WPB4PlhCFX4zK0pp8OxEX4+M/I3lTJFkD3iLmlVO9AYb52E 4 | W0ZLpAzOP0BUipruEIsejB/P0qgzP/gEm2PktQ3QogOaJCZxDFCp20BQX0X9ezNE 5 | wVocvm7GGIEcf2Cjw39bB4Vp7mgHsAsmTxewDsmiLHIBXPBf+Icipiy6tYYmFz/I 6 | yG2MvXuMSVFegfHIBixjRPx/8xmQT1iE3IGI4hLu8PRRNfpb8C+yNRuWQW2gp+LW 7 | WUZPGvTUEilOAwTqqJW7YnSR9TgOK1k8Pp+VGebVV7vwyTh/iAPBnO6ZBga8yOb3 8 | xVqmF45JAgMBAAECggEAYw30KfW7FSm6wYyvn4vQcOE4K3S1WBDh04fVSA66qiXI 9 | e7pl2xxxhJwxI5GPJTZ3cJ/GjuStyvPaANf8AI5lKc2MGxDEWFBSbgjlimbW67T/ 10 | d9i8AUbQ/BpDMLp1+PVB/wBxqk0xBFgz2twZZnwnElMRJ9koR8+bbwJMTuf18VKi 11 | AyxSw/Gfx2Pi2UPzc7FBtwEBX2rd1JnSWg3Im6DzhkfgFZcur5KNBm894ynU7GRl 12 | yQve3VznQ3Jzilj2xngb44rPpWl5O3b0Wqnrn1iPTl2vGa0920LD+fYzvkyzYseh 13 | kcAuHpMv/AzWNIJF9TFCoBTsne3rGaylfKhksAt9HQKBgQD7nZKG30f7bI1JcaT4 14 | eJ0J+0ucUL99s/BxFWbE0Sslb+CasW7PHSmgq9oW5hp8zDsLeaLEcobRKsQcwPuF 15 | VIPBddDOMwMKgReUAsdGUGf6Y0FxnFFY7cuUXVWgb5B5meQ1bfY90ghCTT0hRPaS 16 | P5uT3HxIGi7EAgY5EPwQ+zAOwwKBgQDhB67CXykAG6aEiuEw7DWYzN2BJ8j20sbz 17 | 7Whr78bZrjzbJ/3pjsq/ZQJ05DikG6DNa1zWON8cZes1fhl+3Ri7IdyulXtC4yLL 18 | uqYr6HBfCoYG3pVSE6hAo6iz0thHUOI/zNZKT4RVFuTHQ4wDsX/0Rl1SyGXQJuO5 19 | wsPwKsj2AwKBgCy8Q0T/hcjJ8ATS08Xpi+Iub68HHES5LVKtv2vW1Jj/XyuhyFXC 20 | lZgfddMEbkkp9oV/xtSumBGwTNXf6dg2woYu8ET5BN1lPk/ufoed3B7EbupIJJ5v 21 | CPcD8SlpLIKyPcTSHCm5ogZHvUqg/EXcUUjktqQLI61tvrV+s5JBVrYJAoGBANsh 22 | ixm2Zwu24VnSj+X/L1YjsVPTNUy+BoWE25m4PfC+Tn6vm//zUBY/O7wufcW5Lca7 23 | 1QS7DvDtgrVtnVA/55RbLjZIVGbXHow7rxO03rB+Y/OOjuQFRmPjuyWZnYkdB6VP 24 | SCHG+zuM9q3gZhk2oT5zwu8ZPKQNKtc7BWj7kQSXAoGAEe6okFX/7m6sp4KSFuoE 25 | IiQF4tr3T8jTWacn4U/ie14mx15w+D+hxx3510ojXXkPIrkPz5flfdfveQC5wdml 26 | nZCTDgzu9uC6OJgfLI8VjI2kY7RD8rgO1AXx7qrA+ZNONKx128kVsKrEc/NCNsTu 27 | +G3jSyQWwG+JLGxLKIWlk+s= 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /chrome-extension/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 2, 3 | "name": "tipsy", 4 | "version": "0.1.12", 5 | "description": "A prototype", 6 | "icons": { 7 | "19": "img/logo19.png", 8 | "48": "img/logo48.png", 9 | "64": "img/logo64.png" 10 | }, 11 | "default_locale": "en", 12 | "background": { 13 | "scripts": ["js/background.js"] 14 | }, 15 | "browser_action": { 16 | "default_icon": { 17 | "19": "img/logo19.png", 18 | "48": "img/logo48.png", 19 | "64": "img/logo48.png" 20 | }, 21 | "default_title": "Tipsy" 22 | }, 23 | "content_scripts": [ 24 | { 25 | "matches": [ 26 | "http://*/*", 27 | "https://*/*" 28 | ], 29 | "js": [ 30 | "js/contentscript.js" 31 | ], 32 | "run_at":"document_end" 33 | } 34 | ], 35 | "permissions": [ 36 | "alarms", 37 | "tabs", 38 | "history", 39 | "idle", 40 | "storage", 41 | "unlimitedStorage", 42 | "notifications", 43 | "https://www.dwolla.com/", 44 | "https://uat.dwolla.com/" 45 | ], 46 | "web_accessible_resources": [ 47 | "js/**/*", 48 | "js/contentscript.js.map", 49 | "bower_components/**/*", 50 | "html/index.html" 51 | ], 52 | "content_security_policy": "script-src 'unsafe-eval' 'self' https://www.dwolla.com https://uat.dwolla.com; object-src 'self'; style-src 'unsafe-inline' 'self' https://uat.dwolla.com https://www.dwolla.com https://fonts.googleapis.com" 53 | } 54 | -------------------------------------------------------------------------------- /chrome-extension/test/configure.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | process.exit(); 3 | 4 | var chrome = require('selenium-webdriver/chrome'); 5 | var chromeDriver = require('chromedriver'); 6 | 7 | ExtensionDriver.prototype.navigate = function(url) { 8 | return this._driver.get('chrome-extension://' + this._id + '/' + url); 9 | }; 10 | 11 | var id = 'bpngoepojmffegnjicpfjcakgajpmenk'; 12 | 13 | before(function(done) { 14 | this.timeout(20000); 15 | this.environment = 'chrome'; 16 | 17 | var test = this; 18 | 19 | var service = new chrome.ServiceBuilder(chromeDriver.path).build(); 20 | chrome.setDefaultService(service); 21 | 22 | var options = new chrome.Options(); 23 | options.addExtensions(path.resolve('chrome-extension/dist/tipsy.crx'), function() { 24 | test.driver = new chrome.Driver(options, service); 25 | 26 | //driver.manage().timeouts().implicitlyWait(1000); 27 | test.extensionDriver = new ExtensionDriver(test.driver, id); 28 | test.extensionDriver.navigate('html/index.html').then(done); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /docs/Modules.md: -------------------------------------------------------------------------------- 1 | ## Modules 2 | 3 | Tipsy is broken out into many isolated modules that should do one thing or many 4 | related things well. It is authored in the ES6 module specification flavor. 5 | A good reference and learning resource is: http://jsmodules.io/ 6 | 7 | ### Creating a new module 8 | 9 | A simple module could be a file that looks like this: 10 | 11 | ``` javascript 12 | export var someVariable = 'someValue'; 13 | ``` 14 | 15 | A module can also import other files. Use relative paths to import: 16 | 17 | ``` javascript 18 | import someValue from './some-file'; 19 | ``` 20 | 21 | You may see the syntax: 22 | 23 | ``` javascript 24 | import { someValue } from './some-file'; 25 | ``` 26 | 27 | This allows you to pull a specific exported property from the module. 28 | -------------------------------------------------------------------------------- /docs/NewComponent.md: -------------------------------------------------------------------------------- 1 | ### Adding a new Component 2 | 3 | Components inside Tipsy are defined in: shared/scripts/lib/components/. You 4 | will see existing components already in here that you can base new 5 | functionality off of. 6 | 7 | Creating a new component: 8 | 9 | - Add a folder to `shared/scripts/lib/components/` named after the component. 10 | You should only use lowercase and hyphen separated. 11 | Example: reminder-threshold 12 | - You could copy the reminders component wholesale and then make the necessary 13 | tweaks to get started. 14 | - Add HTML, JS, and Stylus files inside here named after the component. 15 | - `components/reminder-threshold/reminder-treshold.html` 16 | - `components/reminder-threshold/reminder-treshold.js` 17 | - `components/reminder-threshold/reminder-treshold.styl` 18 | - Once you've done this, you'll need to register it in the page (or globally 19 | with Component.register). 20 | - To register in a given page, look at components/settings/settings.js for 21 | inspiration. You will import calls like: 22 | 23 | ``` javascript 24 | import RemindersComponent from '../../components/reminders/reminders'; 25 | ``` 26 | 27 | Add one to match your component: 28 | 29 | ``` javascript 30 | import ReminderThresholdComponent from '../../components/reminder-threshold/reminder-threshold'; 31 | ``` 32 | 33 | - You'll notice that the Component is rendered immediately after the page 34 | has finished rendering inside `afterRender`. 35 | 36 | ``` javascript 37 | new RemindersComponent(select('set-reminders', this.el)).render(); 38 | ``` 39 | 40 | Your code would look something like: 41 | 42 | ``` javascript 43 | new ReminderThresholdComponent(select('reminder-threshold', this.el)).render(); 44 | ``` 45 | 46 | - Add the markup for the component inside the settings page markup 47 | (settings/settings.html): 48 | 49 | ``` html 50 |
51 | 52 |
53 | ``` 54 | 55 | - (Optionally) Add the styles file to: `shared/styles/indx.styl`. 56 | - Under `// Components` around line 17 you'll see a convention for adding 57 | new component styles. 58 | - Adding reminder-threshold would look something like: 59 | 60 | ``` stylus 61 | reminder-threshold 62 | display block 63 | @import '../scripts/lib/components/reminder-threshold/reminder-threshold.styl' 64 | ``` 65 | 66 | - (Optionally) Add content to the markup file: 67 | `components/reminder-threshold/reminder-threshold.html`. This is the 68 | template that will be rendered in place of the settings page markup. 69 | 70 | - Now you need to add the code for the Component: 71 | 72 | ``` javascript 73 | 'use strict'; 74 | 75 | import Component from '../../component'; 76 | 77 | function ReminderThresholdComponent() { 78 | Component.prototype.constructor.apply(this, arguments); 79 | } 80 | 81 | RemindersComponent.prototype = { 82 | template: 'components/reminder-threshold/reminder-threshold.html', 83 | 84 | events: { 85 | 'click': 'handleClick' 86 | }, 87 | 88 | handleClick: function(ev) { 89 | console.log('Component was clicked', ev); 90 | }, 91 | 92 | afterRender: function() { 93 | // Do something with this.$el (jQuery element) after the view is 94 | // rendered. 95 | } 96 | }; 97 | 98 | ReminderThresholdComponent.prototype.__proto__ = Component.prototype; 99 | 100 | export default ReminderThresholdComponent; 101 | ``` 102 | 103 | - Look to other components for inspiration. 104 | -------------------------------------------------------------------------------- /docs/NewPage.md: -------------------------------------------------------------------------------- 1 | ### Creating a new Page 2 | 3 | Pages are simply Components inside the extension. They are registered once 4 | each, using the `Component.registerPage` method. 5 | 6 | ``` javascript 7 | Component.registerPage("#my-page", MyPageConstructor); 8 | ``` 9 | 10 | You will need to import your constructor before using: 11 | 12 | ``` javascript 13 | import MyPageConstructor from './pages/my-page/my-page'; 14 | ``` 15 | 16 | There is, however, a better mechanism in place which is used for registering 17 | pages. Inside: `shared/scripts/lib/index.js` you will see a pages object 18 | near the top of the file. Add the id of the page and the component 19 | constructor; the code following will automatically register and render when 20 | applicable. 21 | 22 | Once you have added this code you will need to modify the 23 | `shared/html/index.html` file to add in your page placeholder. Open this file 24 | and you'll see `
` tags that contain `id`'s that match the id's 25 | assigned above. Add your page placeholder here: 26 | 27 | ``` html 28 |
29 | ``` 30 | 31 | You may also want to add your page to the navigation list in the `