From 24bd461e21ac3c3201c426d5d25cb4b8415f0b6f Mon Sep 17 00:00:00 2001 From: Bastien Date: Tue, 24 Nov 2015 14:54:13 +0100 Subject: [PATCH 1/2] Add gulp task runner, add demo file and change documentation --- .gitignore | 3 + README.md | 23 ++- angular-pagedown.js | 331 ++++++++++++++++++++++---------------------- bower.json | 2 +- demo/index.html | 33 +++++ demo/script.js | 24 ++++ gulpfile.js | 45 ++++++ 7 files changed, 284 insertions(+), 177 deletions(-) create mode 100644 .gitignore create mode 100644 demo/index.html create mode 100644 demo/script.js create mode 100644 gulpfile.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4ff040b --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +node_modules +bower_components +npm-debug.log diff --git a/README.md b/README.md index 3d8ae99..5e89351 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # angular-pagedown -A pagedown editor for AngularJS. View this [Plunker](http://plnkr.co/edit/2LZiw454g77k6aE3HTyd) for demo. +A pagedown editor for AngularJS. View this [Plunker](http://plnkr.co/edit/m93lSn?p=preview) for demo. ## Instructions @@ -35,17 +35,17 @@ This package comes with 2 directives: ## Editor ```html - + ``` Options: -#### content +#### ng-model 1. An expression. 1. *Expression*: Mandatory -1. Example: `` -1. Example: `` +1. Example: `` +1. Example: `` #### show-preview @@ -56,13 +56,13 @@ Options: 1. An expression to invoke upon clicking the help (?) button. 1. *Expression*: Default to open http://daringfireball.net/projects/markdown/syntax in new window -1. Example: `` +1. Example: `` #### insert-image 1. An expression to invoke upon clicking the "Insert Image" button. 1. *Expression*: Default to `noop` -1. Example: `` +1. Example: `` 1. The parent scope function `promptImageUrl` must return either: - A string of image URL. - A promise resolved with a string of image URL. @@ -71,15 +71,15 @@ Options: 1. An expression. 1. *Expression*: Default to empty string -1. Example: `` +1. Example: `` #### editor-class 1. An expression to use as [ngClass](https://docs.angularjs.org/api/ng/directive/ngClass). 1. *Expression*: Default to `wmd-input` -1. Example: `` -1. Example: `` -1. Example: `` +1. Example: `` +1. Example: `` +1. Example: `` #### editor-rows @@ -104,5 +104,4 @@ Options: ``` ## TODO -1. Grunt setup to minify files. 1. Extend PageDown editor to allow override of hyper link insertion. diff --git a/angular-pagedown.js b/angular-pagedown.js index 9eb962e..9b1b369 100644 --- a/angular-pagedown.js +++ b/angular-pagedown.js @@ -1,171 +1,174 @@ -// Mardown Extra Options -var mdExtraOptions = { - extensions: "all", - table_class: 'table' -}; - -// adapted from http://stackoverflow.com/a/20957476/940030 -angular.module("ui.pagedown", []) - .directive("pagedownEditor", ['$compile', '$timeout', '$window', '$q', function ($compile, $timeout, $window, $q) { - var nextId = 0; - var converter = Markdown.getSanitizingConverter(); - Markdown.Extra.init(converter, mdExtraOptions); - - converter.hooks.chain("preBlockGamut", function (text, rbg) { - return text.replace(/^ {0,3}""" *\n((?:.*?\n)+?) {0,3}""" *$/gm, function (whole, inner) { - return "
" + rbg(inner) + "
\n"; - }); - }); - - return { - restrict: "E", - require: 'ngModel', - scope: { - ngModel: "=", - placeholder: "@", - showPreview: "@", - help: "&", - insertImage: "&", - editorClass: "=?", - editorRows: "@", - previewClass: "=?", - previewContent: "=?" - }, - link: function (scope, element, attrs, ngModel) { - - scope.changed = function () { - ngModel.$setDirty(); - scope.$parent.$eval(attrs.ngChange); - }; - - - var editorUniqueId; - - if (attrs.id == null) { - editorUniqueId = nextId++; - } else { - editorUniqueId = attrs.id; - } - - // just hide the preview, we still need it for "onPreviewRefresh" hook - var previewHiddenStyle = scope.showPreview == "false" ? "display: none;" : ""; - - var placeholder = attrs.placeholder || ""; - var editorRows = attrs.editorRows || "10"; - - var newElement = $compile( - '
' + - '
' + - '
' + - '' + - '
' + - '
' + - '
' + - '
')(scope); - - // html() doesn't work - element.append(newElement); - - var help = angular.isFunction(scope.help) ? scope.help : function () { - // redirect to the guide by default - $window.open("http://daringfireball.net/projects/markdown/syntax", "_blank"); - }; - - var editor = new Markdown.Editor(converter, "-" + editorUniqueId, { - handler: help +(function() { + "use strict"; + // Mardown Extra Options + var mdExtraOptions = { + extensions: 'all', + table_class: 'table' + }; + + // adapted from http://stackoverflow.com/a/20957476/940030 + angular.module('ui.pagedown', []) + .directive('pagedownEditor', ['$compile', '$timeout', '$window', '$q', function ($compile, $timeout, $window, $q) { + var nextId = 0; + var converter = Markdown.getSanitizingConverter(); + Markdown.Extra.init(converter, mdExtraOptions); + + converter.hooks.chain('preBlockGamut', function (text, rbg) { + return text.replace(/^ {0,3}""" *\n((?:.*?\n)+?) {0,3}""" *$/gm, function (whole, inner) { + return '
' + rbg(inner) + '
\n'; }); - - - var editorElement = angular.element(document.getElementById("wmd-input-" + editorUniqueId)); - - editorElement.val(scope.ngModel); - - converter.hooks.chain("postConversion", function (text) { - ngModel.$setViewValue(editorElement.val()); - - // update - scope.previewContent = text; - return text; - }); - - - // add watch for content - if (scope.showPreview != "false") { - scope.$watch('content', function () { - editor.refreshPreview(); + }); + + return { + restrict: 'E', + require: 'ngModel', + scope: { + ngModel: '=', + placeholder: '@', + showPreview: '@', + help: '&', + insertImage: '&', + editorClass: '=?', + editorRows: '@', + previewClass: '=?', + previewContent: '=?' + }, + link: function (scope, element, attrs, ngModel) { + + scope.changed = function () { + ngModel.$setDirty(); + scope.$parent.$eval(attrs.ngChange); + }; + + + var editorUniqueId; + + if (attrs.id === null) { + editorUniqueId = nextId++; + } else { + editorUniqueId = attrs.id; + } + + // just hide the preview, we still need it for 'onPreviewRefresh' hook + var previewHiddenStyle = scope.showPreview == 'false' ? 'display: none;' : ''; + + var placeholder = attrs.placeholder || ''; + var editorRows = attrs.editorRows || '10'; + + var newElement = $compile( + '
' + + '
' + + '
' + + '' + + '
' + + '
' + + '
' + + '
')(scope); + + // html() doesn't work + element.append(newElement); + + var help = angular.isFunction(scope.help) ? scope.help : function () { + // redirect to the guide by default + $window.open('http://daringfireball.net/projects/markdown/syntax', '_blank'); + }; + + var editor = new Markdown.Editor(converter, '-' + editorUniqueId, { + handler: help }); - } - editor.hooks.chain("onPreviewRefresh", function () { - // wire up changes caused by user interaction with the pagedown controls - // and do within $apply - $timeout(function () { - scope.content = editorElement.val(); + + + var editorElement = angular.element(document.getElementById('wmd-input-' + editorUniqueId)); + + editorElement.val(scope.ngModel); + + converter.hooks.chain('postConversion', function (text) { + ngModel.$setViewValue(editorElement.val()); + + // update + scope.previewContent = text; + return text; }); - }); - - if (angular.isFunction(scope.insertImage)) { - editor.hooks.set("insertImageDialog", function (callback) { - // expect it to return a promise or a url string - var result = scope.insertImage(); - - // Note that you cannot call the callback directly from the hook; you have to wait for the current scope to be exited. - // https://code.google.com/p/pagedown/wiki/PageDown#insertImageDialog + + + // add watch for content + if (scope.showPreview != 'false') { + scope.$watch('content', function () { + editor.refreshPreview(); + }); + } + editor.hooks.chain('onPreviewRefresh', function () { + // wire up changes caused by user interaction with the pagedown controls + // and do within $apply $timeout(function () { - if (!result) { - // must be null to indicate failure - callback(null); - } else { - // safe way to handle either string or promise - $q.when(result).then( - function success(imgUrl) { - callback(imgUrl); - }, - function error(reason) { - callback(null); - } - ); - } + scope.content = editorElement.val(); }); - - return true; }); - } - - editor.run(); - } - } - }]) - .directive("pagedownViewer", ['$compile', '$sce', function ($compile, $sce) { - var converter = Markdown.getSanitizingConverter(); - Markdown.Extra.init(converter, mdExtraOptions); - - return { - restrict: "E", - scope: { - content: "=" - }, - link: function (scope, element, attrs) { - var run = function run() { - if (!scope.content) { - scope.sanitizedContent = ''; - return; + + if (angular.isFunction(scope.insertImage)) { + editor.hooks.set('insertImageDialog', function (callback) { + // expect it to return a promise or a url string + var result = scope.insertImage(); + + // Note that you cannot call the callback directly from the hook; you have to wait for the current scope to be exited. + // https://code.google.com/p/pagedown/wiki/PageDown#insertImageDialog + $timeout(function () { + if (!result) { + // must be null to indicate failure + callback(null); + } else { + // safe way to handle either string or promise + $q.when(result).then( + function success(imgUrl) { + callback(imgUrl); + }, + function error(reason) { + callback(null); + } + ); + } + }); + + return true; + }); } - - scope.sanitizedContent = $sce.trustAsHtml(converter.makeHtml(scope.content)); - }; - - scope.$watch("content", run); - - run(); - - var newElementHtml = "

"; - var newElement = $compile(newElementHtml)(scope); - - element.append(newElement); - } - } - }]); + + editor.run(); + } + }; + }]) + .directive('pagedownViewer', ['$compile', '$sce', function ($compile, $sce) { + var converter = Markdown.getSanitizingConverter(); + Markdown.Extra.init(converter, mdExtraOptions); + + return { + restrict: 'E', + scope: { + content: '=' + }, + link: function (scope, element, attrs) { + var run = function run() { + if (!scope.content) { + scope.sanitizedContent = ''; + return; + } + + scope.sanitizedContent = $sce.trustAsHtml(converter.makeHtml(scope.content)); + }; + + scope.$watch('content', run); + + run(); + + var newElementHtml = '

'; + var newElement = $compile(newElementHtml)(scope); + + element.append(newElement); + } + }; + }]); +})(); diff --git a/bower.json b/bower.json index 794b5d6..02320cc 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "angular-pagedown", - "version": "0.4.4", + "version": "0.4.5", "main": [ "angular-pagedown.css", "angular-pagedown.js" diff --git a/demo/index.html b/demo/index.html new file mode 100644 index 0000000..ae6cefa --- /dev/null +++ b/demo/index.html @@ -0,0 +1,33 @@ + + + + + + angular-pagedown demo + + + + + + + + + + + + + +
+ +
+
+
+

This is an independent viewer

+ +
+ + \ No newline at end of file diff --git a/demo/script.js b/demo/script.js new file mode 100644 index 0000000..e77444b --- /dev/null +++ b/demo/script.js @@ -0,0 +1,24 @@ +angular.module("myApp", ["ui.pagedown"]) + +.controller("myController", function($scope, $window, $q) { + + $scope.data = { + content: "Wee *wang* **wang**!", + placeholder: "Enter something here.." + }; + + $scope.showSomeHelp = function showSomeHelp() { + // this is what the default will do + $window.open("http://daringfireball.net/projects/markdown/syntax", "_blank"); + }; + + $scope.insertImage = function insertImage() { + var deferred = $q.defer(); + + // or you can return a string straightaway + deferred.resolve("http://www.discoposse.com/wp-content/uploads/2014/08/test-all-the-things.jpg"); + + return deferred.promise; + }; + +}); \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..d2491e0 --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,45 @@ +var gulp = require('gulp'); + +var jshint = require('gulp-jshint'); +var uglify = require('gulp-uglify'); +var rename = require('gulp-rename'); +var minifyCss = require('gulp-minify-css'); +var browserSync = require('browser-sync').create(); + +gulp.task('lint', function() { + return gulp.src(['*.js', '!*.min.js']) + .pipe(jshint()) + .pipe(jshint.reporter('default')); +}); + +gulp.task('scripts', function() { + return gulp.src(['*.js', '!*.min.js']) + .pipe(rename('.min.js')) + .pipe(uglify()); +}); + +gulp.task('styles', function() { + return gulp.src(['*.css', '!*.min.css']) + .pipe(rename('.min.css')) + .pipe(minifyCss({compatibility: 'ie8'})); +}); + +gulp.task('browser-sync', function() { + browserSync.init({ + server: { + baseDir: ["./", "demo"], + routes: { + "/bower_components": "bower_components" + } + } + }); +}); + +gulp.task('watch', function() { + gulp.watch(['*.js', '!*.min.js'], ['lint', 'scripts']); + gulp.watch(['*.css', '!*.min.css'], ['styles']); + gulp.watch(['demo/*.html', '*.js', '!*.min.js', '*.css', '!*.min.css']).on("change", browserSync.reload); +}); + +gulp.task('default', ['lint', 'scripts', 'styles', 'watch']); +gulp.task('serve', ['lint', 'scripts', 'styles', 'browser-sync', 'watch']); \ No newline at end of file From 48dc8b5eb6fc6d8351c2b0b21c1a4f7d624c9001 Mon Sep 17 00:00:00 2001 From: Bastien Date: Wed, 25 Nov 2015 22:56:37 +0100 Subject: [PATCH 2/2] Maj version angular, attribute to remove the button bar and gulp corrections --- README.md | 5 +++++ angular-pagedown.js | 6 ++++-- angular-pagedown.min.css | 2 +- angular-pagedown.min.js | 2 +- bower.json | 2 +- demo/index.html | 25 +++++++++++++------------ demo/script.js | 12 ++++++++---- gulpfile.js | 22 ++++++++++++---------- package.json | 13 +++++++++++++ 9 files changed, 58 insertions(+), 31 deletions(-) create mode 100644 package.json diff --git a/README.md b/README.md index 5e89351..8faa092 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,11 @@ Options: 1. Should a live preview be displayed. 1. *Boolean*: Default to true +#### show-button-bar + +1. Should the button bar be displayed. +1. *Boolean*: Default to true + #### help 1. An expression to invoke upon clicking the help (?) button. diff --git a/angular-pagedown.js b/angular-pagedown.js index 9b1b369..582bcd5 100644 --- a/angular-pagedown.js +++ b/angular-pagedown.js @@ -18,7 +18,7 @@ return '
' + rbg(inner) + '
\n'; }); }); - + return { restrict: 'E', require: 'ngModel', @@ -26,6 +26,7 @@ ngModel: '=', placeholder: '@', showPreview: '@', + showButtonBar: '@', help: '&', insertImage: '&', editorClass: '=?', @@ -51,6 +52,7 @@ // just hide the preview, we still need it for 'onPreviewRefresh' hook var previewHiddenStyle = scope.showPreview == 'false' ? 'display: none;' : ''; + var buttonBarHiddenStyle = scope.showButtonBar == 'false' ? 'display: none;' : ''; var placeholder = attrs.placeholder || ''; var editorRows = attrs.editorRows || '10'; @@ -58,7 +60,7 @@ var newElement = $compile( '
' + '
' + - '
' + + '
' + '
")(a);s.append(p);var v=angular.isFunction(a.help)?a.help:function(){t.open("http://daringfireball.net/projects/markdown/syntax","_blank")},m=new Markdown.Editor(r,"-"+d,{handler:v});r.hooks.chain("postConversion",function(n){return a.previewContent=n,n});var h=angular.element(document.getElementById("wmd-input-"+d));"false"!=a.showPreview&&a.$watch("content",function(){m.refreshPreview()}),m.hooks.chain("onPreviewRefresh",function(){e(function(){a.content=h.val()})}),angular.isFunction(a.insertImage)&&m.hooks.set("insertImageDialog",function(n){var t=a.insertImage();return e(function(){t?i.when(t).then(function(e){n(e)},function(){n(null)}):n(null)}),!0}),m.run()}}}]).directive("pagedownViewer",["$compile","$sce",function(n,e){var t=Markdown.getSanitizingConverter();return Markdown.Extra.init(t,mdExtraOptions),{restrict:"E",scope:{content:"="},link:function(i,o){var r=function(){return i.content?void(i.sanitizedContent=e.trustAsHtml(t.makeHtml(i.content))):void(i.sanitizedContent="")};i.$watch("content",r),r();var a="

",s=n(a)(i);o.append(s)}}}]); \ No newline at end of file +!function(){"use strict";var n={extensions:"all",table_class:"table"};angular.module("ui.pagedown",[]).directive("pagedownEditor",["$compile","$timeout","$window","$q",function(e,t,i,o){var a=0,r=Markdown.getSanitizingConverter();return Markdown.Extra.init(r,n),r.hooks.chain("preBlockGamut",function(n,e){return n.replace(/^ {0,3}""" *\n((?:.*?\n)+?) {0,3}""" *$/gm,function(n,t){return"
"+e(t)+"
\n"})}),{restrict:"E",require:"ngModel",scope:{ngModel:"=",placeholder:"@",showPreview:"@",showButtonBar:"@",help:"&",insertImage:"&",editorClass:"=?",editorRows:"@",previewClass:"=?",previewContent:"=?"},link:function(n,l,s,d){n.changed=function(){d.$setDirty(),n.$parent.$eval(s.ngChange)};var c;c=null===s.id?a++:s.id;var u="false"==n.showPreview?"display: none;":"",w="false"==n.showButtonBar?"display: none;":"",p=s.placeholder||"",v=s.editorRows||"10",g=e('
")(n);l.append(g);var h=angular.isFunction(n.help)?n.help:function(){i.open("http://daringfireball.net/projects/markdown/syntax","_blank")},m=new Markdown.Editor(r,"-"+c,{handler:h}),f=angular.element(document.getElementById("wmd-input-"+c));f.val(n.ngModel),r.hooks.chain("postConversion",function(e){return d.$setViewValue(f.val()),n.previewContent=e,e}),"false"!=n.showPreview&&n.$watch("content",function(){m.refreshPreview()}),m.hooks.chain("onPreviewRefresh",function(){t(function(){n.content=f.val()})}),angular.isFunction(n.insertImage)&&m.hooks.set("insertImageDialog",function(e){var i=n.insertImage();return t(function(){i?o.when(i).then(function(n){e(n)},function(n){e(null)}):e(null)}),!0}),m.run()}}}]).directive("pagedownViewer",["$compile","$sce",function(e,t){var i=Markdown.getSanitizingConverter();return Markdown.Extra.init(i,n),{restrict:"E",scope:{content:"="},link:function(n,o,a){var r=function(){return n.content?void(n.sanitizedContent=t.trustAsHtml(i.makeHtml(n.content))):void(n.sanitizedContent="")};n.$watch("content",r),r();var l='

',s=e(l)(n);o.append(s)}}}])}(); \ No newline at end of file diff --git a/bower.json b/bower.json index 02320cc..d4f55e5 100644 --- a/bower.json +++ b/bower.json @@ -6,7 +6,7 @@ "angular-pagedown.js" ], "dependencies": { - "angular": "~1.2", + "angular": "~1.4", "pagedown": "^1.1.0" } } diff --git a/demo/index.html b/demo/index.html index ae6cefa..eea2a79 100644 --- a/demo/index.html +++ b/demo/index.html @@ -1,27 +1,28 @@ - - - - angular-pagedown demo - - - + + + + angular-pagedown demo + + + - + - + - - + +
+

@@ -29,5 +30,5 @@

This is an independent viewer

- + \ No newline at end of file diff --git a/demo/script.js b/demo/script.js index e77444b..c906711 100644 --- a/demo/script.js +++ b/demo/script.js @@ -1,17 +1,17 @@ angular.module("myApp", ["ui.pagedown"]) .controller("myController", function($scope, $window, $q) { - + $scope.data = { content: "Wee *wang* **wang**!", placeholder: "Enter something here.." }; - + $scope.showSomeHelp = function showSomeHelp() { // this is what the default will do $window.open("http://daringfireball.net/projects/markdown/syntax", "_blank"); }; - + $scope.insertImage = function insertImage() { var deferred = $q.defer(); @@ -20,5 +20,9 @@ angular.module("myApp", ["ui.pagedown"]) return deferred.promise; }; - + + $scope.shout = function shout() { + // test update the content programatically + $scope.data.content += '\n\nTell Laura I love her'; + }; }); \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js index d2491e0..971e274 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -7,21 +7,23 @@ var minifyCss = require('gulp-minify-css'); var browserSync = require('browser-sync').create(); gulp.task('lint', function() { - return gulp.src(['*.js', '!*.min.js']) + return gulp.src('angular-pagedown.js') .pipe(jshint()) .pipe(jshint.reporter('default')); }); gulp.task('scripts', function() { - return gulp.src(['*.js', '!*.min.js']) - .pipe(rename('.min.js')) - .pipe(uglify()); + return gulp.src('angular-pagedown.js') + .pipe(rename('angular-pagedown.min.js')) + .pipe(uglify()) + .pipe(gulp.dest('./')); }); gulp.task('styles', function() { - return gulp.src(['*.css', '!*.min.css']) - .pipe(rename('.min.css')) - .pipe(minifyCss({compatibility: 'ie8'})); + return gulp.src('angular-pagedown.css') + .pipe(rename('angular-pagedown.min.css')) + .pipe(minifyCss({compatibility: 'ie8'})) + .pipe(gulp.dest('./')); }); gulp.task('browser-sync', function() { @@ -36,9 +38,9 @@ gulp.task('browser-sync', function() { }); gulp.task('watch', function() { - gulp.watch(['*.js', '!*.min.js'], ['lint', 'scripts']); - gulp.watch(['*.css', '!*.min.css'], ['styles']); - gulp.watch(['demo/*.html', '*.js', '!*.min.js', '*.css', '!*.min.css']).on("change", browserSync.reload); + gulp.watch('angular-pagedown.js', ['lint', 'scripts']); + gulp.watch('angular-pagedown.css', ['styles']); + gulp.watch(['demo/*.html', 'angular-pagedown.min.js', 'angular-pagedown.min.css']).on("change", browserSync.reload); }); gulp.task('default', ['lint', 'scripts', 'styles', 'watch']); diff --git a/package.json b/package.json new file mode 100644 index 0000000..5eae5e4 --- /dev/null +++ b/package.json @@ -0,0 +1,13 @@ +{ + "name": "angular-pagedown", + "private": true, + "devDependencies": { + "browser-sync": "^2.10.0", + "gulp": "^3.9.0", + "gulp-jshint": "^2.0.0", + "gulp-minify-css": "^1.2.1", + "gulp-rename": "^1.2.2", + "gulp-uglify": "^1.5.1", + "jshint": "^2.8.0" + } +}