<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0, maximum-scale=1.0"/>
  <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.4.0/css/font-awesome.min.css" rel="stylesheet" type="text/css" />
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.25.0/codemirror.min.css">
  <link href="https://cdnjs.cloudflare.com/ajax/libs/froala-editor/2.6.0/css/froala_editor.pkgd.min.css" rel="stylesheet" type="text/css" />
  <link href="https://cdnjs.cloudflare.com/ajax/libs/froala-editor/2.6.0/css/froala_style.min.css" rel="stylesheet" type="text/css" />
</head>

<body ng-app="myapp" ng-controller="myctrl">
  <div id="editor" froala="froalaOptions" ng-model="myHtml">
  </div>

  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.25.0/codemirror.min.js"></script>
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.25.0/mode/xml/xml.min.js"></script>
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/froala-editor/2.6.0//js/froala_editor.pkgd.min.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
  <script src="angular-froala.js"></script>
  <script type="text/javascript" src="script.js"></script>
</body>
</html>
/*$(function(){
  $('#edit').froalaEditor({
    initOnClick: true
  })
});*/

angular.module('myapp', ['froala'])
  .controller('myctrl', function($scope) {
    $scope.myHtml = "<h1>Hello World</h1>";
    $scope.froalaOptions = {
      toolbarButtons: ["bold", "italic", "underline"],
      initOnClick: true
    };
  });
/* Styles go here */

