├── .babelrc ├── .editorconfig ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── example ├── App.vue └── index.js ├── package.json ├── src ├── highlighter.js ├── highlighter.test.js ├── index.js └── index.test.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "poi" 4 | ], 5 | "env": { 6 | "test": { 7 | "plugins": [ "istanbul" ] 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | yarn-error.log 4 | 5 | #coverage 6 | .nyc_output 7 | coverage*.lcov 8 | coverage 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 8 4 | install: 5 | - yarn install 6 | - yarn global add nyc 7 | - yarn global add codecov 8 | script: 9 | - yarn test:cov 10 | - codecov 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Giulio Fagioli 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-highlighter 2 | 3 | > **Warning**
4 | > This project is no longer maintained and its use is not recommended 5 | 6 | 7 | [![NPM version](https://img.shields.io/npm/v/vue-highlighter.svg?style=flat)](https://npmjs.com/package/vue-highlighter) [![NPM downloads](https://img.shields.io/npm/dm/vue-highlighter.svg?style=flat)](https://npmjs.com/package/vue-highlighter) [![Build Status](https://travis-ci.org/Remeic/vue-highlighter.svg?branch=master)](https://travis-ci.org/Remeic/vue-highlighter) 8 | [![codecov](https://codecov.io/gh/Remeic/vue-highlighter/branch/master/graph/badge.svg)](https://codecov.io/gh/Remeic/vue-highlighter) 9 | 10 | Vue directive for highlight multiple istances of a word 11 | 12 | ![Example](https://media.giphy.com/media/YU7J5r4WfnLO0geruD/giphy.gif) 13 | 14 | ## Install 15 | 16 | ```bash 17 | yarn add vue-highlighter 18 | ``` 19 | 20 | CDN: [UNPKG](https://unpkg.com/vue-highlighter/) | [jsDelivr](https://cdn.jsdelivr.net/npm/vue-highlighter/) (available as `window.vueHighlighter`) 21 | 22 | ## Usage 23 | 24 | *** 25 | 26 | ### Version 1.1.2 (**Deprecated**) 27 | ```vue 28 | 31 | 32 | 41 | ``` 42 | 43 | *** 44 | 45 | ### Version 2.1.2 ( and >= ) 46 | ```vue 47 | 50 | 51 | 67 | ``` 68 | 69 | #### Option 70 | **Word (String)**: The text string to look for and highlight 71 | ```js 72 | data: () => { 73 | return { 74 | text: 'I love Alessandra', 75 | word: 'Alessandra', 76 | live: true, 77 | } 78 | } 79 | ``` 80 | 81 | **Word (Array[String])**: List of text strings to look for and highlight 82 | ```js 83 | data: () => { 84 | return { 85 | text: 'I love Alessandra', 86 | word: ['I', 'Alessandra'], 87 | live: true, 88 | } 89 | } 90 | ``` 91 | 92 | **Live**: Allow to highlight word and substring, by automatically changhe the regex expression
93 | The live attribute is an optional attribute, is set to false by default 94 | ```js 95 | data: () => { 96 | return { 97 | text: 'I love Alessandra', 98 | word: 'Alessandra', 99 | live: true, 100 | } 101 | } 102 | ``` 103 | 104 | **Color**: Allow to customize the color of text when highlighted
105 | The color attribute is optional and is set to #fff by default
106 | color can be HEX or String
107 | 108 | ```js 109 | data: () => { 110 | return { 111 | text: 'I love Alessandra', 112 | word: 'Alessandra', 113 | style: { 114 | color: '#ffddee' 115 | } 116 | } 117 | } 118 | ``` 119 | 120 | **Background Color**: Allow to customize the background color of text when highlighted
121 | The bgColor attribute is optional and is set to #009688 by default
122 | bgColor can be HEX or String 123 | 124 | ```js 125 | data: () => { 126 | return { 127 | text: 'I love Alessandra', 128 | word: 'Alessandra', 129 | style: { 130 | bgColor: '#ffddee' 131 | } 132 | } 133 | } 134 | ``` 135 | 136 | **Padding**: Allow to customize the padding of text when highlighted
137 | The padding attribute is optional and is set to 0px 5px by default
138 | padding is validate if match this requirments: there is at least one number followed by one of this unit of measure ['cm','mm','in','px','pt','pc','em','ex','ch','rem','vw','vh','vmin','vmax','%'] 139 | 140 | ```js 141 | data: () => { 142 | return { 143 | text: 'I love Alessandra', 144 | word: 'Alessandra', 145 | style: { 146 | padding: '4rem 5%' 147 | } 148 | } 149 | } 150 | ``` 151 | 152 | ## Works on 153 | 154 | * Paragraph 155 | * Ul 156 | * Ol 157 | * Button 158 | * A 159 | 160 | ### Contributor 161 | 162 | Thanks to [Andrea Stagi](https://github.com/astagi) to help me with troubleshooting ❤️. 163 | 164 | 165 | ## License 166 | 167 | MIT © [Giulio Fagioli](https://github.com/remeic) 168 | -------------------------------------------------------------------------------- /example/App.vue: -------------------------------------------------------------------------------- 1 | 36 | 37 | 69 | 70 | 89 | -------------------------------------------------------------------------------- /example/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | 4 | new Vue({ 5 | el: '#app', 6 | render: h => h(App) 7 | }) 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-highlighter", 3 | "version": "2.6.0", 4 | "description": "Vue directive for highlight multiple istances of a word", 5 | "keywords": [ 6 | "vue", 7 | "highlight", 8 | "word", 9 | "library", 10 | "directive", 11 | "vue-highlight", 12 | "evidence", 13 | "mark" 14 | ], 15 | "repository": { 16 | "url": "remeic/vue-highlighter", 17 | "type": "git" 18 | }, 19 | "publishConfig": { "registry": "https://npm.pkg.github.com/" }, 20 | "main": "dist/vue-highlighter.cjs.js", 21 | "files": [ 22 | "dist" 23 | ], 24 | "scripts": { 25 | "prepublishOnly": "npm test && npm run build", 26 | "lint": "eslint . --ext .js --ext .vue", 27 | "test": "npm run lint && tyu", 28 | "test:cov": "nyc --reporter=lcov --reporter=text npm run test", 29 | "build": "bili", 30 | "example": "poi", 31 | "build:example": "poi build", 32 | "coverage": "nyc report --reporter=text-lcov > coverage.lcov" 33 | }, 34 | "author": { 35 | "name": "Giulio Fagioli", 36 | "email": "fagioli.giulio@gmail.com" 37 | }, 38 | "license": "MIT", 39 | "poi": { 40 | "entry": "example/index.js", 41 | "dist": "example/dist", 42 | "homepage": "./" 43 | }, 44 | "bili": { 45 | "format": [ 46 | "cjs", 47 | "umd" 48 | ], 49 | "name": "vue-highlighter" 50 | }, 51 | "eslintConfig": { 52 | "extends": [ 53 | "plugin:vue/recommended" 54 | ] 55 | }, 56 | "devDependencies": { 57 | "@vue/test-utils": "^1.0.0-beta.13", 58 | "bili": "^1.3.3", 59 | "codecov": "^3.0.0", 60 | "eslint": "^4.14.0", 61 | "eslint-plugin-vue": "^4.0.1", 62 | "poi": "^9.3.10", 63 | "sinon": "^4.5.0", 64 | "tyu": "^1.0.0", 65 | "vue-test-utils": "^1.0.0-beta.9" 66 | }, 67 | "resolutions": { "upath": "1.1.0" }, 68 | "dependencies": { 69 | "babel-plugin-istanbul": "^4.1.5", 70 | "nyc": "^14.1.1" 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/highlighter.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue" 2 | 3 | let originalContent = undefined 4 | /** 5 | * Default color of highlighted texts 6 | * @type {string} 7 | */ 8 | const textColorDefault = '#fff' 9 | 10 | /** 11 | * Default background color of highlighted texts 12 | * @type {string} 13 | */ 14 | const bgColorDefault = '#009688' 15 | 16 | /** 17 | * Default padding of highlight containers 18 | * @type {string} 19 | */ 20 | const paddingDefault= '0px 5px' 21 | 22 | /** 23 | * Create a RegEx pattern to find the desired words 24 | * @param {(string|string[])} word - A string or an array of strings to use to create the RegEx pattern 25 | * @param {boolean} [liveHighlighting=false] - Specify if the pattern should be a live search. Default is false 26 | * @returns {string} The RegEx pattern to find looked for words 27 | */ 28 | function selectPattern(word, liveHighlighting = false) { 29 | let result = "" 30 | let explodedWord = Array.isArray(word) ? word.join('|') : word 31 | if (!liveHighlighting) { 32 | result = "\\b(" + explodedWord + ")\\b" 33 | } else { 34 | result = "(" + explodedWord + ")" 35 | } 36 | return result 37 | } 38 | 39 | /** 40 | * Set text color of highlighted text 41 | * @param {string} [color=textColorDefault] - See {@link testColor} for valid colors 42 | * @returns {string} Return the passed string if it is valid color, the {@link textColorDefault} otherwise 43 | */ 44 | function testTextColor(color = textColorDefault){ 45 | let result = textColorDefault 46 | if(testColor(color)){ 47 | result = color 48 | } 49 | return result 50 | } 51 | 52 | /** 53 | * Set text color of highlighted text 54 | * @param {string} [color=bgColorDefault] - See {@link testColor} for valid colors 55 | * @returns {string} Return the passed string if it is valid color, the {@link bgColorDefault} otherwise 56 | */ 57 | function testBgColor(color = bgColorDefault){ 58 | let result = bgColorDefault 59 | if (testColor(color)) { 60 | result = color 61 | } 62 | return result 63 | } 64 | 65 | /** 66 | * Test if a string representing a color is valid 67 | * @param {string} color - Color to test. Valid color are default CSS text colors (e.g.: 'black') and 3 or 6 hexadecimals preceded by a # 68 | * @returns {boolean} True if the color is considered valid, false otherwise 69 | */ 70 | function testColor(color) { 71 | let result = false 72 | let isAColor = /(^#[0-9a-zA-F]{8}$)|(^#[0-9a-zA-F]{6}$)|(^#[0-a-z9A-F]{4}$)|(^#[0-9a-zA-F]{3}$)/i.test(color) 73 | let isAString = /^[a-zA-Z]+$/.test(color) 74 | if(isAColor || isAString){ 75 | result = true 76 | } 77 | return result 78 | } 79 | 80 | /** 81 | * Test if the passed padding value is valid 82 | * @param {string} padding - The padding value to test 83 | * @returns {string} The passed padding if it is valid, {@link paddingDefault} otherwise 84 | */ 85 | function testPadding(padding) { 86 | let result = paddingDefault 87 | let isAValidValue = /^(\d+(cm|mm|in|px|pt|pc|em|ex|ch|rem|vw|vh|vmin|vmax|%)\s?){1,4}$/i.test(padding) 88 | if (isAValidValue) { 89 | result = padding 90 | } 91 | return result 92 | } 93 | 94 | /** 95 | * Create tags with highlighted looked for text 96 | * @param {string} content - Content where find text to highlight 97 | * @param {(string|string[])} word - A word or an array of words to looking for 98 | * @param {string} patternSelected - RegEx pattern to find looked for words 99 | * @param {string} color - Text color of highlighted container 100 | * @param {string} bgColor - Background color of highlighted container 101 | * @param {string} padding - Padding of highlighted container 102 | * @returns {string} Return replaced content with highlighted tags 103 | */ 104 | function highlight(content, word, patternSelected, color, bgColor, padding) { 105 | const spanStart = 106 | "" 107 | const spanEnd = "" 108 | let result = content 109 | if (word != "") { 110 | let regex = new RegExp(patternSelected, "g") 111 | result = content.replace(regex, spanStart + "$&" + spanEnd) 112 | } 113 | return result 114 | } 115 | 116 | const vueHighlighter = { 117 | bind(el, binding, vnode) { 118 | originalContent = el.innerHTML 119 | let pattern = '' 120 | let word = '' 121 | let color = textColorDefault 122 | let bgColor = bgColorDefault 123 | let padding = paddingDefault 124 | if (binding.value.word != undefined) { 125 | word = binding.value.word 126 | } 127 | if (binding.value.live != undefined) { 128 | pattern = selectPattern(word, binding.value.live) 129 | } 130 | if(binding.value.style != undefined) { 131 | color = testTextColor(binding.value.style.color) 132 | bgColor = testBgColor(binding.value.style.bgColor) 133 | padding = testPadding(binding.value.style.padding) 134 | } 135 | el.innerHTML = highlight(originalContent, word, pattern, color, bgColor, padding) 136 | 137 | }, 138 | update(el, binding, vnode, oldVnode) { 139 | let pattern = '' 140 | let color = textColorDefault 141 | let bgColor = bgColorDefault 142 | let padding = paddingDefault 143 | if (binding.value.style != undefined) { 144 | color = testTextColor(binding.value.style.color) 145 | bgColor = testBgColor(binding.value.style.bgColor) 146 | padding = testPadding(binding.value.style.padding) 147 | } 148 | if (binding.value.live) { 149 | pattern = selectPattern(binding.value.word,binding.value.live) 150 | el.innerHTML = highlight(vnode.children[0].text, binding.value.word, pattern, color, bgColor, padding) 151 | } 152 | else{ 153 | pattern = selectPattern(binding.value.word) 154 | el.innerHTML = highlight(originalContent, binding.value.word, pattern, color, bgColor, padding) 155 | } 156 | }, 157 | unbind(el, binding, vnode) { 158 | el.innerHTML = originalContent 159 | } 160 | } 161 | 162 | export default vueHighlighter 163 | -------------------------------------------------------------------------------- /src/highlighter.test.js: -------------------------------------------------------------------------------- 1 | import { shallow, createLocalVue } from "@vue/test-utils" 2 | 3 | import vueHighlighter from './highlighter'; 4 | import sinon from 'sinon' 5 | 6 | describe('Default Behaviour',() => { 7 | const Component = { 8 | template: '

Hello World

' 9 | } 10 | 11 | const localVue = createLocalVue() 12 | 13 | localVue.directive('highlight', vueHighlighter) 14 | 15 | const wrapper = shallow(Component, { 16 | localVue, 17 | data: { 18 | word: '', 19 | live: false 20 | }, 21 | }) 22 | 23 | it('Empty word', () => { 24 | wrapper.setData({ word: '' }) 25 | expect(wrapper.html()).toBe('

Hello World

') 26 | }) 27 | 28 | it('Contained word', () => { 29 | wrapper.setData({ word: 'World' }) 30 | expect(wrapper.html()).toBe( 31 | '

Hello World

' 32 | ) 33 | }) 34 | 35 | it('Not contained word', () => { 36 | wrapper.setData({ word: 'Giulio' }) 37 | expect(wrapper.html()).toBe('

Hello World

') 38 | }) 39 | }) 40 | 41 | describe('Live Behaviour',() => { 42 | const Component = { 43 | template: '

Hello World

' 44 | } 45 | 46 | const localVue = createLocalVue() 47 | 48 | localVue.directive('highlight', vueHighlighter) 49 | 50 | const wrapper = shallow(Component, { 51 | localVue, 52 | data: { 53 | word: '', 54 | live: true 55 | }, 56 | }) 57 | 58 | it('Empty word', () => { 59 | wrapper.setData({ word: '' }) 60 | expect(wrapper.html()).toBe('

Hello World

') 61 | }) 62 | 63 | it('Contained word', () => { 64 | wrapper.setData({ word: 'World' }) 65 | expect(wrapper.html()).toBe( 66 | '

Hello World

' 67 | ) 68 | }) 69 | 70 | it('Not contained word', () => { 71 | wrapper.setData({ word: 'Giulio' }) 72 | expect(wrapper.html()).toBe('

Hello World

') 73 | }) 74 | 75 | it('Contained substring', () => { 76 | wrapper.setData({ word: 'ell' }) 77 | expect(wrapper.html()).toBe('

Hello World

') 78 | }) 79 | 80 | }) 81 | 82 | describe('Live Behaviour - False -> True', () => { 83 | const Component = { 84 | template: '

Hello World

' 85 | } 86 | 87 | const localVue = createLocalVue() 88 | 89 | localVue.directive('highlight', vueHighlighter) 90 | 91 | const wrapper = shallow(Component, { 92 | localVue, 93 | data: { 94 | word: '', 95 | live: false 96 | }, 97 | }) 98 | 99 | beforeEach(() => { 100 | wrapper.setData({ live: false }) 101 | }) 102 | 103 | it('Empty word', () => { 104 | wrapper.setData({ word: '' }) 105 | wrapper.setData({ live: true }) 106 | expect(wrapper.html()).toBe('

Hello World

') 107 | }) 108 | 109 | it('Contained word', () => { 110 | wrapper.setData({ word: 'World' }) 111 | expect(wrapper.html()).toBe( 112 | '

Hello World

' 113 | ) 114 | wrapper.setData({ live: true }) 115 | expect(wrapper.html()).toBe( 116 | '

Hello World

' 117 | ) 118 | }) 119 | 120 | it('Not contained word', () => { 121 | wrapper.setData({ word: 'Giulio' }) 122 | expect(wrapper.html()).toBe('

Hello World

') 123 | wrapper.setData({ live: true }) 124 | expect(wrapper.html()).toBe('

Hello World

') 125 | }) 126 | 127 | it('Contained substring', () => { 128 | wrapper.setData({ word: 'ell' }) 129 | expect(wrapper.html()).toBe('

Hello World

') 130 | wrapper.setData({ live: true }) 131 | expect(wrapper.html()).toBe('

Hello World

') 132 | }) 133 | 134 | }) 135 | 136 | describe('Live Behaviour - True -> False', () => { 137 | const Component = { 138 | template: '

Hello World

' 139 | } 140 | 141 | const localVue = createLocalVue() 142 | 143 | localVue.directive('highlight', vueHighlighter) 144 | 145 | const wrapper = shallow(Component, { 146 | localVue, 147 | data: { 148 | word: '', 149 | live: true 150 | }, 151 | }) 152 | 153 | beforeEach(() => { 154 | wrapper.setData({ live: true }) 155 | }) 156 | 157 | it('Empty word', () => { 158 | wrapper.setData({ word: '' }) 159 | wrapper.setData({ live: true }) 160 | expect(wrapper.html()).toBe('

Hello World

') 161 | }) 162 | 163 | it('Contained word', () => { 164 | wrapper.setData({ word: 'World' }) 165 | expect(wrapper.html()).toBe( 166 | '

Hello World

' 167 | ) 168 | wrapper.setData({ live: false }) 169 | expect(wrapper.html()).toBe( 170 | '

Hello World

' 171 | ) 172 | }) 173 | 174 | it('Not contained word', () => { 175 | wrapper.setData({ word: 'Giulio' }) 176 | expect(wrapper.html()).toBe('

Hello World

') 177 | wrapper.setData({ live: false }) 178 | expect(wrapper.html()).toBe('

Hello World

') 179 | }) 180 | 181 | it('Contained substring', () => { 182 | wrapper.setData({ word: 'ell' }) 183 | expect(wrapper.html()).toBe('

Hello World

') 184 | wrapper.setData({ live: false }) 185 | expect(wrapper.html()).toBe('

Hello World

') 186 | }) 187 | 188 | }) 189 | 190 | describe('Default Word List Behaviour',() => { 191 | const Component = { 192 | template: '

Hello World, highlight me!

' 193 | } 194 | 195 | const localVue = createLocalVue() 196 | 197 | localVue.directive('highlight', vueHighlighter) 198 | 199 | let wrapper 200 | beforeEach(() => { 201 | wrapper = shallow(Component, { 202 | localVue, 203 | data: { 204 | wordList: [], 205 | live: false 206 | } 207 | }) 208 | }) 209 | 210 | it('Empty list', () => { 211 | wrapper.setData({ wordList: [] }) 212 | expect(wrapper.html()).toBe('

Hello World, highlight me!

') 213 | }) 214 | 215 | it('List with empty word', () => { 216 | wrapper.setData({ wordList: [''] }) 217 | expect(wrapper.html()).toBe('

Hello World, highlight me!

') 218 | }) 219 | 220 | it('List of words', () => { 221 | wrapper.setData({ wordList: ['Hello', 'World', 'highlight me', 'I\'m not here'] }) 222 | expect(wrapper.html()).toBe( 223 | '

Hello World, highlight me!

' 224 | ) 225 | }) 226 | 227 | it('Not contained word', () => { 228 | wrapper.setData({ wordList: ['Not', 'Present', 'In', 'List'] }) 229 | expect(wrapper.html()).toBe('

Hello World, highlight me!

') 230 | }) 231 | }) 232 | 233 | describe('Unbind Directive',() => { 234 | const Component = { 235 | template: '

Hello World

' 236 | } 237 | 238 | const localVue = createLocalVue() 239 | 240 | localVue.directive('highlight', vueHighlighter) 241 | const spy = sinon.stub() 242 | 243 | const wrapper = shallow(Component, { 244 | localVue, 245 | data: { 246 | word: 'Hello', 247 | live: true 248 | }, 249 | destroyed() { 250 | spy() 251 | } 252 | }).destroy() 253 | 254 | it('Method called on destroy', () => { 255 | expect(spy.calledOnce).toBe(true) 256 | }) 257 | 258 | }) 259 | 260 | describe('Custom color of text',() => { 261 | const Component = { 262 | template: '

Hello World

' 263 | } 264 | 265 | const localVue = createLocalVue() 266 | 267 | localVue.directive('highlight', vueHighlighter) 268 | 269 | const wrapper = shallow(Component, { 270 | localVue, 271 | data: { 272 | word: 'Hello', 273 | live: true, 274 | style: { 275 | color: '' 276 | } 277 | } 278 | }) 279 | 280 | it('Default color of text', () => { 281 | expect(wrapper.html()).toBe('

Hello World

') 282 | }) 283 | 284 | it('Custom color of text as hex', () => { 285 | wrapper.setData({ 286 | style: { 287 | color: '#000000' 288 | } 289 | }) 290 | expect(wrapper.html()).toBe('

Hello World

') 291 | }) 292 | 293 | it('Custom color of text as word', () => { 294 | wrapper.setData({ 295 | style: { 296 | color: 'white' 297 | } 298 | }) 299 | expect(wrapper.html()).toBe('

Hello World

') 300 | }) 301 | 302 | it('Wrong custom text color', () => { 303 | wrapper.setData({ 304 | style: { 305 | color: 'e54%' 306 | } 307 | }) 308 | expect(wrapper.html()).toBe('

Hello World

') 309 | }) 310 | 311 | it('Change color : wrong to correct', () => { 312 | wrapper.setData({ 313 | style: { 314 | color: 'e54%' 315 | } 316 | }) 317 | expect(wrapper.html()).toBe('

Hello World

') 318 | wrapper.setData({ 319 | style: { 320 | color: '#ffddee' 321 | } 322 | }) 323 | expect(wrapper.html()).toBe('

Hello World

') 324 | }) 325 | 326 | it('Change color : correct to wrong', () => { 327 | wrapper.setData({ 328 | style: { 329 | color: '#ffddee' 330 | } 331 | }) 332 | expect(wrapper.html()).toBe('

Hello World

') 333 | wrapper.setData({ 334 | style: { 335 | color: 'e54%' 336 | } 337 | }) 338 | expect(wrapper.html()).toBe('

Hello World

') 339 | }) 340 | }) 341 | 342 | 343 | describe('Custom color of background', () => { 344 | const Component = { 345 | template: '

Hello World

' 346 | } 347 | 348 | const localVue = createLocalVue() 349 | 350 | localVue.directive('highlight', vueHighlighter) 351 | 352 | const wrapper = shallow(Component, { 353 | localVue, 354 | data: { 355 | word: 'Hello', 356 | live: true, 357 | style: { 358 | bgColor: '' 359 | } 360 | } 361 | }) 362 | 363 | it('Default color of background', () => { 364 | expect(wrapper.html()).toBe('

Hello World

') 365 | }) 366 | 367 | it('Custom color of background as hex', () => { 368 | wrapper.setData({ 369 | style: { 370 | bgColor: '#000000' 371 | } 372 | }) 373 | expect(wrapper.html()).toBe('

Hello World

') 374 | }) 375 | 376 | it('Custom color of background as word', () => { 377 | wrapper.setData({ 378 | style: { 379 | bgColor: 'white' 380 | } 381 | }) 382 | expect(wrapper.html()).toBe('

Hello World

') 383 | }) 384 | 385 | it('Wrong custom background color', () => { 386 | wrapper.setData({ 387 | style: { 388 | bgColor: 'e54%' 389 | } 390 | }) 391 | expect(wrapper.html()).toBe('

Hello World

') 392 | }) 393 | 394 | it('Change color : wrong to correct', () => { 395 | wrapper.setData({ 396 | style: { 397 | bgColor: 'e54%' 398 | } 399 | }) 400 | expect(wrapper.html()).toBe('

Hello World

') 401 | wrapper.setData({ 402 | style: { 403 | bgColor: '#ffddee' 404 | } 405 | }) 406 | expect(wrapper.html()).toBe('

Hello World

') 407 | }) 408 | 409 | it('Change color : correct to wrong', () => { 410 | wrapper.setData({ 411 | style: { 412 | bgColor: '#ffddee' 413 | } 414 | }) 415 | expect(wrapper.html()).toBe('

Hello World

') 416 | wrapper.setData({ 417 | style: { 418 | bgColor: 'e54%' 419 | } 420 | }) 421 | expect(wrapper.html()).toBe('

Hello World

') 422 | }) 423 | }) 424 | 425 | describe('Custom Text and Background color', () => { 426 | const Component = { 427 | template: '

Hello World

' 428 | } 429 | 430 | const localVue = createLocalVue() 431 | 432 | localVue.directive('highlight', vueHighlighter) 433 | 434 | const wrapper = shallow(Component, { 435 | localVue, 436 | data: { 437 | word: 'Hello', 438 | live: true, 439 | style: { 440 | color: '', 441 | bgColor: '' 442 | } 443 | } 444 | }) 445 | 446 | it('Default color', () => { 447 | expect(wrapper.html()).toBe('

Hello World

') 448 | }) 449 | 450 | it('Custom color hex', () => { 451 | wrapper.setData({ 452 | style: { 453 | color: '#111', 454 | bgColor: '#000000' 455 | } 456 | }) 457 | expect(wrapper.html()).toBe('

Hello World

') 458 | }) 459 | 460 | it('Custom color as word', () => { 461 | wrapper.setData({ 462 | style: { 463 | color: 'white', 464 | bgColor: 'white' 465 | } 466 | }) 467 | expect(wrapper.html()).toBe('

Hello World

') 468 | }) 469 | 470 | it('Wrong custom background color', () => { 471 | wrapper.setData({ 472 | style: { 473 | color: '#fee', 474 | bgColor: 'e54%' 475 | } 476 | }) 477 | expect(wrapper.html()).toBe('

Hello World

') 478 | }) 479 | 480 | it('Wrong custom text color', () => { 481 | wrapper.setData({ 482 | style: { 483 | color: '#e54%', 484 | bgColor: '#fee' 485 | } 486 | }) 487 | expect(wrapper.html()).toBe('

Hello World

') 488 | }) 489 | }) 490 | 491 | describe('Custom Padding', () => { 492 | const Component = { 493 | template: '

Hello World

' 494 | } 495 | 496 | const localVue = createLocalVue() 497 | 498 | localVue.directive('highlight', vueHighlighter) 499 | 500 | const wrapper = shallow(Component, { 501 | localVue, 502 | data: { 503 | word: 'Hello', 504 | live: true, 505 | style: { 506 | padding: '' 507 | } 508 | } 509 | }) 510 | 511 | it('Default padding', () => { 512 | expect(wrapper.html()).toBe('

Hello World

') 513 | }) 514 | 515 | it('Custom padding - 1 value', () => { 516 | wrapper.setData({ 517 | style: { 518 | padding: '1px' 519 | } 520 | }) 521 | expect(wrapper.html()).toBe('

Hello World

') 522 | }) 523 | 524 | it('Custom padding - 2 value', () => { 525 | wrapper.setData({ 526 | style: { 527 | padding: '1px 2px' 528 | } 529 | }) 530 | expect(wrapper.html()).toBe('

Hello World

') 531 | }) 532 | 533 | it('Custom padding - 3 value', () => { 534 | wrapper.setData({ 535 | style: { 536 | padding: '1px 2px 3px' 537 | } 538 | }) 539 | expect(wrapper.html()).toBe('

Hello World

') 540 | }) 541 | 542 | it('Custom padding - 4 value', () => { 543 | wrapper.setData({ 544 | style: { 545 | padding: '1px 2px 3px 4px' 546 | } 547 | }) 548 | expect(wrapper.html()).toBe('

Hello World

') 549 | }) 550 | 551 | it('Wrong Padding', () => { 552 | wrapper.setData({ 553 | style: { 554 | padding: 'ooo' 555 | } 556 | }) 557 | expect(wrapper.html()).toBe('

Hello World

') 558 | }) 559 | 560 | it('Custom Padding - %', () => { 561 | wrapper.setData({ 562 | style: { 563 | padding: '5%' 564 | } 565 | }) 566 | expect(wrapper.html()).toBe('

Hello World

') 567 | }) 568 | 569 | it('Change padding : wrong to correct', () => { 570 | wrapper.setData({ 571 | style: { 572 | padding: 'ooo' 573 | } 574 | }) 575 | expect(wrapper.html()).toBe('

Hello World

') 576 | wrapper.setData({ 577 | style:{ 578 | padding: '4rem' 579 | } 580 | }) 581 | expect(wrapper.html()).toBe('

Hello World

') 582 | }) 583 | 584 | it('Change padding : correct to wrong', () => { 585 | wrapper.setData({ 586 | style: { 587 | padding: '4rem' 588 | } 589 | }) 590 | expect(wrapper.html()).toBe('

Hello World

') 591 | 592 | wrapper.setData({ 593 | style:{ 594 | padding: 'ooo' 595 | } 596 | }) 597 | expect(wrapper.html()).toBe('

Hello World

') 598 | 599 | }) 600 | 601 | }) 602 | 603 | describe('Empty Behaviuor',() => { 604 | const Component = { 605 | template: '

Hello World

' 606 | } 607 | 608 | const localVue = createLocalVue() 609 | 610 | localVue.directive('highlight', vueHighlighter) 611 | 612 | const wrapper = shallow(Component, { 613 | localVue, 614 | data: { 615 | } 616 | }) 617 | 618 | it('Without Attribute', () => { 619 | expect(wrapper.html()).toBe('

Hello World

') 620 | }) 621 | }) 622 | 623 | 624 | describe('Without Directive', () => { 625 | const Component = { 626 | template: '

Hello World

' 627 | } 628 | 629 | const localVue = createLocalVue() 630 | 631 | localVue.directive('highlight', vueHighlighter) 632 | 633 | const wrapper = shallow(Component, { 634 | localVue, 635 | data: { 636 | } 637 | }) 638 | 639 | it('Without Attribute', () => { 640 | expect(wrapper.html()).toBe('

Hello World

') 641 | }) 642 | }) 643 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | 2 | import highlight from './highlighter' 3 | 4 | const Plugin = { 5 | install(Vue, options) { 6 | Vue.directive('highlight', highlight) 7 | } 8 | } 9 | 10 | export default Plugin 11 | 12 | export { 13 | highlight 14 | } 15 | 16 | // Install by default 17 | if (typeof window !== 'undefined' && window.Vue) { 18 | window.Vue.use(Plugin) 19 | } 20 | -------------------------------------------------------------------------------- /src/index.test.js: -------------------------------------------------------------------------------- 1 | import { shallow, createLocalVue } from '@vue/test-utils' 2 | 3 | import VueHighlighter from './index' 4 | import { highlight } from './index' 5 | 6 | describe('Plugin', () => { 7 | 8 | const Component = { 9 | template: '

Hello World

' 10 | } 11 | 12 | it('Add plugin', () => { 13 | const localVue = createLocalVue() 14 | localVue.use(VueHighlighter) 15 | expect(localVue.options.directives).toHaveProperty('highlight') 16 | }) 17 | 18 | it('Add directive', () => { 19 | const wrapper = shallow(Component, { 20 | directives: { 21 | highlight 22 | }, 23 | data: { 24 | word: '', 25 | live: false 26 | } 27 | }) 28 | expect(wrapper.vm.$options.directives).toHaveProperty('highlight') 29 | }) 30 | 31 | }) 32 | --------------------------------------------------------------------------------