├── .gitignore ├── README.md ├── package.json ├── LICENSE ├── index.coffee └── transform.coffee /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/**/* 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # html-to-react-native 2 | Transform HTML to a well formatted React Native JSX Code using and tags. 3 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "html-to-react-native", 3 | "version": "1.0.0", 4 | "description": "Transform HTML to a well formatted React Native JSX Code", 5 | "main": "index.coffee", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/miduga/html-to-react-native.git" 12 | }, 13 | "keywords": [ 14 | "text", 15 | "react", 16 | "native", 17 | "parse", 18 | "html" 19 | ], 20 | "author": "Miguel Ángel Durán (http://miduga.es)", 21 | "license": "ISC", 22 | "bugs": { 23 | "url": "https://github.com/miduga/html-to-react-native/issues" 24 | }, 25 | "homepage": "https://github.com/miduga/html-to-react-native#readme", 26 | "dependencies": { 27 | "htmlparser": "^1.7.7", 28 | "react-native": "^0.11.0", 29 | "underscore": "^1.8.3", 30 | "underscore.string": "^3.2.2" 31 | }, 32 | "peerDependencies": { 33 | "react-native": "^0.11.0" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2015 Miguel Ángel Durán García http://miduga.es 4 | 5 | Permission is hereby granted, free of charge, to any person 6 | obtaining a copy of this software and associated documentation 7 | files (the "Software"), to deal in the Software without 8 | restriction, including without limitation the rights to use, 9 | copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the 11 | Software is furnished to do so, subject to the following 12 | conditions: 13 | 14 | The above copyright notice and this permission notice shall be 15 | included in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 19 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 21 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 22 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 24 | OTHER DEALINGS IN THE SOFTWARE. 25 | -------------------------------------------------------------------------------- /index.coffee: -------------------------------------------------------------------------------- 1 | util = require 'util' 2 | _ = require 'underscore' 3 | _s = require 'underscore.string' 4 | htmlparser = require 'htmlparser' 5 | 6 | helper = require './helper' 7 | transform = null 8 | 9 | # TAGS THAT WE SHOULD SKIP 10 | TYPES_TO_SKIP = [ 'style', 'script' ] 11 | 12 | convertHTMLToReactNative = ( html ) -> 13 | 14 | defaultHandlerFunction = ( err, dom ) -> return 15 | 16 | handler = new htmlparser.DefaultHandler defaultHandlerFunction, { 17 | verbose: true, 18 | ignoreWhitespace: true 19 | } 20 | 21 | transform = require( './transform' )( transformHTMLTags ) 22 | 23 | new htmlparser.Parser( handler ).parseComplete( html ) 24 | filteredDOM = filterDOM( handler.dom ) 25 | result = transformHTMLTags( filteredDOM ) 26 | _s.trim( result ) 27 | 28 | filterDOM = ( dom ) -> 29 | dom[0].children 30 | 31 | checkIfNeedsSpace = ( result ) -> 32 | whiteSpaceRegex = /\S$/ 33 | whiteSpaceRegex.test( result ) 34 | 35 | handleText = ( el, result ) -> 36 | el.needsSpace = checkIfNeedsSpace( result ) 37 | transform.text( el ) 38 | 39 | handleTag = ( el, tag, result, style ) -> 40 | switch tag 41 | when 'img' 42 | transform.image( el ) 43 | when 'a' 44 | elem.needsSpace = checkIfNeedsSpace( result ) 45 | transform.link( el ) 46 | when 'p' 47 | transform.paragraph( el ) 48 | when 'li' 49 | transform.list( el ) 50 | when 'h1', 'h2', 'h3', 'h4' 51 | transform.heading( el ) 52 | when 'br' 53 | transform.lineBreak( el ) 54 | when 'hr' 55 | transform.horizontalLine( el ) 56 | when 'strong', 'b', 'bold' 57 | transform.bold( el ) 58 | else 59 | { children = [] } = el 60 | transformHTMLTags( children, result ) 61 | 62 | transformHTMLTags = ( dom, result = '', style = {} ) -> 63 | # check for each element on the DOM the tag 64 | _.each dom, ( el ) -> 65 | { type, raw, name, children = [] } = el 66 | if type is 'text' and raw isnt '\r\n' 67 | result += handleText( el ) 68 | else if type is 'tag' 69 | tag = name.toLowerCase() 70 | if tag in [ 'a', 'p', 'li', 'h1', 'h2', 'h3', 'h4', 'br', 'hr', 'img', 'bold', 'strong', 'b' ] 71 | result += handleTag( el, tag, result ) 72 | else 73 | result = handleTag( el, tag, result ) 74 | else 75 | if !_.include( TYPES_TO_SKIP, type ) 76 | result = transformHTMLTags( children, result ) 77 | # return the result that we have so far 78 | return result 79 | 80 | exports.fromString = (str) -> 81 | return htmlToText(str || {}) 82 | -------------------------------------------------------------------------------- /transform.coffee: -------------------------------------------------------------------------------- 1 | _s = require 'underscore.string' 2 | 3 | HTMLEntities = { 4 | apos:0x0027,quot:0x0022,amp:0x0026,lt:0x003C,gt:0x003E,nbsp:0x00A0,iexcl:0x00A1,cent:0x00A2,pound:0x00A3, 5 | curren:0x00A4,yen:0x00A5,brvbar:0x00A6,sect:0x00A7,uml:0x00A8,copy:0x00A9,ordf:0x00AA,laquo:0x00AB, 6 | not:0x00AC,shy:0x00AD,reg:0x00AE,macr:0x00AF,deg:0x00B0,plusmn:0x00B1,sup2:0x00B2,sup3:0x00B3, 7 | acute:0x00B4,micro:0x00B5,para:0x00B6,middot:0x00B7,cedil:0x00B8,sup1:0x00B9,ordm:0x00BA,raquo:0x00BB, 8 | frac14:0x00BC,frac12:0x00BD,frac34:0x00BE,iquest:0x00BF,Agrave:0x00C0,Aacute:0x00C1,Acirc:0x00C2,Atilde:0x00C3, 9 | Auml:0x00C4,Aring:0x00C5,AElig:0x00C6,Ccedil:0x00C7,Egrave:0x00C8,Eacute:0x00C9,Ecirc:0x00CA,Euml:0x00CB, 10 | Igrave:0x00CC,Iacute:0x00CD,Icirc:0x00CE,Iuml:0x00CF,ETH:0x00D0,Ntilde:0x00D1,Ograve:0x00D2,Oacute:0x00D3, 11 | Ocirc:0x00D4,Otilde:0x00D5,Ouml:0x00D6,times:0x00D7,Oslash:0x00D8,Ugrave:0x00D9,Uacute:0x00DA,Ucirc:0x00DB, 12 | Uuml:0x00DC,Yacute:0x00DD,THORN:0x00DE,szlig:0x00DF,agrave:0x00E0,aacute:0x00E1,acirc:0x00E2,atilde:0x00E3, 13 | auml:0x00E4,aring:0x00E5,aelig:0x00E6,ccedil:0x00E7,egrave:0x00E8,eacute:0x00E9,ecirc:0x00EA,euml:0x00EB, 14 | igrave:0x00EC,iacute:0x00ED,icirc:0x00EE,iuml:0x00EF,eth:0x00F0,ntilde:0x00F1,ograve:0x00F2,oacute:0x00F3, 15 | ocirc:0x00F4,otilde:0x00F5,ouml:0x00F6,divide:0x00F7,oslash:0x00F8,ugrave:0x00F9,uacute:0x00FA,ucirc:0x00FB, 16 | uuml:0x00FC,yacute:0x00FD,thorn:0x00FE,yuml:0x00FF,OElig:0x0152,oelig:0x0153,Scaron:0x0160,scaron:0x0161, 17 | Yuml:0x0178,fnof:0x0192,circ:0x02C6,tilde:0x02DC,Alpha:0x0391,Beta:0x0392,Gamma:0x0393,Delta:0x0394, 18 | Epsilon:0x0395,Zeta:0x0396,Eta:0x0397,Theta:0x0398,Iota:0x0399,Kappa:0x039A,Lambda:0x039B,Mu:0x039C, 19 | Nu:0x039D,Xi:0x039E,Omicron:0x039F,Pi:0x03A0,Rho:0x03A1,Sigma:0x03A3,Tau:0x03A4,Upsilon:0x03A5, 20 | Phi:0x03A6,Chi:0x03A7,Psi:0x03A8,Omega:0x03A9,alpha:0x03B1,beta:0x03B2,gamma:0x03B3,delta:0x03B4, 21 | epsilon:0x03B5,zeta:0x03B6,eta:0x03B7,theta:0x03B8,iota:0x03B9,kappa:0x03BA,lambda:0x03BB,mu:0x03BC, 22 | nu:0x03BD,xi:0x03BE,omicron:0x03BF,pi:0x03C0,rho:0x03C1,sigmaf:0x03C2,sigma:0x03C3,tau:0x03C4, 23 | upsilon:0x03C5,phi:0x03C6,chi:0x03C7,psi:0x03C8,omega:0x03C9,thetasym:0x03D1,upsih:0x03D2,piv:0x03D6, 24 | ensp:0x2002,emsp:0x2003,thinsp:0x2009,zwnj:0x200C,zwj:0x200D,lrm:0x200E,rlm:0x200F,ndash:0x2013, 25 | mdash:0x2014,lsquo:0x2018,rsquo:0x2019,sbquo:0x201A,ldquo:0x201C,rdquo:0x201D,bdquo:0x201E,dagger:0x2020, 26 | Dagger:0x2021,bull:0x2022,hellip:0x2026,permil:0x2030,prime:0x2032,Prime:0x2033,lsaquo:0x2039,rsaquo:0x203A, 27 | oline:0x203E,frasl:0x2044,euro:0x20AC,image:0x2111,weierp:0x2118,real:0x211C,trade:0x2122,alefsym:0x2135, 28 | larr:0x2190,uarr:0x2191,rarr:0x2192,darr:0x2193,harr:0x2194,crarr:0x21B5,lArr:0x21D0,uArr:0x21D1, 29 | rArr:0x21D2,dArr:0x21D3,hArr:0x21D4,forall:0x2200,part:0x2202,exist:0x2203,empty:0x2205,nabla:0x2207, 30 | isin:0x2208,notin:0x2209,ni:0x220B,prod:0x220F,sum:0x2211,minus:0x2212,lowast:0x2217,radic:0x221A, 31 | prop:0x221D,infin:0x221E,ang:0x2220,and:0x2227,or:0x2228,cap:0x2229,cup:0x222A,"int":0x222B, 32 | there4:0x2234,sim:0x223C,cong:0x2245,asymp:0x2248,ne:0x2260,equiv:0x2261,le:0x2264,ge:0x2265, 33 | sub:0x2282,sup:0x2283,nsub:0x2284,sube:0x2286,supe:0x2287,oplus:0x2295,otimes:0x2297,perp:0x22A5, 34 | sdot:0x22C5,lceil:0x2308,rceil:0x2309,lfloor:0x230A,rfloor:0x230B,lang:0x2329,rang:0x232A,loz:0x25CA, 35 | spades:0x2660,clubs:0x2663,hearts:0x2665,diams:0x2666 36 | }; 37 | 38 | `decodeHTMLEntities = function decodeHTMLEntities(text) { 39 | return text.replace(/&(.+?);/g, function(str, ent) { 40 | return String.fromCharCode(ent[0] !== '#' ? HTMLEntities[ent] : ent[1] === 'x' ? parseInt(ent.substr(2),16) : parseInt(ent.substr(1), 10)); 41 | }); 42 | };` 43 | 44 | Transform = ( fn ) -> 45 | 46 | return { 47 | 48 | text : ( el, style = {} ) -> 49 | text = decodeHTMLEntities( _s.strip( el.raw ) ) 50 | "#{text}" 51 | 52 | image : ( el ) -> 53 | if el.src? then "" 54 | else "" 55 | 56 | bold : ( el ) -> 57 | fn( el.children, '', { fontWeight: 'bold' } ) 58 | 59 | paragraph : ( el ) -> 60 | style = { fontWeight: '200', color: '#111' } 61 | fn( el.children, '', style ) + '\n\n' 62 | 63 | heading : ( el ) -> 64 | style = { fontSize: 20, fontWeight: '200', color: '#111' } 65 | fn( el.children, style ) 66 | 67 | link : ( el ) -> 68 | fn( el.children ) 69 | 70 | list : ( el ) -> 71 | fn( el.children ) 72 | 73 | horizontalLine : ( el ) -> 74 | console.log el 75 | fn( el.children ) + '\n\n' 76 | # console.log walk 77 | } 78 | 79 | module.exports = Transform 80 | --------------------------------------------------------------------------------