diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..b08a31e --- /dev/null +++ b/.editorconfig @@ -0,0 +1,25 @@ +# EditorConfig helps developers define and maintain consistent +# coding styles between different editors and IDEs +# editorconfig.org + +root = true + +[*] + +indent_style = space +indent_size = 4 + +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false + +[{*.json,*.yml}] +indent_size = 2 + +[*.html] +indent_style = tab +indent_size = 2 \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..37939dc --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.DS_Store +node_modules +.sass-cache +Gemfile.lock +_site + +# Ignore files beginning with a # +\#* diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 0000000..36d95e5 --- /dev/null +++ b/.jshintrc @@ -0,0 +1,25 @@ +{ + "node": true, + "browser": true, + "esnext": true, + "bitwise": true, + "camelcase": true, + "curly": true, + "eqeqeq": true, + "immed": true, + "indent": 4, + "latedef": true, + "newcap": true, + "noarg": true, + "quotmark": "single", + "regexp": true, + "undef": true, + "unused": true, + "strict": true, + "trailing": true, + "smarttabs": true, + "globals": { + "jQuery": true, + "define": true + } +} diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..65f382c --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,5 @@ +# Change Log + +## 1.0.0-alpha - 2019-11 + +initial version \ No newline at end of file diff --git a/Credits.md b/Credits.md new file mode 100644 index 0000000..892fddb --- /dev/null +++ b/Credits.md @@ -0,0 +1 @@ +Icon tax by I Putu Kharismayadi from the Noun Project \ No newline at end of file diff --git a/Gruntfile.js b/Gruntfile.js new file mode 100644 index 0000000..5afa70c --- /dev/null +++ b/Gruntfile.js @@ -0,0 +1,173 @@ +module.exports = function (grunt) { + + 'use strict'; + + // Load grunt tasks automatically + require('load-grunt-tasks')(grunt); + + // Time how long tasks take. Can help when optimizing build times + require('time-grunt')(grunt); + + // Project configuration. + grunt.initConfig({ + + config: { + src: 'src', + dist: 'dist' + }, + + pkg: require('./package'), + + // Content of banner appended to files + meta: { + banner: '/**\n' + + ' * <%= pkg.title %> <%= pkg.version %>\n' + + ' * <%= pkg.description %>\n' + + ' * (c) <%= grunt.template.today("yyyy") %> <%= pkg.maintainers[0].name %>\n' + + ' * <%= pkg.license %> license\n' + + ' */\n' + }, + + // Watches files for changes and runs tasks based on the changed files + watch: { + compass: { + files: ['<%= config.src %>/{,*/}*.{scss,sass}'], + tasks: ['compass:dist', 'postcss:dist', 'cssmin:dist'] + }, + + jshint: { + files: '<%= config.src %>/{,*/}*.js', + tasks: ['jshint'] + }, + + concat: { + files: '<%= config.src %>/{,*/}*.js', + tasks: ['concat:dist', 'uglify:dist'] + } + }, + + // Make sure code styles are up to par and there are no obvious mistakes + jshint: { + options: { + jshintrc: '.jshintrc', + reporter: require('jshint-stylish') + }, + all: [ + 'Gruntfile.js', + '<%= config.src %>/{,*/}*.js' + ], + }, + + // Compiles Sass to CSS and generates necessary files if requested + compass: { + options: { + sassDir: 'src', + cssDir: '<%= config.dist %>' + }, + dist: { + options: { + // banner: '<%= meta.banner %>', + // specify: '<%= config.src %>/editpricehelper.scss', + debugInfo: false, + noLineComments: true + } + } + }, + + // Add post-processors to CSS + postcss: { + options: { + processors: [ + require('autoprefixer')({ + flexbox: 'no-2009' + }), + ] + }, + dist: { + src: '<%= config.dist %>/editpricehelper.css' + } + }, + + // Prepend a banner to the files + concat: { + options: { + banner: '<%= meta.banner %>' + }, + dist: { + src: ['<%= config.src %>/jquery.editpricehelper.js'], + dest: '<%= config.dist %>/jquery.editpricehelper.js' + } + }, + + // Generate a minified version of JS + uglify: { + options: { + //banner: '<%= meta.banner %>' + }, + dist: { + src: ['<%= config.dist %>/jquery.editpricehelper.js'], + dest: '<%= config.dist %>/jquery.editpricehelper.min.js' + } + }, + + // Generate a minified version of CSS + cssmin: { + options: { + banner: '<%= meta.banner %>' + }, + dist: { + src: ['<%= config.dist %>/editpricehelper.css'], + dest: '<%= config.dist %>/editpricehelper.min.css' + } + }, + + // Increment version + bump: { + options: { + files: [ + 'bower.json', + 'package.json', + ], + updateConfigs: ['pkg'], + commitMessage: 'Release v%VERSION%', + commitFiles: [ + 'bower.json', + 'package.json', + 'dist' + ], + push: false, + pushTo: 'origin', + createTag: false, + tagName: 'v%VERSION%', + tagMessage: 'Version %VERSION%', + prereleaseName: 'alpha' + } + } + + }); + + // Build task + grunt.registerTask('build', [ + 'compass:dist', + 'postcss:dist', + 'jshint', + 'concat:dist', + 'uglify:dist', + 'cssmin:dist' + ]); + + // Release task + grunt.registerTask('release', [ + 'bump-only', + 'build', + 'bump-commit' + ]); + + // Pre-release task + grunt.registerTask('prerelease', [ + 'bump-only:prerelease', + 'build', + 'bump-commit' + ]); + +}; diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..c7d9150 --- /dev/null +++ b/LICENSE @@ -0,0 +1,18 @@ +The MIT License (MIT) + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..b726fd9 --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ +# ![logo](docs/_medias/editpricehelper.svg) Edit Price Helper + +> A small jQuery plugin to help edit prices with taxes. + +The goal of this script is to give a real-time feedback of the taxes when you edit a price. + +Say you have a no-tax price input and another one for the tax rate on a form: the script will add an all taxes included price input and the tax amount, keeping all values in sync. The added inputs are just here to help fill the original inputs, their values are not meant to be posted. + +![preview](docs/_medias/editpricehelper_on.png) + +* ~2.3kB gzipped + +**[Check the documentation](https://tcharlss.github.io/editpricehelper/) to get started and see some examples.** \ No newline at end of file diff --git a/bower.json b/bower.json new file mode 100644 index 0000000..828e53e --- /dev/null +++ b/bower.json @@ -0,0 +1,34 @@ +{ + "name": "editpricehelper", + "description": "A small jQuery plugin to help edit prices with taxes.", + "title": "Edit Price Helper", + "version": "0.1.0-alpha.1", + "authors": [ + "tcharlss ", + ], + "main": "dist/jquery.editpricehelper.js", + "keywords": [ + "price", + "helper", + "tax", + "input" + ], + "license": "MIT", + "homepage": "https://tcharlss.github.io/editpricehelper/", + "docs": "https://tcharlss.github.io/editpricehelper/", + "download": "https://github.com/tcharlss/editpricehelper/releases", + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "test", + "tests" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/tcharlss/editpricehelper.git" + }, + "dependencies": { + "jquery": ">=3.0" + } +} diff --git a/dist/editpricehelper.css b/dist/editpricehelper.css new file mode 100644 index 0000000..1506ae6 --- /dev/null +++ b/dist/editpricehelper.css @@ -0,0 +1,62 @@ +/** + * ================= + * Edit Price Helper + * ================= + * + * Markup : + * + * label + * span.price.price_notax + * label + * input + * span.price.price_tax + * label + * input + * span.tax tax_amount + * span span + * span.tax tax.rate + * span span + */ +.price { + display: block; +} +.price__label { + display: inline-block; + font-style: italic; + padding-right: 1em; +} +.price__input { + -webkit-transition: background 0.5s; + transition: background 0.5s; +} +.price__input.highlight { + -webkit-animation-name: editpricehelper-highlight; + animation-name: editpricehelper-highlight; + -webkit-animation-duration: 0.5s; + animation-duration: 0.5s; +} +.price__tax-rate { + margin-left: 0.5em; +} + +@-webkit-keyframes editpricehelper-highlight { + from { + -webkit-box-shadow: inset 0 0 0 99em #f7e06e; + box-shadow: inset 0 0 0 99em #f7e06e; + } + to { + -webkit-box-shadow: none; + box-shadow: none; + } +} + +@keyframes editpricehelper-highlight { + from { + -webkit-box-shadow: inset 0 0 0 99em #f7e06e; + box-shadow: inset 0 0 0 99em #f7e06e; + } + to { + -webkit-box-shadow: none; + box-shadow: none; + } +} diff --git a/dist/editpricehelper.min.css b/dist/editpricehelper.min.css new file mode 100644 index 0000000..97f9a07 --- /dev/null +++ b/dist/editpricehelper.min.css @@ -0,0 +1 @@ +.price{display:block}.price__label{display:inline-block;font-style:italic;padding-right:1em}.price__input{-webkit-transition:background .5s;transition:background .5s}.price__input.highlight{-webkit-animation-name:editpricehelper-highlight;animation-name:editpricehelper-highlight;-webkit-animation-duration:.5s;animation-duration:.5s}.price__tax-rate{margin-left:.5em}@-webkit-keyframes editpricehelper-highlight{from{-webkit-box-shadow:inset 0 0 0 99em #f7e06e;box-shadow:inset 0 0 0 99em #f7e06e}to{-webkit-box-shadow:none;box-shadow:none}}@keyframes editpricehelper-highlight{from{-webkit-box-shadow:inset 0 0 0 99em #f7e06e;box-shadow:inset 0 0 0 99em #f7e06e}to{-webkit-box-shadow:none;box-shadow:none}} \ No newline at end of file diff --git a/dist/jquery.editpricehelper.js b/dist/jquery.editpricehelper.js new file mode 100644 index 0000000..b07aec6 --- /dev/null +++ b/dist/jquery.editpricehelper.js @@ -0,0 +1,517 @@ +/** + * Edit Price Helper 0.1.0-alpha.1 + * A small jQuery plugin to help edit prices with taxes. + * (c) 2019 tcharlss + * MIT license + */ +(function ($) { + 'use strict'; + + // Plugin identifier and default values + var + pluginName = 'editpricehelper', + pluginIdentifier = 0, + defaults = { + priceType: 'notax', // Type of price of the main input: `tax` or `notax`. + otherPriceInput: null, // Selector of an existing input containing the complementary price. Otherwise, it will be created. + taxRateInput: null, // Selector of an existing input containing the tax rate. Otherwise, a default taxe rate is needed. + taxRate: null, // Default tax rate to apply in case there's no input or no value is entered. + taxRateInPercent: false, // Indicate weither the tax rate is in percent or not, eg. `20` instead of `0.2` for instance. + precision: 2, // Precision of the displayed numbers. + urlCalculate: null, // URL to a script calculating the prices. Otherwise, they will be calculated in-house. + displayTaxAmount: true, // Display the tax amount or not. + // Text of labels + mainLabel: 'Price', + priceTaxLabel: 'All taxes included', + priceNoTaxLabel: 'Pre-tax', + taxAmountLabel: 'Tax', + defaultLabel: 'default', + // CSS classes + priceTaxClass: 'price price_tax', + priceNoTaxClass: 'price price_notax', + taxAmountClass: 'price price_tax-amount', + taxRateClass: 'price price_tax-rate', + taxRateDisplayClass: 'price__tax-rate', + labelClass: 'price__label', + inputClass: 'price__input', + // Debug + debug: false, + }; + + /** + * Plugin + * @param {String} element + * @param {Object} options + */ + function Plugin(element, options) { + + // Basics + this.$element = $(element); + this.options = $.extend({}, defaults, options, this.$element.data()); + this.identifier = pluginName + '-' + (pluginIdentifier++); + + // Usefull stuff + this.priceType = this.options.priceType; + this.otherPriceType = this.getOtherPriceType(this.priceType); + this.hasSinglePriceInput = ($(this.options.otherPriceInput).length === 0); + this.hasTaxRateInput = ($(this.options.taxRateInput).length > 0); + + // Will be added after init + this.$inputs = null; // 3 main inputs + this.$taxRateDisplay = null; // Tax rate display helper + + // Call the initialization + this.init(); + } + + /** + * Initialization + * @return {Void} + */ + Plugin.prototype.init = function () { + var error = this.check(); + if (!error) { + this.setup(); + this.addInteractions(); + + // Event : onInit + if (this.onInit && typeof this.onInit === 'function') { + this.onInit(); + } + } else { + console.log('Edit Price Helper error: ' + error); + } + }; + + /** + * Check that we have everything we need + * @return {Void} + */ + Plugin.prototype.check = function () { + var + error = '', + elementTag = this.$element.prop('tagName'), + inputType = this.$element.attr('type'); + + // Check that main input is text or number + if (elementTag !== 'INPUT' || (inputType !== 'text' && inputType !== 'number')) { + error = 'Main input type need to be `text` or `number`'; + } + // Check that we have a taxe rate + else if (!this.hasTaxRateInput && !this.options.taxRate) { + error = 'No taxe rate provided, use `taxRateInput` or `taxRate`.'; + } + + return error; + }; + + /** + * Set everything up : add elements to the DOM and such + * @return {Void} + */ + Plugin.prototype.setup = function () { + + var + $this = this, + options = this.options, + $inputs = {}, + id = this.$element.attr('id'), + $label = $('label[for="' + id + '"]'), + priceType = this.priceType, + otherPriceType = this.otherPriceType, + labels, + classes; + + // Labels & classes + labels = { + main: options.mainLabel, + notax: options.priceNoTaxLabel, + tax: options.priceTaxLabel, + taxAmount: options.taxAmountLabel, + defaultTaxAmount: options.defaultTaxAmountLabel, + }; + classes = { + notax: options.priceNoTaxClass, + tax: options.priceTaxClass, + taxAmount: options.taxAmountClass, + taxRate: options.taxRateClass, + taxRateDisplay: options.taxRateDisplayClass, + input: options.inputClass, + label: options.labelClass, + }; + + // Store main inputs globally : + // main price, complementary price, tax rate & tax amount + this.$inputs = $inputs; + + // Main price input + $inputs[priceType] = this.$element.data('priceType', priceType); + + // Taxe rate input if present + if (this.hasTaxRateInput) { + $inputs.taxRate = $(options.taxRateInput); + } + + // If there is a single price input, + // add the complementary price input and the tax amount input, + // then wrap them and add labels to distinguish them. + if (this.hasSinglePriceInput) { + + // Add complementary price input + $inputs[otherPriceType] = $inputs[priceType] + .clone(false, false) + .attr('value', '') + .removeData() + .removeAttr('name required') // this value is not meant to be posted + .attr('id', id + '_helper') + .data('priceType', otherPriceType) + .insertAfter($inputs[priceType]); + + // Add tax amount input + if (options.displayTaxAmount) { + $inputs.taxAmount = $inputs[otherPriceType] + .clone(false, false) + .removeData() + .removeAttr('min max step') + .attr('type', 'text') + .attr({disabled:'',readonly:''}) + .attr('id', id + '_tax_amount') + .insertAfter($inputs[otherPriceType]); + } + + // Wrap inputs and add labels to distinguish them + this.$taxRateDisplay = $('') + .addClass(classes.taxRateDisplay) + .html(this.displayTaxRate()); + $.each($inputs, function (input) { + var + id = $(this).attr('id'), + $label; + + // wrap in a span + $(this) + .addClass(classes.input) + .wrap($('') + .addClass(classes[input])); + // Add a label + if (labels[input]) { + $label = $('