From 4d92770c9f2447be48380045bd197d98819dc7b3 Mon Sep 17 00:00:00 2001 From: Skial Bainn Date: Sat, 25 Jun 2016 13:59:58 +0100 Subject: [PATCH] Add out bound link tracking. --- all-html.sh | 2 +- buildjs.sh | 1 + electron-checkmissing/CheckMissing.hx | 81 +++++++++++++++++++-------- electron-version/Version.hx | 71 ++++++++++++----------- htmlmin.sh | 2 +- jsmin.sh | 32 +++++++++++ package.json | 12 +++- 7 files changed, 138 insertions(+), 63 deletions(-) create mode 100644 buildjs.sh create mode 100644 jsmin.sh diff --git a/all-html.sh b/all-html.sh index 8307488a..97742d27 100644 --- a/all-html.sh +++ b/all-html.sh @@ -1,4 +1,4 @@ INPUT="$@" electron --enable-logging . -w 1920 -h 1080 --input "//$INPUT/index.html" --script ./script.js --outputDir "//bin" --show \ ---scripts linkqueue.js font.characters.js sitemap.js checkmissing.js screengrab.js version.js +--scripts linkqueue.js checkmissing.js font.characters.js sitemap.js screengrab.js version.js find $INPUT -name "*.html" | xargs -P 6 -n 1 htmlmin.sh diff --git a/buildjs.sh b/buildjs.sh new file mode 100644 index 00000000..21e70c1c --- /dev/null +++ b/buildjs.sh @@ -0,0 +1 @@ +browserify ./node_modules/autotrack/lib/plugins/outbound-link-tracker.js > ./src/js/outbound-link-tracker.js diff --git a/electron-checkmissing/CheckMissing.hx b/electron-checkmissing/CheckMissing.hx index aea711de..b08108d4 100644 --- a/electron-checkmissing/CheckMissing.hx +++ b/electron-checkmissing/CheckMissing.hx @@ -28,47 +28,66 @@ class CheckMissing { ipcRenderer = electron.ipcRenderer; var head = cast window.document.getElementsByTagName( 'head' )[0]; - //var script = window.document.querySelectorAll( 'head script[src*="haxe.io.js"]' )[0]; - var tags:Array> = [ - [{tag:'link', rel:'apple-touch-icon', sizes:'57x57'/*, href:"/apple-touch-icon-57x57.png"*/}, {href:"/apple-touch-icon-57x57.png?v=wAANbdxLQn"}], - [{tag:'link', rel:'apple-touch-icon', sizes:'60x60'/*, href:"/apple-touch-icon-60x60.png"*/}, {href:"/apple-touch-icon-60x60.png?v=wAANbdxLQn"}], - [{tag:'link', rel:'apple-touch-icon', sizes:'72x72'/*, href:"/apple-touch-icon-72x72.png"*/}, {href:"/apple-touch-icon-72x72.png?v=wAANbdxLQn"}], - [{tag:'link', rel:'apple-touch-icon', sizes:'76x76'/*, href:"/apple-touch-icon-76x76.png"*/}, {href:"/apple-touch-icon-76x76.png?v=wAANbdxLQn"}], - [{tag:'link', rel:'apple-touch-icon', sizes:'114x114'/*, href:"/apple-touch-icon-114x114.png"*/}, {href:"/apple-touch-icon-114x114.png?v=wAANbdxLQn"}], - [{tag:'link', rel:'apple-touch-icon', sizes:'120x120'/*, href:"/apple-touch-icon-120x120.png"*/}, {href:"/apple-touch-icon-120x120.png?v=wAANbdxLQn"}], - [{tag:'link', rel:'apple-touch-icon', sizes:'144x144'/*, href:"/apple-touch-icon-144x144.png"*/}, {href:"/apple-touch-icon-144x144.png?v=wAANbdxLQn"}], - [{tag:'link', rel:'apple-touch-icon', sizes:'152x152'/*, href:"/apple-touch-icon-152x152.png"*/}, {href:"/apple-touch-icon-152x152.png?v=wAANbdxLQn"}], - [{tag:'link', rel:'apple-touch-icon', sizes:'180x180'/*, href:"/apple-touch-icon-180x180.png"*/}, {href:"/apple-touch-icon-180x180.png?v=wAANbdxLQn"}], - [{tag:'link', rel:'icon', type:"image/png", sizes:'16x16'/*, href:"/favicon-16x16.png"*/}, {href:"/favicon-16x16.png?v=wAANbdxLQn"}], - [{tag:'link', rel:'icon', type:"image/png", sizes:'32x32'/*, href:"/favicon-32x32.png"*/}, {href:"/favicon-32x32.png?v=wAANbdxLQn"}], - [{tag:'link', rel:'icon', type:"image/png", sizes:'96x96'/*, href:"/favicon-96x96.png"*/}, {href:"/favicon-96x96.png?v=wAANbdxLQn"}], - [{tag:'link', rel:'icon', type:"image/png", sizes:'192x192'/*, href:"/favicon-192x192.png"*/}, {href:"/favicon-192x192.png?v=wAANbdxLQn"}], - [{tag:'link', rel:'icon', type:"image/png", sizes:'194x194'/*, href:"/favicon-194x194.png"*/}, {href:"/favicon-194x194.png?v=wAANbdxLQn"}], - [{tag:'link', rel:'manifest'/*, href:"/manifest.json"*/}, {href:"/manifest.json?v=wAANbdxLQn"}], - [{tag:'link', rel:'mask-icon', color:"#fffdf9", /*href:"/safari-pinned-tab.svg"*/}, {href:"/safari-pinned-tab.svg?v=wAANbdxLQn"}], - [{tag:'link', rel:'shortcut icon'/*, href:"/favicon.ico"*/}, {href:"/favicon.ico?v=wAANbdxLQn"}], + var body = cast window.document.getElementsByTagName( 'body' )[0]; + + var headTags:Array> = [ + [{tag:'link', rel:'apple-touch-icon', sizes:'57x57'}, {href:"/apple-touch-icon-57x57.png?v=wAANbdxLQn"}], + [{tag:'link', rel:'apple-touch-icon', sizes:'60x60'}, {href:"/apple-touch-icon-60x60.png?v=wAANbdxLQn"}], + [{tag:'link', rel:'apple-touch-icon', sizes:'72x72'}, {href:"/apple-touch-icon-72x72.png?v=wAANbdxLQn"}], + [{tag:'link', rel:'apple-touch-icon', sizes:'76x76'}, {href:"/apple-touch-icon-76x76.png?v=wAANbdxLQn"}], + [{tag:'link', rel:'apple-touch-icon', sizes:'114x114'}, {href:"/apple-touch-icon-114x114.png?v=wAANbdxLQn"}], + [{tag:'link', rel:'apple-touch-icon', sizes:'120x120'}, {href:"/apple-touch-icon-120x120.png?v=wAANbdxLQn"}], + [{tag:'link', rel:'apple-touch-icon', sizes:'144x144'}, {href:"/apple-touch-icon-144x144.png?v=wAANbdxLQn"}], + [{tag:'link', rel:'apple-touch-icon', sizes:'152x152'}, {href:"/apple-touch-icon-152x152.png?v=wAANbdxLQn"}], + [{tag:'link', rel:'apple-touch-icon', sizes:'180x180'}, {href:"/apple-touch-icon-180x180.png?v=wAANbdxLQn"}], + [{tag:'link', rel:'icon', type:"image/png", sizes:'16x16'}, {href:"/favicon-16x16.png?v=wAANbdxLQn"}], + [{tag:'link', rel:'icon', type:"image/png", sizes:'32x32'}, {href:"/favicon-32x32.png?v=wAANbdxLQn"}], + [{tag:'link', rel:'icon', type:"image/png", sizes:'96x96'}, {href:"/favicon-96x96.png?v=wAANbdxLQn"}], + [{tag:'link', rel:'icon', type:"image/png", sizes:'192x192'}, {href:"/favicon-192x192.png?v=wAANbdxLQn"}], + [{tag:'link', rel:'icon', type:"image/png", sizes:'194x194'}, {href:"/favicon-194x194.png?v=wAANbdxLQn"}], + [{tag:'link', rel:'manifest'}, {href:"/manifest.json?v=wAANbdxLQn"}], + [{tag:'link', rel:'mask-icon', color:"#fffdf9"}, {href:"/safari-pinned-tab.svg?v=wAANbdxLQn"}], + [{tag:'link', rel:'shortcut icon'}, {href:"/favicon.ico?v=wAANbdxLQn"}], [{tag:'meta', name:'msapplication-TileColor', content:"#f15922"}, {}], - [{tag:'meta', name:'msapplication-TileImage'/*, content:"/mstile-144x144.png"*/}, {content:"/mstile-144x144.png?v=wAANbdxLQn"}], + [{tag:'meta', name:'msapplication-TileImage'}, {content:"/mstile-144x144.png?v=wAANbdxLQn"}], [{tag:'meta', name:'theme-color', content:"#ffffff"}, {}], [{tag:'script', src:'/js/haxe.io.js'}, {async:'async', defer:'defer'}], + [{tag:'script', src:'/js/outbound-link-tracker.js'}, {async:'async', defer:'defer'}], + [{tag:'script', type:'text/javascript'}, {innerHTML:"(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ + (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), + m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) + })(window,document,'script','https://www.google-analytics.com/analytics.js','ga'); + + ga('create', 'UA-49222122-1', 'auto'); + ga('require', 'displayfeatures'); + ga('require', 'outboundLinkTracker'); + ga('set', 'forceSSL', true); + ga('send', 'pageview');"}], ]; - for (array in tags) { + var bodyTags:Array> = [ + //[{tag:'a', href:'://'}, {onclick:"trackOutboundLink('http://www.example.com'); return false;"}] + ]; + + for (array in headTags) { var keys:DynamicAccess = array[0]; var values:DynamicAccess = array[1]; - var selector = keys.get('tag') + [for(key in keys.keys()) if (key != 'tag') '[$key*="${keys.get(key)}"]'].join(''); + var selector = keys.get('tag') + [for(key in keys.keys()) if (key != 'tag' && key != 'innerHTML') '[$key*="${keys.get(key)}"]'].join(''); var matches = window.document.querySelectorAll( selector ); + if (matches.length == 0) { var element:DOMElement = window.document.createElement( keys.get('tag') ); - for (key in keys.keys()) if (key != 'tag') element.setAttribute( key, keys.get( key ) ); + for (key in keys.keys()) if (key != 'tag' && key != 'innerHTML') element.setAttribute( key, keys.get( key ) ); for (key in values.keys()) element.setAttribute( key, values.get( key ) ); + if (values.exists('innerHTML')) element.innerHTML = values.get('innerHTML'); cast(head,Node).appendChild( element ); } else { var element = cast(matches[0],DOMElement); if (element.hasAttribute('contents')) element.removeAttribute('contents'); if (element.hasAttribute('tag')) element.removeAttribute( 'tag' ); - for (key in values.keys()) if (key != 'tag') element.setAttribute( key, values.get( key ) ); + for (key in values.keys()) if (key != 'tag' && key != 'innerHTML') element.setAttribute( key, values.get( key ) ); + if (values.exists('innerHTML')) element.innerHTML = values.get('innerHTML'); for (i in 1...matches.length) { head.removeChild( matches[i] ); } @@ -77,6 +96,20 @@ class CheckMissing { } + for (array in bodyTags) { + var keys:DynamicAccess = array[0]; + var values:DynamicAccess = array[1]; + var selector = keys.get('tag') + [for(key in keys.keys()) if (key != 'tag') '[$key*="${keys.get(key)}"]'].join(''); + var matches = window.document.querySelectorAll( selector ); + + if (matches.length > 0) for (match in matches) { + var element = cast(match,DOMElement); + for (key in values.keys()) if (key != 'tag') element.setAttribute( key, values.get( key ) ); + + } + + } + ipcRenderer.send('checkmissing::complete', 'true'); } diff --git a/electron-version/Version.hx b/electron-version/Version.hx index 60c02766..317e5cd6 100644 --- a/electron-version/Version.hx +++ b/electron-version/Version.hx @@ -21,21 +21,21 @@ using StringTools; using haxe.io.Path; class Version { - + private var electron:Dynamic; private var ipcRenderer:{on:String->Function->Dynamic, once:String->Function->Dynamic, send:String->Rest->Void}; private var hashedPaths:StringMap = new StringMap(); private var input:String = ''; private var counter:Int = 0; - + public static function main() { var v = new Version(); } - + public function new() { electron = require('electron'); ipcRenderer = electron.ipcRenderer; - + ipcRenderer.send('fetch::data', 'version'); ipcRenderer.on('fetched::data::version', function(event:String, arg:String) { var data:{input:String} = Unserializer.run(arg); @@ -43,11 +43,11 @@ class Version { for (node in window.document.querySelectorAll( 'link[href]' )) process('href', cast node); for (node in window.document.querySelectorAll( 'body [src], script[src]' )) process('src', cast node); for (node in window.document.querySelectorAll( 'meta[content*="ms"]' )) process('content', cast node); - + }); - + } - + private function process(attr:String, node:DOMElement):Void { var value:String = node.getAttribute( attr ); trace( value ); @@ -59,14 +59,14 @@ class Version { if ((url.query:DynamicAccess).exists('v')) { Reflect.deleteField(url, 'search'); (url.query:DynamicAccess).remove('v'); - + } - + value = format( url ); trace( format(url).normalize() ); var cb = modifyUrl.bind(node, attr, _, _); hash('content::hash', format(url).normalize(), cb); - + } else { if (url.host != null && url.host.indexOf('haxe.io') > -1) { counter++; @@ -75,50 +75,50 @@ class Version { if ((url.query:DynamicAccess).exists('v')) { Reflect.deleteField(url, 'search'); (url.query:DynamicAccess).remove('v'); - + } url.protocol = url.hostname = url.host = ''; trace( format(url).normalize() ); hash('content::hash', format(url).normalize(), cb); - + } - + } } - + private function modifyUrl(node:DOMElement, attr:String, event:String, arg:String):Void { if (arg != 'failed'){ var value:String = node.getAttribute( attr ); var url = parse( value, true, true ); - + Reflect.deleteField(url, 'search'); if (url.query == null) url.query = {}; if ((url.query:DynamicAccess).exists('v')) { Reflect.deleteField(url, 'search'); (url.query:DynamicAccess).remove('v'); - + } (url.query:DynamicAccess).set('v', arg); //trace( format( url ) ); node.setAttribute( attr, format( url )); - + } else { - trace( event, node.getAttribute(attr) ); + trace( event, arg, node.getAttribute(attr) ); } - + counter--; //trace( counter ); if (counter < 1) ipcRenderer.send('version::complete', 'true'); } - + private function hash(event:String, arg:String, cb:String->String->Void):Void { var path = (__dirname + input.directory() + arg).normalize(); //trace( path.extension() ); if (path.extension() == '') path += '/index.html'; - //trace( path ); + trace( path ); if (hashedPaths.exists(path)) { cb('content::hashed::$arg', hashedPaths.get( path )); - + } else { stat(path, function(error, stats) { if (error == null && stats.isFile()) { @@ -128,30 +128,33 @@ class Version { var data = stream.read(); if (data != null) { hash.update(data); - + } else { - hashedPaths.set( path, hash.digest('hex') ); + var digest = hash.digest('hex'); + + hashedPaths.set( path, digest ); //try { //trace( hashedPaths.get( path )); - cb('content::hashed::$arg', hashedPaths.get( path )); - + cb('content::hashed::$arg', digest); + /*} catch (e:Dynamic) { console.log( path, hashedPaths.get( path ), e ); - + }*/ - + } }); - + } else { + trace( error ); cb('content::hashed::$arg', 'failed'); - + } - + }); - + } - + } - + } diff --git a/htmlmin.sh b/htmlmin.sh index 7a061227..d958c98d 100644 --- a/htmlmin.sh +++ b/htmlmin.sh @@ -74,5 +74,5 @@ cp $MIN $OPT html-minifier \ --collapse-boolean-attributes --remove-comments --remove-empty-attributes --remove-redundant-attributes \ --collapse-whitespace --decode-entities --minify-js --remove-style-link-type-attributes \ ---remove-script-type-attributes --minify-css -o $OPT $OPT_CRIT +--remove-script-type-attributes --minify-css -o "$OPT" "$OPT_CRIT" #zopfli --i1000 $OPT diff --git a/jsmin.sh b/jsmin.sh new file mode 100644 index 00000000..f2e266da --- /dev/null +++ b/jsmin.sh @@ -0,0 +1,32 @@ +CLOSURE=./node_modules/google-closure-compiler/compiler.jar +INPUT="$@" +#echo $INPUT +STR="${INPUT:3}" +BIN=./bin$STR +BIN_DIR=${BIN%/*} +BIN_BASE="${BIN/$BIN_DIR/}" +BIN_BASE="${BIN_BASE/.css/}" + +MIN=./min$STR +MIN_DIR=${MIN%/*} +MIN_BASE="${MIN/$MIN_DIR/}" +MIN_BASE="${MIN_BASE/.js/}" + +OPT=./opt$STR +OPT_DIR=${OPT%/*} +OPT_BASE="${OPT/$OPT_DIR/}" +#echo $BASE +OPT_BASE="${OPT_BASE/.js/}" +OPT_CRIT=$OPT_DIR$OPT_BASE.crt.js +OPT_TWIN=$OPT_DIR$OPT_BASE.opt.js + +mkdir -p $BIN_DIR +mkdir -p $MIN_DIR +mkdir -p $OPT_DIR + +cp $INPUT $BIN +cp $BIN $MIN +cp $MIN $OPT + +java -jar $CLOSURE --js $INPUT --compilation_level SIMPLE_OPTIMIZATIONS --js_output_file $BIN +java -jar $CLOSURE --js $INPUT --compilation_level ADVANCED_OPTIMIZATIONS --js_output_file $OPT diff --git a/package.json b/package.json index 71c4b43c..1e608546 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,7 @@ { "name": "haxe.io", + "repo": "https://github.com/skial/haxe.io", + "version": "0.0.1", "devDependencies": { "onchange": "latest", "http-server": "latest", @@ -12,11 +14,15 @@ "critical": "addyosmani/critical", "node-static": "latest", "electron-prebuilt": "latest", - "electron-spawn": "latest" + "electron-spawn": "latest", + "browserify": "latest", + "autotrack": "latest", + "google-closure-compiler": "latest" }, - "scripts": { + "scripts": { + "watch:jsmin": "onchange \"./src/js/*.js\" -w -- jsmin.sh {{changed}}", "watch:htmlmin": "onchange \"./src/**/*.html\" -w -- htmlmin.sh {{changed}}", "watch:cssmin": "onchange \"./src/css/*.css\" -w -- cssmin.sh {{changed}}", - "watch": "npm-run-all -p watch:cssmin watch:htmlmin" + "watch": "npm-run-all -p watch:jsmin watch:cssmin watch:htmlmin" } }