angular-summernote
Advanced tools
Comparing version
{ | ||
"name": "angular-summernote", | ||
"description": "AngularJS directive to Summernote", | ||
"version": "0.7.0", | ||
"version": "0.7.1", | ||
"main": [ | ||
@@ -6,0 +6,0 @@ "./dist/angular-summernote.js" |
@@ -0,1 +1,12 @@ | ||
# 0.7.1 (2016-01-22) | ||
* Fix a bug that load 2 editor on IE(it is a workaround) | ||
[#98](https://github.com/summernote/angular-summernote/issues/98) | ||
* Fix a bug when content is empty | ||
[#105](https://github.com/summernote/angular-summernote/pull/105) | ||
* Support placeholder, min height and max height options | ||
[#97](https://github.com/summernote/angular-summernote/pull/97), | ||
[#104](https://github.com/summernote/angular-summernote/pull/104) | ||
* Supoort on-media-delete callback | ||
[#92](https://github.com/summernote/angular-summernote/issues/92) | ||
# 0.7.0 (2015-12-11) | ||
@@ -2,0 +13,0 @@ * Make compatible with summernote v0.7.0 |
@@ -1,2 +0,2 @@ | ||
/* angular-summernote v0.7.0 | (c) 2014, 2015 JeongHoon Byun | MIT license */ | ||
/* angular-summernote v0.7.1 | (c) 2016 JeongHoon Byun | MIT license */ | ||
/* global angular */ | ||
@@ -11,3 +11,6 @@ angular.module('summernote', []) | ||
if (angular.isDefined($attrs.height)) { summernoteConfig.height = $attrs.height; } | ||
if (angular.isDefined($attrs.height)) { summernoteConfig.height = +$attrs.height; } | ||
if (angular.isDefined($attrs.minHeight)) { summernoteConfig.minHeight = +$attrs.minHeight; } | ||
if (angular.isDefined($attrs.maxHeight)) { summernoteConfig.maxHeight = +$attrs.maxHeight; } | ||
if (angular.isDefined($attrs.placeholder)) { summernoteConfig.placeholder = $attrs.placeholder; } | ||
if (angular.isDefined($attrs.focus)) { summernoteConfig.focus = true; } | ||
@@ -34,2 +37,13 @@ if (angular.isDefined($attrs.airmode)) { summernoteConfig.airMode = true; } | ||
} | ||
if (angular.isDefined($attrs.onMediaDelete)) { | ||
callbacks.onMediaDelete = function(target) { | ||
// make new object that has information of target to avoid error:isecdom | ||
var removedMedia = {attrs: {}}; | ||
removedMedia.tagName = target[0].tagName; | ||
angular.forEach(target[0].attributes, function(attr) { | ||
removedMedia.attrs[attr.name] = attr.value; | ||
}); | ||
$scope.mediaDelete({target: removedMedia}); | ||
} | ||
} | ||
@@ -48,4 +62,6 @@ this.activate = function(scope, element, ngModel) { | ||
callbacks.onChange = function(contents) { | ||
if (element.summernote('isEmpty')) { contents = ''; } | ||
updateNgModel(); | ||
$timeout(function() { | ||
if (element.summernote('isEmpty')) { contents = ''; } | ||
updateNgModel(); | ||
}, 0); | ||
$scope.change({contents:contents, editable: $scope.editable}); | ||
@@ -85,3 +101,7 @@ }; | ||
ngModel.$render = function() { | ||
element.summernote('code', ngModel.$viewValue || ''); | ||
if (ngModel.$viewValue) { | ||
element.summernote('code', ngModel.$viewValue); | ||
} else { | ||
element.summernote('empty'); | ||
} | ||
}; | ||
@@ -134,3 +154,4 @@ } | ||
change: '&onChange', | ||
imageUpload: '&onImageUpload' | ||
imageUpload: '&onImageUpload', | ||
mediaDelete: '&onMediaDelete' | ||
}, | ||
@@ -137,0 +158,0 @@ template: '<div class="summernote"></div>', |
@@ -1,2 +0,2 @@ | ||
/* angular-summernote v0.7.0 | (c) 2014, 2015 JeongHoon Byun | MIT license */ | ||
angular.module("summernote",[]).controller("SummernoteController",["$scope","$attrs","$timeout",function($scope,$attrs,$timeout){"use strict";var currentElement,summernoteConfig=$scope.summernoteConfig||{};if(angular.isDefined($attrs.height)&&(summernoteConfig.height=$attrs.height),angular.isDefined($attrs.focus)&&(summernoteConfig.focus=!0),angular.isDefined($attrs.airmode)&&(summernoteConfig.airMode=!0),angular.isDefined($attrs.lang)){if(!angular.isDefined($.summernote.lang[$attrs.lang]))throw new Error('"'+$attrs.lang+'" lang file must be exist.');summernoteConfig.lang=$attrs.lang}var callbacks={};callbacks.onInit=$scope.init,callbacks.onEnter=function(evt){$scope.enter({evt:evt})},callbacks.onFocus=function(evt){$scope.focus({evt:evt})},callbacks.onPaste=function(evt){$scope.paste({evt:evt})},callbacks.onKeyup=function(evt){$scope.keyup({evt:evt})},callbacks.onKeydown=function(evt){$scope.keydown({evt:evt})},angular.isDefined($attrs.onImageUpload)&&(callbacks.onImageUpload=function(files){$scope.imageUpload({files:files,editable:$scope.editable})}),this.activate=function(scope,element,ngModel){var updateNgModel=function(){var newValue=element.summernote("code");element.summernote("isEmpty")&&(newValue=""),ngModel&&ngModel.$viewValue!==newValue&&$timeout(function(){ngModel.$setViewValue(newValue)},0)};callbacks.onChange=function(contents){element.summernote("isEmpty")&&(contents=""),updateNgModel(),$scope.change({contents:contents,editable:$scope.editable})},callbacks.onBlur=function(evt){!summernoteConfig.airMode&&element.blur(),$scope.blur({evt:evt})},summernoteConfig.callbacks=callbacks,element.summernote(summernoteConfig);var unwatchNgModel,editor$=element.next(".note-editor");editor$.find(".note-toolbar").click(function(){updateNgModel(),editor$.hasClass("codeview")?(editor$.on("keyup",updateNgModel),ngModel&&(unwatchNgModel=scope.$watch(function(){return ngModel.$modelValue},function(newValue){editor$.find(".note-codable").val(newValue)}))):(editor$.off("keyup",updateNgModel),angular.isFunction(unwatchNgModel)&&unwatchNgModel())}),ngModel&&(ngModel.$render=function(){element.summernote("code",ngModel.$viewValue||"")}),angular.isDefined($attrs.editable)&&($scope.editable=editor$.find(".note-editable")),angular.isDefined($attrs.editor)&&($scope.editor=element),currentElement=element,element.on("$destroy",function(){element.summernote("destroy"),$scope.summernoteDestroyed=!0})},$scope.$on("$destroy",function(){$scope.summernoteDestroyed||currentElement.summernote("destroy")})}]).directive("summernote",[function(){"use strict";return{restrict:"EA",transclude:"element",replace:!0,require:["summernote","?ngModel"],controller:"SummernoteController",scope:{summernoteConfig:"=config",editable:"=",editor:"=",init:"&onInit",enter:"&onEnter",focus:"&onFocus",blur:"&onBlur",paste:"&onPaste",keyup:"&onKeyup",keydown:"&onKeydown",change:"&onChange",imageUpload:"&onImageUpload"},template:'<div class="summernote"></div>',link:function(scope,element,attrs,ctrls,transclude){var summernoteController=ctrls[0],ngModel=ctrls[1];transclude(scope,function(clone,scope){element.append(clone.html())}),summernoteController.activate(scope,element,ngModel)}}}]); | ||
/* angular-summernote v0.7.1 | (c) 2016 JeongHoon Byun | MIT license */ | ||
angular.module("summernote",[]).controller("SummernoteController",["$scope","$attrs","$timeout",function($scope,$attrs,$timeout){"use strict";var currentElement,summernoteConfig=$scope.summernoteConfig||{};if(angular.isDefined($attrs.height)&&(summernoteConfig.height=+$attrs.height),angular.isDefined($attrs.minHeight)&&(summernoteConfig.minHeight=+$attrs.minHeight),angular.isDefined($attrs.maxHeight)&&(summernoteConfig.maxHeight=+$attrs.maxHeight),angular.isDefined($attrs.placeholder)&&(summernoteConfig.placeholder=$attrs.placeholder),angular.isDefined($attrs.focus)&&(summernoteConfig.focus=!0),angular.isDefined($attrs.airmode)&&(summernoteConfig.airMode=!0),angular.isDefined($attrs.lang)){if(!angular.isDefined($.summernote.lang[$attrs.lang]))throw new Error('"'+$attrs.lang+'" lang file must be exist.');summernoteConfig.lang=$attrs.lang}var callbacks={};callbacks.onInit=$scope.init,callbacks.onEnter=function(evt){$scope.enter({evt:evt})},callbacks.onFocus=function(evt){$scope.focus({evt:evt})},callbacks.onPaste=function(evt){$scope.paste({evt:evt})},callbacks.onKeyup=function(evt){$scope.keyup({evt:evt})},callbacks.onKeydown=function(evt){$scope.keydown({evt:evt})},angular.isDefined($attrs.onImageUpload)&&(callbacks.onImageUpload=function(files){$scope.imageUpload({files:files,editable:$scope.editable})}),angular.isDefined($attrs.onMediaDelete)&&(callbacks.onMediaDelete=function(target){var removedMedia={attrs:{}};removedMedia.tagName=target[0].tagName,angular.forEach(target[0].attributes,function(attr){removedMedia.attrs[attr.name]=attr.value}),$scope.mediaDelete({target:removedMedia})}),this.activate=function(scope,element,ngModel){var updateNgModel=function(){var newValue=element.summernote("code");element.summernote("isEmpty")&&(newValue=""),ngModel&&ngModel.$viewValue!==newValue&&$timeout(function(){ngModel.$setViewValue(newValue)},0)};callbacks.onChange=function(contents){$timeout(function(){element.summernote("isEmpty")&&(contents=""),updateNgModel()},0),$scope.change({contents:contents,editable:$scope.editable})},callbacks.onBlur=function(evt){!summernoteConfig.airMode&&element.blur(),$scope.blur({evt:evt})},summernoteConfig.callbacks=callbacks,element.summernote(summernoteConfig);var unwatchNgModel,editor$=element.next(".note-editor");editor$.find(".note-toolbar").click(function(){updateNgModel(),editor$.hasClass("codeview")?(editor$.on("keyup",updateNgModel),ngModel&&(unwatchNgModel=scope.$watch(function(){return ngModel.$modelValue},function(newValue){editor$.find(".note-codable").val(newValue)}))):(editor$.off("keyup",updateNgModel),angular.isFunction(unwatchNgModel)&&unwatchNgModel())}),ngModel&&(ngModel.$render=function(){ngModel.$viewValue?element.summernote("code",ngModel.$viewValue):element.summernote("empty")}),angular.isDefined($attrs.editable)&&($scope.editable=editor$.find(".note-editable")),angular.isDefined($attrs.editor)&&($scope.editor=element),currentElement=element,element.on("$destroy",function(){element.summernote("destroy"),$scope.summernoteDestroyed=!0})},$scope.$on("$destroy",function(){$scope.summernoteDestroyed||currentElement.summernote("destroy")})}]).directive("summernote",[function(){"use strict";return{restrict:"EA",transclude:"element",replace:!0,require:["summernote","?ngModel"],controller:"SummernoteController",scope:{summernoteConfig:"=config",editable:"=",editor:"=",init:"&onInit",enter:"&onEnter",focus:"&onFocus",blur:"&onBlur",paste:"&onPaste",keyup:"&onKeyup",keydown:"&onKeydown",change:"&onChange",imageUpload:"&onImageUpload",mediaDelete:"&onMediaDelete"},template:'<div class="summernote"></div>',link:function(scope,element,attrs,ctrls,transclude){var summernoteController=ctrls[0],ngModel=ctrls[1];transclude(scope,function(clone,scope){element.append(clone.html())}),summernoteController.activate(scope,element,ngModel)}}}]); |
@@ -12,3 +12,3 @@ var gulp = require('gulp'), | ||
var banner = '/* angular-summernote v<%=pkg.version%> | (c) 2014, 2015 JeongHoon Byun | MIT license */\n'; | ||
var banner = '/* angular-summernote v<%=pkg.version%> | (c) 2016 JeongHoon Byun | MIT license */\n'; | ||
var isAngular12 = isAngular13 = false; | ||
@@ -15,0 +15,0 @@ |
{ | ||
"name": "angular-summernote", | ||
"description": "AngularJS directive to Summernote", | ||
"version": "0.7.0", | ||
"version": "0.7.1", | ||
"author": { | ||
@@ -6,0 +6,0 @@ "name": "\"Outsider\" Jeonghoon Byun", |
@@ -5,3 +5,2 @@ # angular-summernote - [AngularJS](http://angularjs.org/) directive to [Summernote](http://summernote.org/) | ||
[](http://gruntjs.com/) | ||
[](https://travis-ci.org/summernote/angular-summernote) | ||
@@ -36,3 +35,3 @@ [](https://gemnasium.com/summernote/angular-summernote) | ||
See at [JSFiddle](http://jsfiddle.net/outsider/n8dt4/246/embedded/result%2Chtml%2Cjs%2Ccss/) | ||
See at [JSFiddle](http://jsfiddle.net/outsider/n8dt4/271/embedded/result%2Chtml%2Cjs%2Ccss/) | ||
or run example in projects(need to run `bower install` before run) | ||
@@ -104,2 +103,35 @@ | ||
If you use the `removeMedia` button in popover, like below: | ||
``` | ||
<summernote airMode config="options" on-media-delete="mediaDelete(target)"></summernote> | ||
``` | ||
``` | ||
function DemoController($scope) { | ||
$scope.options = { | ||
popover: { | ||
image: [['remove', ['removeMedia']] ], | ||
air: [['insert', ['picture']]] | ||
} | ||
}; | ||
$scope.mediaDelete = function(target) { | ||
console.log('media is delted:', target); | ||
} | ||
} | ||
``` | ||
You can use the 'onMediaDelete` callback. The `target` object has information of the DOM that is removed like: | ||
``` | ||
{ | ||
tagName: "IMG", | ||
attrs: { | ||
data-filename: "image-name.jpg", | ||
src: "http://path/to/image", | ||
style: "width: 100px;" | ||
} | ||
} | ||
``` | ||
#### options object | ||
@@ -106,0 +138,0 @@ |
@@ -10,3 +10,6 @@ /* global angular */ | ||
if (angular.isDefined($attrs.height)) { summernoteConfig.height = $attrs.height; } | ||
if (angular.isDefined($attrs.height)) { summernoteConfig.height = +$attrs.height; } | ||
if (angular.isDefined($attrs.minHeight)) { summernoteConfig.minHeight = +$attrs.minHeight; } | ||
if (angular.isDefined($attrs.maxHeight)) { summernoteConfig.maxHeight = +$attrs.maxHeight; } | ||
if (angular.isDefined($attrs.placeholder)) { summernoteConfig.placeholder = $attrs.placeholder; } | ||
if (angular.isDefined($attrs.focus)) { summernoteConfig.focus = true; } | ||
@@ -33,2 +36,13 @@ if (angular.isDefined($attrs.airmode)) { summernoteConfig.airMode = true; } | ||
} | ||
if (angular.isDefined($attrs.onMediaDelete)) { | ||
callbacks.onMediaDelete = function(target) { | ||
// make new object that has information of target to avoid error:isecdom | ||
var removedMedia = {attrs: {}}; | ||
removedMedia.tagName = target[0].tagName; | ||
angular.forEach(target[0].attributes, function(attr) { | ||
removedMedia.attrs[attr.name] = attr.value; | ||
}); | ||
$scope.mediaDelete({target: removedMedia}); | ||
} | ||
} | ||
@@ -47,4 +61,6 @@ this.activate = function(scope, element, ngModel) { | ||
callbacks.onChange = function(contents) { | ||
if (element.summernote('isEmpty')) { contents = ''; } | ||
updateNgModel(); | ||
$timeout(function() { | ||
if (element.summernote('isEmpty')) { contents = ''; } | ||
updateNgModel(); | ||
}, 0); | ||
$scope.change({contents:contents, editable: $scope.editable}); | ||
@@ -84,3 +100,7 @@ }; | ||
ngModel.$render = function() { | ||
element.summernote('code', ngModel.$viewValue || ''); | ||
if (ngModel.$viewValue) { | ||
element.summernote('code', ngModel.$viewValue); | ||
} else { | ||
element.summernote('empty'); | ||
} | ||
}; | ||
@@ -133,3 +153,4 @@ } | ||
change: '&onChange', | ||
imageUpload: '&onImageUpload' | ||
imageUpload: '&onImageUpload', | ||
mediaDelete: '&onMediaDelete' | ||
}, | ||
@@ -136,0 +157,0 @@ template: '<div class="summernote"></div>', |
@@ -72,8 +72,33 @@ /** | ||
}); | ||
}); | ||
describe('"min-height" option', function() { | ||
it('should be 300 if it specified', function () { | ||
var element = $compile('<summernote min-height="300"></summernote>')($rootScope); | ||
$rootScope.$digest(); | ||
expect(element.next().find('.note-editable').css('min-height')).to.be.equal('300px'); | ||
}); | ||
}); | ||
// FIXME: summernote v0.7 has a bug in focus options | ||
// https://github.com/summernote/summernote/issues/1483 | ||
describe.skip('"focus" option', function() { | ||
describe('"max-height" option', function() { | ||
it('should be 500 if it specified', function () { | ||
var element = $compile('<summernote max-height="500"></summernote>')($rootScope); | ||
$rootScope.$digest(); | ||
expect(element.next().find('.note-editable').css('max-height')).to.be.equal('500px'); | ||
}); | ||
}); | ||
describe('"placeholder" option', function() { | ||
it('should placeholder', function () { | ||
var element = $compile('<summernote placeholder="This is a placeholder"></summernote>')($rootScope); | ||
$rootScope.$digest(); | ||
expect(element.next().find('.note-placeholder')).to.length(1); | ||
expect(element.next().find('.note-placeholder').text()).to.be.equal('This is a placeholder'); | ||
}); | ||
}); | ||
describe('"focus" option', function() { | ||
it('should be focused if it specified', function () { | ||
@@ -122,2 +147,4 @@ var el = $('<summernote focus height="400"></summernote>').appendTo(document.body); | ||
height: 300, | ||
minHeight: 200, | ||
maxHeight: 500, | ||
focus: true, | ||
@@ -141,2 +168,16 @@ toolbar: [ | ||
it('"minHeight" should be 300', function() { | ||
var element = $compile('<summernote config="summernoteConfig"></summernote>')(scope); | ||
$rootScope.$digest(); | ||
expect(element.next().find('.note-editable').css('min-height')).to.be.equal('200px'); | ||
}); | ||
it('"maxHeight" should be 300', function() { | ||
var element = $compile('<summernote config="summernoteConfig"></summernote>')(scope); | ||
$rootScope.$digest(); | ||
expect(element.next().find('.note-editable').css('max-height')).to.be.equal('500px'); | ||
}); | ||
it('toolbar should be customized', function() { | ||
@@ -359,2 +400,17 @@ var element = $compile('<summernote config="summernoteConfig"></summernote>')(scope); | ||
}); | ||
it('should empty summernote when model is empty', function() { | ||
// given | ||
scope.text = 'Hello World'; | ||
var element = $compile($('<summernote ng-Model="text"></summernote>').appendTo(document.body))(scope); | ||
scope.$digest(); | ||
// when | ||
scope.text = ''; | ||
scope.$digest(); | ||
// then | ||
expect(element.summernote('code')).to.not.equal(''); | ||
expect(element.summernote('isEmpty')).to.equal(true); | ||
}); | ||
}); | ||
@@ -586,5 +642,3 @@ | ||
// FIXME: summernote v0.7 has a bug with contents | ||
// https://github.com/summernote/summernote/issues/1468 | ||
it.skip('set blank html if no text in summernote directive', function() { | ||
it('set blank html if no text in summernote directive', function() { | ||
// given | ||
@@ -591,0 +645,0 @@ var scope = $rootScope.$new(); |
Sorry, the diff of this file is not supported yet
137899
4.86%1284
7%271
13.39%