(function (window, angular, jQuery, undefined) {
    'use strict';

    angular.module('froala', [])
    .value('froalaConfig', {})
    .directive('froala', ['froalaConfig', function (froalaConfig) {
        "use strict"; //Scope strict mode to only this directive
        var generatedIds = 0;
        var defaultConfig = {
            immediateAngularModelUpdate: false,
            angularIgnoreAttrs: null
        };

        var innerHtmlAttr = 'innerHTML';

        var scope = {
            froalaOptions: '=froala',
            initFunction: '&froalaInit'
        };

        froalaConfig = froalaConfig || {};

        // Constants
        var MANUAL = "manual";
        var AUTOMATIC = "automatic";
        var SPECIAL_TAGS = ['img', 'button', 'input', 'a'];

        return {
            restrict: 'A',
            require: 'ngModel',
            scope: scope,
            link: function (scope, element, attrs, ngModel) {
                if (jQuery) element = jQuery(element);

                var specialTag = false;
                if (SPECIAL_TAGS.indexOf(element.prop("tagName").toLowerCase()) != -1) {
                    specialTag = true;
                }

                var ctrl = {
                    editorInitialized: false
                };

                scope.initMode = attrs.froalaInit ? MANUAL : AUTOMATIC;

                ctrl.init = function () {
                    if (!attrs.id) {
                        // generate an ID if not present
                        attrs.$set('id', 'froala-' + generatedIds++);
                    }

                    //init the editor
                    if (scope.initMode === AUTOMATIC) {
                        ctrl.createEditor();
                    }

                    //Instruct ngModel how to update the froala editor
                    ngModel.$render = function () {
                        if (ctrl.editorInitialized) {
                            if (specialTag) {
                                var tags = ngModel.$modelValue;

                                // add tags on element
                                if (tags) {
                                    for (var attr in tags) {
                                        if (tags.hasOwnProperty(attr) && attr != innerHtmlAttr) {
                                            element.attr(attr, tags[attr]);
                                        }
                                    }
                                    if (tags.hasOwnProperty(innerHtmlAttr)) {
                                        element[0].innerHTML = tags[innerHtmlAttr];
                                    }
                                }
                            } else {
                                element.froalaEditor('html.set', ngModel.$viewValue || '', true);
                                //This will reset the undo stack everytime the model changes externally. Can we fix this?
                                element.froalaEditor('undo.reset');
                                element.froalaEditor('undo.saveStep');
                            }
                        }
                    };

                    ngModel.$isEmpty = function (value) {
                        if (!value) {
                            return true;
                        }

                        var isEmpty = element.froalaEditor('node.isEmpty', jQuery('<div>' + value + '</div>').get(0));
                        return isEmpty;
                    };
                };

                ctrl.createEditor = function (froalaInitOptions) {
                    ctrl.listeningEvents = ['froalaEditor'];
                    if (!ctrl.editorInitialized) {
                        froalaInitOptions = (froalaInitOptions || {});
                        ctrl.options = angular.extend({}, defaultConfig, froalaConfig, scope.froalaOptions,froalaInitOptions);

                        if (ctrl.options.immediateAngularModelUpdate) {
                            ctrl.listeningEvents.push('keyup');
                        }

                        // flush means to load ng-model into editor
                        var flushNgModel = function() {
                            ctrl.editorInitialized = true;
                            ngModel.$render();
                        }

                        if (specialTag) {
                            // flush before editor is initialized
                            flushNgModel();
                        } else {
                            ctrl.registerEventsWithCallbacks('froalaEditor.initialized', function() {
                                flushNgModel();
                            });
                        }

                        // Register events provided in the options
                        // Registering events before initializing the editor will bind the initialized event correctly.
                        for (var eventName in ctrl.options.events) {
                            if (ctrl.options.events.hasOwnProperty(eventName)) {
                                ctrl.registerEventsWithCallbacks(eventName, ctrl.options.events[eventName]);
                            }
                        }

                        ctrl.froalaElement = element.froalaEditor(ctrl.options).data('froala.editor').$el;
                        ctrl.froalaEditor = angular.bind(element, element.froalaEditor);
                        ctrl.initListeners();

                        //assign the froala instance to the options object to make methods available in parent scope
                        if (scope.froalaOptions) {
                            scope.froalaOptions.froalaEditor = ctrl.froalaEditor;
                        }
                    }
                };

                ctrl.initListeners = function () {
                    if (ctrl.options.immediateAngularModelUpdate) {
                        ctrl.froalaElement.on('keyup', function () {
                            scope.$evalAsync(ctrl.updateModelView);
                        });
                    }

                    element.on('froalaEditor.contentChanged', function () {
                        scope.$evalAsync(ctrl.updateModelView);
                    });

                    element.bind('$destroy', function () {
                        element.off(ctrl.listeningEvents.join(" "));
                        element.froalaEditor('destroy');
                        element = null;
                    });
                };

                ctrl.updateModelView = function () {

                    var modelContent = null;

                    if (specialTag) {
                        var attributeNodes = element[0].attributes;
                        var attrs = {};

                        for (var i = 0; i < attributeNodes.length; i++ ) {
                            var attrName = attributeNodes[i].name;
                            if (ctrl.options.angularIgnoreAttrs && ctrl.options.angularIgnoreAttrs.indexOf(attrName) != -1) {
                                continue;
                            }
                            attrs[attrName] = attributeNodes[i].value;
                        }
                        if (element[0].innerHTML) {
                            attrs[innerHtmlAttr] = element[0].innerHTML;
                        }
                        modelContent = attrs;
                    } else {
                        var returnedHtml = element.froalaEditor('html.get');
                        if (angular.isString(returnedHtml)) {
                            modelContent = returnedHtml;
                        }
                    }

                    ngModel.$setViewValue(modelContent);
                    if (!scope.$root.$$phase) {
                        scope.$apply();
                    }
                };

                ctrl.registerEventsWithCallbacks = function (eventName, callback) {
                    if (eventName && callback) {
                        ctrl.listeningEvents.push(eventName);
                        element.on(eventName, callback);
                    }
                };

                if (scope.initMode === MANUAL) {
                    var _ctrl = ctrl;
                    var controls = {
                        initialize: ctrl.createEditor,
                        destroy: function () {
                            if (_ctrl.froalaEditor) {
                                _ctrl.froalaEditor('destroy');
                                _ctrl.editorInitialized = false;
                            }
                        },
                        getEditor: function () {
                            return _ctrl.froalaEditor ? _ctrl.froalaEditor : null;
                        }
                    };
                    scope.initFunction({initControls: controls});
                }
                ctrl.init();
            }
        };
    }])
    .directive('froalaView', ['$sce', function ($sce) {
        return {
            restrict: 'ACM',
            scope: false,
            link: function (scope, element, attrs) {
                element.addClass('fr-view');
                scope.$watch(attrs.froalaView, function (nv) {
                    if (nv || nv === ''){
                        var explicitlyTrustedValue = $sce.trustAsHtml(nv);
                        element.html(explicitlyTrustedValue.toString());
                    }
                });
            }
        };
    }]);
})(window, window.angular, window.jQuery);