From 4a4335a86d4c470d54418e757a8adcc1b706df47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Szcz=C4=99=C5=9Bniak-Szlagowski?= Date: Fri, 23 Oct 2015 23:11:38 +0100 Subject: [PATCH 1/7] Get base URL from window.location --- live_editor/scripts/controllers/main.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/live_editor/scripts/controllers/main.js b/live_editor/scripts/controllers/main.js index 24de565b31..7363a4dfe7 100644 --- a/live_editor/scripts/controllers/main.js +++ b/live_editor/scripts/controllers/main.js @@ -9,12 +9,12 @@ */ angular.module('angularMermaidApp') .controller('MainCtrl', ['$scope', '$sce', '$location', function($scope, $sce, $location) { - $scope.absurl = ''; + var absurl = window.location.href.split('#')[0]; $scope.diaglink = ''; $scope.showerror = false; $scope.checkUpdate = function() { - $scope.diaglink = $scope.absurl + '##' + encodeURIComponent($scope.mermaidsyntax); + $scope.diaglink = absurl + '##' + encodeURIComponent($scope.mermaidsyntax); setTimeout(function() { var syntax = $sce.trustAsHtml($scope.mermaidsyntax) + '\n'; // Delete and re add the mermaid node from the DOM @@ -46,9 +46,7 @@ angular.module('angularMermaidApp') $scope.showform = false; $scope.diagclass = 'col s12 m12 l12'; $scope.cardclass = ''; - } else { - $scope.absurl = $location.absUrl(); $scope.showform = true; $scope.diagclass = 'col s12 m12 l9'; $scope.cardclass = 'card'; @@ -61,5 +59,4 @@ angular.module('angularMermaidApp') } document.getElementsByClassName('materialize-textarea')[0].focus(); $scope.checkUpdate(); - }]); From aa3cadd51037a1db0388191ec30a7e6840026214 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Szcz=C4=99=C5=9Bniak-Szlagowski?= Date: Sat, 24 Oct 2015 00:40:15 +0100 Subject: [PATCH 2/7] Add angular-utf8-base64 dependency --- .../angular-utf8-base64/.bower.json | 26 +++ .../angular-utf8-base64/.gitignore | 2 + .../angular-utf8-base64/.jshintrc | 29 +++ .../angular-utf8-base64/LICENSE | 21 ++ .../angular-utf8-base64/README.md | 53 +++++ .../angular-utf8-base64.js | 194 ++++++++++++++++++ .../angular-utf8-base64.min.js | 1 + .../angular-utf8-base64/bower.json | 15 ++ .../angular-utf8-base64/karma.conf.js | 69 +++++++ .../angular-utf8-base64/test/.jshintrc | 40 ++++ .../test/angular-utf8-base64.spec.js | 84 ++++++++ live_editor/index.html | 1 + live_editor/scripts/app.js | 2 +- 13 files changed, 536 insertions(+), 1 deletion(-) create mode 100644 live_editor/bower_components/angular-utf8-base64/.bower.json create mode 100644 live_editor/bower_components/angular-utf8-base64/.gitignore create mode 100644 live_editor/bower_components/angular-utf8-base64/.jshintrc create mode 100644 live_editor/bower_components/angular-utf8-base64/LICENSE create mode 100644 live_editor/bower_components/angular-utf8-base64/README.md create mode 100644 live_editor/bower_components/angular-utf8-base64/angular-utf8-base64.js create mode 100644 live_editor/bower_components/angular-utf8-base64/angular-utf8-base64.min.js create mode 100644 live_editor/bower_components/angular-utf8-base64/bower.json create mode 100644 live_editor/bower_components/angular-utf8-base64/karma.conf.js create mode 100644 live_editor/bower_components/angular-utf8-base64/test/.jshintrc create mode 100644 live_editor/bower_components/angular-utf8-base64/test/angular-utf8-base64.spec.js diff --git a/live_editor/bower_components/angular-utf8-base64/.bower.json b/live_editor/bower_components/angular-utf8-base64/.bower.json new file mode 100644 index 0000000000..1090805261 --- /dev/null +++ b/live_editor/bower_components/angular-utf8-base64/.bower.json @@ -0,0 +1,26 @@ +{ + "name": "angular-utf8-base64", + "version": "0.0.5", + "main": "angular-utf8-base64.js", + "ignore": [ + "package.json", + "Gruntfile.js" + ], + "dependencies": { + "angular": ">= 1.0.8" + }, + "devDependencies": { + "angular-mocks": "~1.3.1" + }, + "homepage": "https://github.com/stranger82/angular-utf8-base64", + "_release": "0.0.5", + "_resolution": { + "type": "version", + "tag": "v0.0.5", + "commit": "43cea612939acc07e06939f8da97e6f22186d1e2" + }, + "_source": "git://github.com/stranger82/angular-utf8-base64.git", + "_target": "~0.0.5", + "_originalSource": "angular-utf8-base64", + "_direct": true +} \ No newline at end of file diff --git a/live_editor/bower_components/angular-utf8-base64/.gitignore b/live_editor/bower_components/angular-utf8-base64/.gitignore new file mode 100644 index 0000000000..7bf6eb18f7 --- /dev/null +++ b/live_editor/bower_components/angular-utf8-base64/.gitignore @@ -0,0 +1,2 @@ +bower_components +node_modules diff --git a/live_editor/bower_components/angular-utf8-base64/.jshintrc b/live_editor/bower_components/angular-utf8-base64/.jshintrc new file mode 100644 index 0000000000..7e6bc53053 --- /dev/null +++ b/live_editor/bower_components/angular-utf8-base64/.jshintrc @@ -0,0 +1,29 @@ +{ + "bitwise": true, + "curly": false, + "eqeqeq": true, + "eqnull": true, + "evil": true, + "forin": true, + "globalstrict": true, + "immed": true, + "latedef": true, + "newcap": true, + "noarg": true, + "noempty": true, + "nonew": true, + "trailing": true, + "undef": true, + "unused": true, + + "camelcase": true, + "indent": 4, + "quotmark": "single", + + "predef": [ + "angular", + "navigator", + "module" // Require + ] +} + diff --git a/live_editor/bower_components/angular-utf8-base64/LICENSE b/live_editor/bower_components/angular-utf8-base64/LICENSE new file mode 100644 index 0000000000..e4b375b4d0 --- /dev/null +++ b/live_editor/bower_components/angular-utf8-base64/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Andrey Bezyazychniy + +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. \ No newline at end of file diff --git a/live_editor/bower_components/angular-utf8-base64/README.md b/live_editor/bower_components/angular-utf8-base64/README.md new file mode 100644 index 0000000000..bb6e4abce7 --- /dev/null +++ b/live_editor/bower_components/angular-utf8-base64/README.md @@ -0,0 +1,53 @@ +# angular-utf8-base64 + +AngularJS service for UTF-8 and Base64 and Base64url Javascript Encoding + +angular-utf8-base64 is based on [Really fast Javascript Base64 encoder/decoder with utf-8 support](http://jsbase64.codeplex.com/releases/view/89265). I just wrapped it as AngularJS service. + +There is another AngularJS service for Base64 encoding [available](https://github.com/ninjatronic/angular-base64). +But it doesn't support UTF-8. + + +## Installation + +### Bower + +``` +bower install angular-utf8-base64 +``` + +```html + +``` + +## Usage + +```javascript +angular + .module('myApp', ['ab-base64']) + .controller('myController', [ + + '$scope','base64', + function($scope,base64) { + + $scope.encoded = base64.encode('a string'); + $scope.decoded = base64.decode('YSBzdHJpbmc='); + }]); +``` + +### Base64Url Support + +Commonly used for supporting JWS and JWT encodings, base64url encoding creates a URL safe output. + +```javascript +angular + .module('myApp', ['ab-base64']) + .controller('myController', [ + + '$scope','base64', + function($scope,base64) { + + $scope.encoded = base64.urlencode('a string'); + $scope.decoded = base64.urldecode('YSBzdHJpbmc'); + }]); +``` diff --git a/live_editor/bower_components/angular-utf8-base64/angular-utf8-base64.js b/live_editor/bower_components/angular-utf8-base64/angular-utf8-base64.js new file mode 100644 index 0000000000..01bc05242b --- /dev/null +++ b/live_editor/bower_components/angular-utf8-base64/angular-utf8-base64.js @@ -0,0 +1,194 @@ +'use strict'; + +angular.module('ab-base64',[]).constant('base64', (function() { + + /* + * Encapsulation of Vassilis Petroulias's base64.js library for AngularJS + * Original notice included below + */ + + /* + Copyright Vassilis Petroulias [DRDigit] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + var B64 = { + alphabet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=', + lookup: null, + ie: /MSIE /.test(navigator.userAgent), + ieo: /MSIE [67]/.test(navigator.userAgent), + encode: function (s) { + /* jshint bitwise:false */ + var buffer = B64.toUtf8(s), + position = -1, + result, + len = buffer.length, + nan0, nan1, nan2, enc = [, , , ]; + + if (B64.ie) { + result = []; + while (++position < len) { + nan0 = buffer[position]; + nan1 = buffer[++position]; + enc[0] = nan0 >> 2; + enc[1] = ((nan0 & 3) << 4) | (nan1 >> 4); + if (isNaN(nan1)) + enc[2] = enc[3] = 64; + else { + nan2 = buffer[++position]; + enc[2] = ((nan1 & 15) << 2) | (nan2 >> 6); + enc[3] = (isNaN(nan2)) ? 64 : nan2 & 63; + } + result.push(B64.alphabet.charAt(enc[0]), B64.alphabet.charAt(enc[1]), B64.alphabet.charAt(enc[2]), B64.alphabet.charAt(enc[3])); + } + return result.join(''); + } else { + result = ''; + while (++position < len) { + nan0 = buffer[position]; + nan1 = buffer[++position]; + enc[0] = nan0 >> 2; + enc[1] = ((nan0 & 3) << 4) | (nan1 >> 4); + if (isNaN(nan1)) + enc[2] = enc[3] = 64; + else { + nan2 = buffer[++position]; + enc[2] = ((nan1 & 15) << 2) | (nan2 >> 6); + enc[3] = (isNaN(nan2)) ? 64 : nan2 & 63; + } + result += B64.alphabet[enc[0]] + B64.alphabet[enc[1]] + B64.alphabet[enc[2]] + B64.alphabet[enc[3]]; + } + return result; + } + }, + decode: function (s) { + /* jshint bitwise:false */ + s = s.replace(/\s/g, ''); + if (s.length % 4) + throw new Error('InvalidLengthError: decode failed: The string to be decoded is not the correct length for a base64 encoded string.'); + if(/[^A-Za-z0-9+\/=\s]/g.test(s)) + throw new Error('InvalidCharacterError: decode failed: The string contains characters invalid in a base64 encoded string.'); + + var buffer = B64.fromUtf8(s), + position = 0, + result, + len = buffer.length; + + if (B64.ieo) { + result = []; + while (position < len) { + if (buffer[position] < 128) + result.push(String.fromCharCode(buffer[position++])); + else if (buffer[position] > 191 && buffer[position] < 224) + result.push(String.fromCharCode(((buffer[position++] & 31) << 6) | (buffer[position++] & 63))); + else + result.push(String.fromCharCode(((buffer[position++] & 15) << 12) | ((buffer[position++] & 63) << 6) | (buffer[position++] & 63))); + } + return result.join(''); + } else { + result = ''; + while (position < len) { + if (buffer[position] < 128) + result += String.fromCharCode(buffer[position++]); + else if (buffer[position] > 191 && buffer[position] < 224) + result += String.fromCharCode(((buffer[position++] & 31) << 6) | (buffer[position++] & 63)); + else + result += String.fromCharCode(((buffer[position++] & 15) << 12) | ((buffer[position++] & 63) << 6) | (buffer[position++] & 63)); + } + return result; + } + }, + toUtf8: function (s) { + /* jshint bitwise:false */ + var position = -1, + len = s.length, + chr, buffer = []; + if (/^[\x00-\x7f]*$/.test(s)) while (++position < len) + buffer.push(s.charCodeAt(position)); + else while (++position < len) { + chr = s.charCodeAt(position); + if (chr < 128) + buffer.push(chr); + else if (chr < 2048) + buffer.push((chr >> 6) | 192, (chr & 63) | 128); + else + buffer.push((chr >> 12) | 224, ((chr >> 6) & 63) | 128, (chr & 63) | 128); + } + return buffer; + }, + fromUtf8: function (s) { + /* jshint bitwise:false */ + var position = -1, + len, buffer = [], + enc = [, , , ]; + if (!B64.lookup) { + len = B64.alphabet.length; + B64.lookup = {}; + while (++position < len) + B64.lookup[B64.alphabet.charAt(position)] = position; + position = -1; + } + len = s.length; + while (++position < len) { + enc[0] = B64.lookup[s.charAt(position)]; + enc[1] = B64.lookup[s.charAt(++position)]; + buffer.push((enc[0] << 2) | (enc[1] >> 4)); + enc[2] = B64.lookup[s.charAt(++position)]; + if (enc[2] === 64) + break; + buffer.push(((enc[1] & 15) << 4) | (enc[2] >> 2)); + enc[3] = B64.lookup[s.charAt(++position)]; + if (enc[3] === 64) + break; + buffer.push(((enc[2] & 3) << 6) | enc[3]); + } + return buffer; + } + }; + + var B64url = { + decode: function(input) { + // Replace non-url compatible chars with base64 standard chars + input = input + .replace(/-/g, '+') + .replace(/_/g, '/'); + + // Pad out with standard base64 required padding characters + var pad = input.length % 4; + if(pad) { + if(pad === 1) { + throw new Error('InvalidLengthError: Input base64url string is the wrong length to determine padding'); + } + input += new Array(5-pad).join('='); + } + + return B64.decode(input); + }, + + encode: function(input) { + var output = B64.encode(input); + return output + .replace(/\+/g, '-') + .replace(/\//g, '_') + .split('=', 1)[0]; + } + }; + + return { + decode: B64.decode, + encode: B64.encode, + urldecode: B64url.decode, + urlencode: B64url.encode, + }; +})()); + diff --git a/live_editor/bower_components/angular-utf8-base64/angular-utf8-base64.min.js b/live_editor/bower_components/angular-utf8-base64/angular-utf8-base64.min.js new file mode 100644 index 0000000000..24af57d020 --- /dev/null +++ b/live_editor/bower_components/angular-utf8-base64/angular-utf8-base64.min.js @@ -0,0 +1 @@ +"use strict";angular.module("ab-base64",[]).constant("base64",function(){var a={alphabet:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",lookup:null,ie:/MSIE /.test(navigator.userAgent),ieo:/MSIE [67]/.test(navigator.userAgent),encode:function(b){var c,d,e,f,g=a.toUtf8(b),h=-1,i=g.length,j=[,,,];if(a.ie){for(c=[];++h>2,j[1]=(3&d)<<4|e>>4,isNaN(e)?j[2]=j[3]=64:(f=g[++h],j[2]=(15&e)<<2|f>>6,j[3]=isNaN(f)?64:63&f),c.push(a.alphabet.charAt(j[0]),a.alphabet.charAt(j[1]),a.alphabet.charAt(j[2]),a.alphabet.charAt(j[3]));return c.join("")}for(c="";++h>2,j[1]=(3&d)<<4|e>>4,isNaN(e)?j[2]=j[3]=64:(f=g[++h],j[2]=(15&e)<<2|f>>6,j[3]=isNaN(f)?64:63&f),c+=a.alphabet[j[0]]+a.alphabet[j[1]]+a.alphabet[j[2]]+a.alphabet[j[3]];return c},decode:function(b){if(b=b.replace(/\s/g,""),b.length%4)throw new Error("InvalidLengthError: decode failed: The string to be decoded is not the correct length for a base64 encoded string.");if(/[^A-Za-z0-9+\/=\s]/g.test(b))throw new Error("InvalidCharacterError: decode failed: The string contains characters invalid in a base64 encoded string.");var c,d=a.fromUtf8(b),e=0,f=d.length;if(a.ieo){for(c=[];f>e;)c.push(d[e]<128?String.fromCharCode(d[e++]):d[e]>191&&d[e]<224?String.fromCharCode((31&d[e++])<<6|63&d[e++]):String.fromCharCode((15&d[e++])<<12|(63&d[e++])<<6|63&d[e++]));return c.join("")}for(c="";f>e;)c+=String.fromCharCode(d[e]<128?d[e++]:d[e]>191&&d[e]<224?(31&d[e++])<<6|63&d[e++]:(15&d[e++])<<12|(63&d[e++])<<6|63&d[e++]);return c},toUtf8:function(a){var b,c=-1,d=a.length,e=[];if(/^[\x00-\x7f]*$/.test(a))for(;++cb?e.push(b):2048>b?e.push(b>>6|192,63&b|128):e.push(b>>12|224,b>>6&63|128,63&b|128);return e},fromUtf8:function(b){var c,d=-1,e=[],f=[,,,];if(!a.lookup){for(c=a.alphabet.length,a.lookup={};++d>4),f[2]=a.lookup[b.charAt(++d)],64!==f[2])&&(e.push((15&f[1])<<4|f[2]>>2),f[3]=a.lookup[b.charAt(++d)],64!==f[3]);)e.push((3&f[2])<<6|f[3]);return e}},b={decode:function(b){b=b.replace(/-/g,"+").replace(/_/g,"/");var c=b.length%4;if(c){if(1===c)throw new Error("InvalidLengthError: Input base64url string is the wrong length to determine padding");b+=new Array(5-c).join("=")}return a.decode(b)},encode:function(b){var c=a.encode(b);return c.replace(/\+/g,"-").replace(/\//g,"_").split("=",1)[0]}};return{decode:a.decode,encode:a.encode,urldecode:b.decode,urlencode:b.encode}}()); \ No newline at end of file diff --git a/live_editor/bower_components/angular-utf8-base64/bower.json b/live_editor/bower_components/angular-utf8-base64/bower.json new file mode 100644 index 0000000000..775812c9d8 --- /dev/null +++ b/live_editor/bower_components/angular-utf8-base64/bower.json @@ -0,0 +1,15 @@ +{ + "name": "angular-utf8-base64", + "version": "0.0.5", + "main": "angular-utf8-base64.js", + "ignore": [ + "package.json", + "Gruntfile.js" + ], + "dependencies": { + "angular": ">= 1.0.8" + }, + "devDependencies": { + "angular-mocks": "~1.3.1" + } +} diff --git a/live_editor/bower_components/angular-utf8-base64/karma.conf.js b/live_editor/bower_components/angular-utf8-base64/karma.conf.js new file mode 100644 index 0000000000..590fea6b88 --- /dev/null +++ b/live_editor/bower_components/angular-utf8-base64/karma.conf.js @@ -0,0 +1,69 @@ +'use strict'; +// Karma configuration +// Generated on Mon Nov 03 2014 14:52:53 GMT-0700 (MST) + +module.exports = function(config) { + config.set({ + + // base path that will be used to resolve all patterns (eg. files, exclude) + basePath: '', + + + // frameworks to use + // available frameworks: https://npmjs.org/browse/keyword/karma-adapter + frameworks: ['mocha', 'chai'], + + + // list of files / patterns to load in the browser + files: [ + 'bower_components/angular/angular.js', + 'bower_components/angular-mocks/angular-mocks.js', + 'angular-utf8-base64.js', + 'test/**/*.spec.js' + ], + + + // list of files to exclude + exclude: [ + ], + + + // preprocess matching files before serving them to the browser + // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor + preprocessors: { + }, + + + // test results reporter to use + // possible values: 'dots', 'progress' + // available reporters: https://npmjs.org/browse/keyword/karma-reporter + reporters: ['progress'], + + + // web server port + port: 9876, + + + // enable / disable colors in the output (reporters and logs) + colors: true, + + + // level of logging + // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG + logLevel: config.LOG_INFO, + + + // enable / disable watching file and executing tests whenever any file changes + autoWatch: false, + + + // start these browsers + // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher + browsers: ['PhantomJS'], + + + // Continuous Integration mode + // if true, Karma captures browsers, runs the tests and exits + singleRun: false + }); +}; diff --git a/live_editor/bower_components/angular-utf8-base64/test/.jshintrc b/live_editor/bower_components/angular-utf8-base64/test/.jshintrc new file mode 100644 index 0000000000..95535b2797 --- /dev/null +++ b/live_editor/bower_components/angular-utf8-base64/test/.jshintrc @@ -0,0 +1,40 @@ +{ + "bitwise": true, + "curly": false, + "eqeqeq": true, + "eqnull": true, + "evil": true, + "forin": true, + "globalstrict": true, + "immed": true, + "latedef": true, + "newcap": true, + "noarg": true, + "noempty": true, + "nonew": true, + "trailing": true, + "undef": true, + "unused": true, + + "camelcase": true, + "indent": 4, + "quotmark": "single", + + "globals": { + // Mocha + "describe": false, + "it": false, + "before": false, + "beforeEach": false, + "after": false, + "afterEach": false, + + // chai + "expect": false, + + // angular spec + "module": false, + "inject": false + } +} + diff --git a/live_editor/bower_components/angular-utf8-base64/test/angular-utf8-base64.spec.js b/live_editor/bower_components/angular-utf8-base64/test/angular-utf8-base64.spec.js new file mode 100644 index 0000000000..d4d1e46db0 --- /dev/null +++ b/live_editor/bower_components/angular-utf8-base64/test/angular-utf8-base64.spec.js @@ -0,0 +1,84 @@ +'use strict'; + +var base64; + +beforeEach(module('ab-base64')); +beforeEach(inject(function(_base64_) { + base64 = _base64_; +})); + +describe('base64 encode', function() { + it('should encode simple ASCII', function() { + expect(base64.encode('a string')).to.equal('YSBzdHJpbmc='); + }); + + it('should encode data with whitespace', function() { + expect(base64.encode('a string\r\ta paragraph')).to.equal('YSBzdHJpbmcNCWEgcGFyYWdyYXBo'); + }); + + it('should encode extended utf8', function() { + expect(base64.encode('I ♥ base64')).to.equal('SSDimaUgYmFzZTY0'); + }); + + it('should encode empty data', function() { + expect(base64.encode('')).to.equal(''); + }); +}); + +describe('base64 decode', function() { + it('should decode simple ASCII', function() { + expect(base64.decode('YSBzdHJpbmc=')).to.equal('a string'); + }); + + it('should decode extended utf8', function() { + expect(base64.decode('SSDimaUgYmFzZTY0')).to.equal('I ♥ base64'); + }); + + it('should decode empty data', function() { + expect(base64.decode('')).to.equal(''); + }); + + it('should decode input with whitepace', function() { + expect(base64.decode('YSBzd\r\t HJpbmc=')).to.equal('a string'); + }); + + it('should throw on bad length', function() { + expect(function() { base64.decode('235'); }).to.throw(/InvalidLengthError/); + }); + + it('should throw on bad characters', function() { + expect(function() { base64.decode('!$#%'); }).to.throw(/InvalidCharacterError/); + }); +}); + +describe('base64url encode', function() { + it('should encode simple ASCII', function() { + expect(base64.urlencode('a string')).to.equal('YSBzdHJpbmc'); + }); + + it('should only use URL safe characters ', function() { + expect(base64.urlencode('So?

I')).to.equal('U28_PHA-SQ'); + }); + + it('should encode extended utf8', function() { + expect(base64.urlencode('I ♥ me some base64url')).to.equal('SSDimaUgbWUgc29tZSBiYXNlNjR1cmw'); + }); +}); + +describe('base64url decode', function() { + it('should decode simple ASCII', function() { + expect(base64.urldecode('YSBzdHJpbmc')).to.equal('a string'); + }); + + it('should decode extended utf8', function() { + expect(base64.urldecode('SSDimaUgbWUgc29tZSBiYXNlNjR1cmw')).to.equal('I ♥ me some base64url'); + }); + + it('should decode with URL safe characters ', function() { + expect(base64.urldecode('U28_PHA-SQ')).to.equal('So?

I'); + }); + + it('should throw on invalid length', function() { + expect(function() { base64.urldecode('SSDim'); }).to.throw(/InvalidLengthError/); + }); +}); diff --git a/live_editor/index.html b/live_editor/index.html index 749e2a8d2f..eb0e72b68e 100644 --- a/live_editor/index.html +++ b/live_editor/index.html @@ -82,6 +82,7 @@ + diff --git a/live_editor/scripts/app.js b/live_editor/scripts/app.js index 9f7d5c9b06..3449f9c7d7 100644 --- a/live_editor/scripts/app.js +++ b/live_editor/scripts/app.js @@ -9,4 +9,4 @@ * Main module of the application. */ angular - .module('angularMermaidApp', ['ngSanitize']); + .module('angularMermaidApp', ['ngSanitize', 'ab-base64']); From eea2cede7a753e1ba5d82800e67fc0c8c923adfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Szcz=C4=99=C5=9Bniak-Szlagowski?= Date: Sat, 24 Oct 2015 00:42:36 +0100 Subject: [PATCH 3/7] Use url-safe base64 encoding for permalinks This comes with backwards compatibility. The motivation is that: * The new URLs are slightly shorter * There's a lot of software out there which fails at recognising URLs when they contain less common characters, even if perfectly valid. --- live_editor/scripts/controllers/main.js | 58 ++++++++++++++++++------- 1 file changed, 43 insertions(+), 15 deletions(-) diff --git a/live_editor/scripts/controllers/main.js b/live_editor/scripts/controllers/main.js index 7363a4dfe7..0843064bff 100644 --- a/live_editor/scripts/controllers/main.js +++ b/live_editor/scripts/controllers/main.js @@ -8,13 +8,20 @@ * Controller of the angularMermaidApp */ angular.module('angularMermaidApp') - .controller('MainCtrl', ['$scope', '$sce', '$location', function($scope, $sce, $location) { + .controller('MainCtrl', ['$scope', '$sce', '$location', 'base64', function($scope, $sce, $location, base64) { var absurl = window.location.href.split('#')[0]; + var exampleCode = 'sequenceDiagram\n' + + 'A->> B: Query\n' + + 'B->> C: Forward query\n' + + 'Note right of C: Thinking...\n' + + 'C->> B: Response\n' + + 'B->> A: Forward response\n'; + $scope.diaglink = ''; $scope.showerror = false; $scope.checkUpdate = function() { - $scope.diaglink = absurl + '##' + encodeURIComponent($scope.mermaidsyntax); + $scope.diaglink = buildURL('view', $scope.mermaidsyntax); setTimeout(function() { var syntax = $sce.trustAsHtml($scope.mermaidsyntax) + '\n'; // Delete and re add the mermaid node from the DOM @@ -39,24 +46,45 @@ angular.module('angularMermaidApp') }, 1000); }; - if ($location.hash()) { - $scope.mermaidsyntax = $location.hash(); - console.log($location.hash()); - //Delete the other elements and leave only the diagram + route(); + + document.getElementsByClassName('materialize-textarea')[0].focus(); + $scope.checkUpdate(); + + function route() { + var code; + + // ##uriEncodedDiagramString (for backwards compatibility) + if ($location.hash()) { + code = $location.hash(); + return viewDiagram(code); + } + + // #/view/base64EncodedDiagramString + if ($location.path().match(/^\/view\//)) { + code = base64.urldecode($location.path().split('/')[2]); + return viewDiagram(code); + } + + return editDiagram(exampleCode); + } + + function viewDiagram(code) { + $scope.mermaidsyntax = code; + // Delete the other elements and leave only the diagram $scope.showform = false; $scope.diagclass = 'col s12 m12 l12'; $scope.cardclass = ''; - } else { + } + + function editDiagram(code) { + $scope.mermaidsyntax = code; $scope.showform = true; $scope.diagclass = 'col s12 m12 l9'; $scope.cardclass = 'card'; - $scope.mermaidsyntax = 'sequenceDiagram\n' + - 'A->> B: Query\n' + - 'B->> C: Forward query\n' + - 'Note right of C: Thinking...\n' + - 'C->> B: Response\n' + - 'B->> A: Forward response\n'; } - document.getElementsByClassName('materialize-textarea')[0].focus(); - $scope.checkUpdate(); + + function buildURL(action, code) { + return absurl + '#/' + action + '/' + base64.urlencode(code); + } }]); From 20ac941d44f6f1c41f71fb775e100746b508634a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Szcz=C4=99=C5=9Bniak-Szlagowski?= Date: Sat, 24 Oct 2015 00:53:26 +0100 Subject: [PATCH 4/7] Add another link to edit the diagram --- live_editor/index.html | 3 ++- live_editor/scripts/controllers/main.js | 9 ++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/live_editor/index.html b/live_editor/index.html index eb0e72b68e..eebe4c1478 100644 --- a/live_editor/index.html +++ b/live_editor/index.html @@ -62,7 +62,8 @@

Generated diagram
- PERMALINK + LINK TO VIEW + LINK TO EDIT
diff --git a/live_editor/scripts/controllers/main.js b/live_editor/scripts/controllers/main.js index 0843064bff..c27629b494 100644 --- a/live_editor/scripts/controllers/main.js +++ b/live_editor/scripts/controllers/main.js @@ -21,7 +21,8 @@ angular.module('angularMermaidApp') $scope.showerror = false; $scope.checkUpdate = function() { - $scope.diaglink = buildURL('view', $scope.mermaidsyntax); + $scope.viewlink = buildURL('view', $scope.mermaidsyntax); + $scope.editlink = buildURL('edit', $scope.mermaidsyntax); setTimeout(function() { var syntax = $sce.trustAsHtml($scope.mermaidsyntax) + '\n'; // Delete and re add the mermaid node from the DOM @@ -66,6 +67,12 @@ angular.module('angularMermaidApp') return viewDiagram(code); } + // #/edit/base64EncodedDiagramString + if ($location.path().match(/^\/edit\//)) { + code = base64.urldecode($location.path().split('/')[2]); + return editDiagram(code); + } + return editDiagram(exampleCode); } From 7b0720266ee80b13843a7231c6ee2d476cd74f93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Szcz=C4=99=C5=9Bniak-Szlagowski?= Date: Sat, 24 Oct 2015 01:02:57 +0100 Subject: [PATCH 5/7] Support hashchange immediately Previously the user had to reload (hard) the website after changing hash URL or clicking one of the permalinks. --- live_editor/scripts/controllers/main.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/live_editor/scripts/controllers/main.js b/live_editor/scripts/controllers/main.js index c27629b494..1fa907b5de 100644 --- a/live_editor/scripts/controllers/main.js +++ b/live_editor/scripts/controllers/main.js @@ -39,7 +39,6 @@ angular.module('angularMermaidApp') mermaidnode.className = 'mermaid'; mermaidnode.appendChild(document.createTextNode($sce.trustAsHtml($scope.mermaidsyntax))); mermaidholder.appendChild(mermaidnode); - console.log($scope.diaglink); mermaid.init(); // jshint ignore:line } else { $scope.showerror = true; @@ -47,10 +46,7 @@ angular.module('angularMermaidApp') }, 1000); }; - route(); - - document.getElementsByClassName('materialize-textarea')[0].focus(); - $scope.checkUpdate(); + $scope.$watch(function() { return $location.url(); }, route); function route() { var code; @@ -82,6 +78,7 @@ angular.module('angularMermaidApp') $scope.showform = false; $scope.diagclass = 'col s12 m12 l12'; $scope.cardclass = ''; + $scope.checkUpdate(); } function editDiagram(code) { @@ -89,6 +86,8 @@ angular.module('angularMermaidApp') $scope.showform = true; $scope.diagclass = 'col s12 m12 l9'; $scope.cardclass = 'card'; + document.getElementsByClassName('materialize-textarea')[0].focus(); + $scope.checkUpdate(); } function buildURL(action, code) { From 62902f9d1196e3bacfaebeaaa92179b917473666 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Szcz=C4=99=C5=9Bniak-Szlagowski?= Date: Sat, 24 Oct 2015 01:18:07 +0100 Subject: [PATCH 6/7] Update mermaid to 0.5.5 in live editor --- live_editor/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/live_editor/index.html b/live_editor/index.html index eebe4c1478..9cae02624f 100644 --- a/live_editor/index.html +++ b/live_editor/index.html @@ -80,7 +80,7 @@ - + From 9f8dedb09442526cfd5535119c30b712d1a5692c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Szcz=C4=99=C5=9Bniak-Szlagowski?= Date: Sat, 24 Oct 2015 02:17:27 +0100 Subject: [PATCH 7/7] Add a button to download SVG Fixes #144 --- live_editor/index.html | 6 ++++-- live_editor/scripts/app.js | 5 ++++- live_editor/scripts/controllers/main.js | 11 ++++++++++- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/live_editor/index.html b/live_editor/index.html index 9cae02624f..13e77de48f 100644 --- a/live_editor/index.html +++ b/live_editor/index.html @@ -62,8 +62,10 @@ diff --git a/live_editor/scripts/app.js b/live_editor/scripts/app.js index 3449f9c7d7..f0eed7c571 100644 --- a/live_editor/scripts/app.js +++ b/live_editor/scripts/app.js @@ -9,4 +9,7 @@ * Main module of the application. */ angular - .module('angularMermaidApp', ['ngSanitize', 'ab-base64']); + .module('angularMermaidApp', ['ngSanitize', 'ab-base64']) + .config(['$compileProvider', function ($compileProvider) { + $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|local|data):/); + }]); diff --git a/live_editor/scripts/controllers/main.js b/live_editor/scripts/controllers/main.js index 1fa907b5de..8fbace7c2f 100644 --- a/live_editor/scripts/controllers/main.js +++ b/live_editor/scripts/controllers/main.js @@ -17,7 +17,9 @@ angular.module('angularMermaidApp') 'C->> B: Response\n' + 'B->> A: Forward response\n'; - $scope.diaglink = ''; + $scope.viewlink = ''; + $scope.editlink = ''; + $scope.svglink = ''; $scope.showerror = false; $scope.checkUpdate = function() { @@ -40,9 +42,11 @@ angular.module('angularMermaidApp') mermaidnode.appendChild(document.createTextNode($sce.trustAsHtml($scope.mermaidsyntax))); mermaidholder.appendChild(mermaidnode); mermaid.init(); // jshint ignore:line + $scope.svglink = buildSVGURL(); } else { $scope.showerror = true; } + $scope.$apply(); }, 1000); }; @@ -93,4 +97,9 @@ angular.module('angularMermaidApp') function buildURL(action, code) { return absurl + '#/' + action + '/' + base64.urlencode(code); } + + function buildSVGURL() { + var svg = document.querySelector('svg').outerHTML; + return 'data:image/svg+xml;base64,' + base64.encode(svg); + } }]);