From 03ece0accf788c36468b218606b8696c72ae66a2 Mon Sep 17 00:00:00 2001 From: flyacts GmbH Date: Mon, 3 Nov 2014 14:24:11 +0100 Subject: [PATCH] initial commit --- .gitignore | 4 + Gruntfile.js | 18 +++ LICENSE.txt | 24 +++ README.md | 3 + bower.json | 17 +++ demo.html | 29 ++++ package.json | 28 ++++ src/ng-quill.js | 345 ++++++++++++++++++++++++++++++++++++++++++++ src/ng-quill.min.js | 1 + 9 files changed, 469 insertions(+) create mode 100644 .gitignore create mode 100644 Gruntfile.js create mode 100644 LICENSE.txt create mode 100644 README.md create mode 100644 bower.json create mode 100644 demo.html create mode 100644 package.json create mode 100644 src/ng-quill.js create mode 100644 src/ng-quill.min.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5becf69 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.swp +bower_components +.DS_Store +node_modules diff --git a/Gruntfile.js b/Gruntfile.js new file mode 100644 index 0000000..7bac051 --- /dev/null +++ b/Gruntfile.js @@ -0,0 +1,18 @@ +module.exports = function (grunt) { + + // Project configuration. + grunt.initConfig({ + pkg: grunt.file.readJSON('package.json'), + uglify: { + my_target: { + files: { + "src/ng-quill.min.js": "src/ng-quill.js" + } + } + } + }); + + grunt.loadNpmTasks('grunt-contrib-uglify'); + + grunt.registerTask('default', ['uglify']); +}; diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..00c9ca2 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,24 @@ +The MIT License (MIT) + +Copyright (c) 2014 Bengt Weiße other contributors + +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. diff --git a/README.md b/README.md new file mode 100644 index 0000000..f363f06 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# ngQuill + +ngQuickDate is an [Angular.js](http://angularjs.org/) directive for Quilll rich text editor. \ No newline at end of file diff --git a/bower.json b/bower.json new file mode 100644 index 0000000..dd8f690 --- /dev/null +++ b/bower.json @@ -0,0 +1,17 @@ +{ + "name": "ngQuill", + "version": "0.1", + "main": ["src/ng-quill.js"], + "ignore": [ + "bower_components", + "node_modules", + "spec", + "src", + "package.json", + "Gruntfile.js" + ], + "dependencies": { + "quill": "~0.18.1", + "angularjs": "~1.3.1" + } +} diff --git a/demo.html b/demo.html new file mode 100644 index 0000000..68ece80 --- /dev/null +++ b/demo.html @@ -0,0 +1,29 @@ + + + Quill Test + + + + + + + + + + + + + + +
+ +
+ + \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..95aa6ad --- /dev/null +++ b/package.json @@ -0,0 +1,28 @@ +{ + "name": "ngQuill", + "description": "Angular directive for rich text editor Quill", + "author": "Bnegt Weiße ", + "homepage": "https://github.com/KillerCodeMonkey/ngQuill", + "devDependencies": { + "grunt": "~0.4.3", + "grunt-contrib-uglify": "~0.6.0" + }, + "engines": { + "node": ">=0.10" + }, + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/KillerCodeMonkey/ngQuill" + }, + "bugs": { + "url": "https://github.com/KillerCodeMonkey/ngQuill/issues" + }, + "keywords": [ + "editor", + "rich text", + "wysiwyg", + "angular", + "directive" + ] +} \ No newline at end of file diff --git a/src/ng-quill.js b/src/ng-quill.js new file mode 100644 index 0000000..d856559 --- /dev/null +++ b/src/ng-quill.js @@ -0,0 +1,345 @@ +/*global Quill*/ +(function () { + + var app; + // declar ngQuill module + app = angular.module("ngQuill", []); + + app.service('ngQuillService', function () { + // formats lists + this.formats = [ + 'link', + 'image', + 'bold', + 'italic', + 'underline', + 'strike', + 'color', + 'background', + 'align', + 'font', + 'size', + 'bullet', + 'list' + ]; + // default translations + this.defaultTranslation = { + font: 'Font', + size: 'Size', + small: 'Small', + normal: 'Normal', + large: 'Large', + huge: 'Huge', + bold: 'Bold', + italic: 'Italic', + underline: 'Underline', + strike: 'Strikethrough', + textColor: 'Text Color', + backgroundColor: 'Background Color', + list: 'List', + bullet: 'Bullet', + textAlign: 'Text Align', + left: 'Left', + center: 'Center', + right: 'Right', + justify: 'Justify', + link: 'Link', + image: 'Image', + visitURL: 'Visit URL', + change: 'Change', + done: 'Done', + cancel: 'Cancel', + insert: 'Insert', + preview: 'Preview' + }; + // validate formats + this.validateFormats = function (checkFormats) { + var correctFormats = [], + self = this, + i = 0; + + for (i; i < checkFormats.length; i = i + 1) { + if (self.formats.indexOf(checkFormats[i]) !== -1) { + correctFormats.push(checkFormats[i]); + } + } + + return correctFormats; + }; + }); + + app.directive("ngQuillEditor", [ + '$timeout', + 'ngQuillService', + function ($timeout, ngQuillService) { + return { + scope: { + 'toolbarEntries': '@?', + 'toolbar': '@?', + 'linkTooltip': '@?', + 'imageTooltip': '@?', + 'theme': '@?', + 'translations': '=?', + 'required': '@?editorRequired', + 'readOnly': '@?', + 'errorClass': '@?', + 'ngModel': '=' + }, + require: 'ngModel', + restrict: 'E', + templateUrl: 'ngQuill/template.html', + link: function ($scope, element, attr, ngModel) { + var config = { + theme: $scope.theme || 'snow', + readOnly: $scope.readOnly || false, + formats: $scope.toolbarEntries ? ngQuillService.validateFormats($scope.toolbarEntries.split(' ')) : ngQuillService.formats, + modules: {} + }, + changed = false, + editor, + setClass = function () { + // if editor content length <= 1 and content is required -> add custom error clas and ng-invalid + if ($scope.required && (!$scope.modelLength || $scope.modelLength <= 1)) { + element.addClass('ng-invalid'); + element.removeClass('ng-valid'); + if ($scope.errorClass && changed) { + element.children().addClass($scope.errorClass); + } + } else { // set to valid + element.removeClass('ng-invalid'); + element.addClass('ng-valid'); + if ($scope.errorClass) { + element.children().removeClass($scope.errorClass); + } + } + }; + + // set required flag (if text editor is required) + if ($scope.required && $scope.required === 'true') { + $scope.required = true; + } else { + $scope.required = false; + } + + // default translations + $scope.dict = ngQuillService.defaultTranslation; + + $scope.shouldShow = function (formats) { + var okay = false, + i = 0; + for (i; i < formats.length; i = i + 1) { + if (config.formats.indexOf(formats[i]) !== -1) { + okay = true; + break; + } + } + + return okay; + }; + + // if there are custom translations + if ($scope.translations) { + $scope.dict = $scope.translations; + } + + // add tooltip modules + if ($scope.linkTooltip && $scope.linkTooltip === 'true') { + config.modules['link-tooltip'] = { + template: '' + $scope.dict.visitURL + ': ' + + '' + + '' + + ' - ' + + '' + $scope.dict.change + '' + + '' + $scope.dict.done + '' + }; + } + if ($scope.imageTooltip && $scope.imageTooltip === 'true') { + config.modules['image-tooltip'] = { + template: '' + + '
' + + ' ' + $scope.dict.preview + '' + + '
' + + '' + $scope.dict.cancel + '' + + '' + $scope.dict.insert + '' + }; + } + + // init editor + editor = new Quill(element[0].querySelector('.advanced-wrapper .editor-container'), config); + + // add toolbar afterwards with a timeout to be sure that translations has replaced. + if ($scope.toolbar && $scope.toolbar === 'true') { + $timeout(function () { + editor.addModule('toolbar', { + container: element[0].querySelector('.advanced-wrapper .toolbar-container') + }); + $scope.toolbarCreated = true; + }, 0); + } + + // provide event to get recognized when editor is created -> pass editor object. + $scope.$broadcast('editorCreated', editor); + + // set initial value + $scope.$watch(function () { + return $scope.ngModel; + }, function (newText) { + if (newText !== undefined && !changed) { + editor.setHTML(newText); + $scope.modelLength = editor.getLength(); + } + }); + + // Update model on textchange + editor.on('text-change', function () { + // initial change + if (!changed) { + changed = true; + } else { + $timeout(function () { + $scope.modelLength = editor.getLength(); + setClass(); + ngModel.$setViewValue(editor.getHTML()); + }, 0); + } + }); + } + }; + } + ]); + + app.run([ + '$templateCache', + '$rootScope', + '$window', + function ($templateCache, $rootScope, $window) { + + $rootScope.$on('$locationChangeSuccess', function () { + if ($window.Quill && $window.Quill.editors) { + $window.Quill.editors.length = 0; + } + }); + + return $templateCache.put('ngQuill/template.html', + '
' + + '
' + + '
' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '
' + + '
' + + '' + + '
' + + '
'); + } + ]); +}).call(this); diff --git a/src/ng-quill.min.js b/src/ng-quill.min.js new file mode 100644 index 0000000..00a27b3 --- /dev/null +++ b/src/ng-quill.min.js @@ -0,0 +1 @@ +(function(){var a;a=angular.module("ngQuill",[]),a.service("ngQuillService",function(){this.formats=["link","image","bold","italic","underline","strike","color","background","align","font","size","bullet","list"],this.defaultTranslation={font:"Font",size:"Size",small:"Small",normal:"Normal",large:"Large",huge:"Huge",bold:"Bold",italic:"Italic",underline:"Underline",strike:"Strikethrough",textColor:"Text Color",backgroundColor:"Background Color",list:"List",bullet:"Bullet",textAlign:"Text Align",left:"Left",center:"Center",right:"Right",justify:"Justify",link:"Link",image:"Image",visitURL:"Visit URL",change:"Change",done:"Done",cancel:"Cancel",insert:"Insert",preview:"Preview"},this.validateFormats=function(a){var b=[],c=this,d=0;for(d;d'+c.dict.visitURL+':  - '+c.dict.change+''+c.dict.done+""}),c.imageTooltip&&"true"===c.imageTooltip&&(h.modules["image-tooltip"]={template:'
'+c.dict.preview+'
'+c.dict.cancel+''+c.dict.insert+""}),g=new Quill(d[0].querySelector(".advanced-wrapper .editor-container"),h),c.toolbar&&"true"===c.toolbar&&a(function(){g.addModule("toolbar",{container:d[0].querySelector(".advanced-wrapper .toolbar-container")}),c.toolbarCreated=!0},0),c.$broadcast("editorCreated",g),c.$watch(function(){return c.ngModel},function(a){void 0===a||i||(g.setHTML(a),c.modelLength=g.getLength())}),g.on("text-change",function(){i?a(function(){c.modelLength=g.getLength(),j(),f.$setViewValue(g.getHTML())},0):i=!0})}}}]),a.run(["$templateCache","$rootScope","$window",function(a,b,c){return b.$on("$locationChangeSuccess",function(){c.Quill&&c.Quill.editors&&(c.Quill.editors.length=0)}),a.put("ngQuill/template.html",'
')}])}).call(this); \ No newline at end of file