├── projects
├── demo
│ ├── src
│ │ ├── image.jpg
│ │ ├── main.ts
│ │ ├── polyfills.ts
│ │ ├── typings.d.ts
│ │ ├── index.html
│ │ ├── app.module.ts
│ │ └── app
│ │ │ ├── froala.component.ts
│ │ │ └── app.component.ts
│ └── tsconfig.json
└── library
│ ├── src
│ ├── view
│ │ ├── index.ts
│ │ ├── view.module.ts
│ │ └── view.directive.ts
│ ├── editor
│ │ ├── index.ts
│ │ ├── editor.module.ts
│ │ └── editor.directive.ts
│ ├── index.ts
│ └── fe-root.module.ts
│ ├── ng-package.json
│ ├── package.json
│ └── tsconfig.json
├── version.json
├── tsconfig.json
├── docker-compose.yml.template
├── Dockerfile
├── .gitignore
├── .travis.yml
├── package.json
├── publish-npm.sh
├── push-image-to-nexus.sh
├── angular.json
├── deploy_sdk.sh
└── README.md
/projects/demo/src/image.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/froala/angular-froala-wysiwyg/HEAD/projects/demo/src/image.jpg
--------------------------------------------------------------------------------
/projects/library/src/view/index.ts:
--------------------------------------------------------------------------------
1 | export { FroalaViewDirective } from './view.directive';
2 | export { FroalaViewModule } from './view.module';
--------------------------------------------------------------------------------
/projects/library/src/editor/index.ts:
--------------------------------------------------------------------------------
1 | export { FroalaEditorDirective } from './editor.directive';
2 | export { FroalaEditorModule } from './editor.module';
--------------------------------------------------------------------------------
/projects/demo/src/main.ts:
--------------------------------------------------------------------------------
1 | import './polyfills';
2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
3 | import { AppModule } from './app.module';
4 |
5 | platformBrowserDynamic().bootstrapModule(AppModule);
6 |
--------------------------------------------------------------------------------
/projects/demo/src/polyfills.ts:
--------------------------------------------------------------------------------
1 | // This file includes polyfills needed by Angular 2 and is loaded before
2 | // the app. You can add your own extra polyfills to this file.
3 | import 'zone.js';
4 | import 'zone.js/testing';
5 |
6 | import 'classlist.js';
7 |
--------------------------------------------------------------------------------
/projects/library/ng-package.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
3 | "dest": "../../dist",
4 | "deleteDestPath": true,
5 | "allowedNonPeerDependencies": [
6 | "froala-editor"
7 | ],
8 | "lib": {
9 | "entryFile": "src/index.ts"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/projects/demo/src/typings.d.ts:
--------------------------------------------------------------------------------
1 | // Typings reference file, you can add your own global typings here
2 | // https://www.typescriptlang.org/docs/handbook/writing-declaration-files.html
3 | // tslint:disable
4 | declare const System: any;
5 | declare const ENV:string;
6 |
7 | // google code-prettify
8 | declare const PR:any;
--------------------------------------------------------------------------------
/projects/library/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular-froala-wysiwyg",
3 | "repository": {
4 | "type": "git",
5 | "url": "https://github.com/froala/angular-froala-wysiwyg.git",
6 | "directory":"projects/library"
7 | },
8 | "version": "4.7.1",
9 | "dependencies": {
10 | "froala-editor": "4.7.1"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/projects/library/src/index.ts:
--------------------------------------------------------------------------------
1 | export { FroalaEditorDirective } from './editor/editor.directive';
2 | export { FroalaEditorModule } from './editor/editor.module';
3 |
4 | export { FroalaViewDirective } from './view/view.directive';
5 | export { FroalaViewModule } from './view/view.module';
6 |
7 | export { FERootModule } from './fe-root.module';
8 |
9 |
--------------------------------------------------------------------------------
/version.json:
--------------------------------------------------------------------------------
1 | {
2 | "comment-1": " Please update this file for any new branch with core libary name - package name and version uploaded to nexus",
3 | "name": "froala-editor-QA241122",
4 | "version": "4.0.16",
5 | "comment-2": "Please specify the maximum allowed deployments per environment",
6 | "dev": "1",
7 | "qa": "2",
8 | "qe": "2",
9 | "stg": "1"
10 | }
11 |
--------------------------------------------------------------------------------
/projects/demo/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Angular Froala WYSIWYG
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | Loading...
14 |
15 |
16 |
--------------------------------------------------------------------------------
/projects/library/src/fe-root.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { FroalaEditorModule } from './editor/editor.module';
3 | import { FroalaViewModule } from './view/view.module';
4 |
5 | @NgModule({
6 | imports: [
7 | FroalaEditorModule.forRoot(),
8 | FroalaViewModule.forRoot()
9 | ],
10 | exports: [
11 | FroalaEditorModule,
12 | FroalaViewModule
13 | ]
14 | })
15 | export class FERootModule {
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/projects/library/src/view/view.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule, ModuleWithProviders } from '@angular/core';
2 |
3 | import { FroalaViewDirective } from './view.directive';
4 |
5 | @NgModule({
6 | declarations: [FroalaViewDirective],
7 | exports: [FroalaViewDirective]
8 | })
9 | export class FroalaViewModule {
10 | public static forRoot(): ModuleWithProviders {
11 | return {ngModule: FroalaViewModule, providers: []};
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/projects/library/src/editor/editor.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule, ModuleWithProviders } from '@angular/core';
2 |
3 | import { FroalaEditorDirective } from './editor.directive';
4 |
5 | @NgModule({
6 | declarations: [FroalaEditorDirective],
7 | exports: [FroalaEditorDirective]
8 | })
9 |
10 | export class FroalaEditorModule {
11 | public static forRoot(): ModuleWithProviders {
12 | return {ngModule: FroalaEditorModule, providers: []};
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": "./",
4 | "rootDir": ".",
5 | "downlevelIteration": true,
6 | "outDir": "./dist/out-tsc",
7 | "sourceMap": true,
8 | "declaration": false,
9 | "module": "esnext",
10 | "moduleResolution": "node",
11 | "importHelpers": true,
12 | "emitDecoratorMetadata": true,
13 | "skipLibCheck": true,
14 | "experimentalDecorators": true,
15 | "target": "es2020",
16 | "typeRoots": [
17 | "node_modules/@types"
18 | ],
19 | "lib": [
20 | "es2017",
21 | "dom"
22 | ]
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/docker-compose.yml.template:
--------------------------------------------------------------------------------
1 | version: '3.7'
2 |
3 | services:
4 | ServiceName:
5 | restart: unless-stopped
6 | image: ImageName
7 | pull_policy: always
8 | container_name: ContainerName
9 | networks:
10 | - caddy
11 | # ports:
12 | # - "1500:4200"
13 |
14 | labels:
15 | caddy_0: UrlName
16 | caddy_0.reverse_proxy: "{{upstreams PortNum}}"
17 | caddy_0.tls.ca: https://acme-staging-v02.api.letsencrypt.org/directory
18 | # rate limit exceeded ; use letsencryot staging url :https://letsencrypt.org/docs/rate-limits/
19 |
20 | networks:
21 | caddy:
22 | external: true
--------------------------------------------------------------------------------
/projects/library/src/view/view.directive.ts:
--------------------------------------------------------------------------------
1 | import { Directive, ElementRef, Renderer2, Input } from '@angular/core';
2 |
3 | @Directive({
4 | selector: '[froalaView]',
5 | standalone: false
6 | })
7 | export class FroalaViewDirective {
8 |
9 | private _element: HTMLElement;
10 |
11 | constructor(private renderer: Renderer2, element: ElementRef) {
12 | this._element = element.nativeElement;
13 | }
14 |
15 | // update content model as it comes
16 | @Input() set froalaView(content: string) {
17 | this._element.innerHTML = content;
18 | }
19 |
20 | ngAfterViewInit() {
21 | this.renderer.addClass(this._element, "fr-view");
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:18
2 |
3 | LABEL maintainer="froala_git_travis_bot@idera.com"
4 |
5 | ARG PackageName
6 | ARG PackageVersion
7 | ARG NexusUser
8 | ARG NexusPassword
9 |
10 | COPY . /app
11 | WORKDIR /app/
12 |
13 | RUN apt update -y \
14 | && apt install -y jq unzip wget
15 | RUN echo "Dummy line"
16 |
17 | RUN echo "PackageName=$PackageName PackageVersion=$PackageVersion NexusUser=${NexusUser} NexusPassword=${NexusPassword}"
18 | RUN wget --no-check-certificate --user ${NexusUser} --password ${NexusPassword} https://nexus.tools.froala-infra.com/repository/Froala-npm/${PackageName}/-/${PackageName}-${PackageVersion}.tgz
19 |
20 | RUN npm install
21 |
22 | RUN npm run demo.build
23 | EXPOSE 4200
24 | CMD ["npm","run","start"]
25 |
--------------------------------------------------------------------------------
/projects/demo/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "declaration": false,
5 | "emitDecoratorMetadata": true,
6 | "experimentalDecorators": true,
7 | "noEmitHelpers" :true,
8 | "lib": ["es6", "dom"],
9 | "types": [
10 | "webpack"
11 | ],
12 | "module": "esnext",
13 | "moduleResolution": "node",
14 | "target": "ES2022",
15 | "baseUrl": ".",
16 | "sourceMap": true,
17 | "typeRoots": [
18 | "../../node_modules/@types"
19 | ],
20 | "paths": {
21 | "angular-fraola-wysiwyg": [
22 | "../library/src/index.ts"
23 | ]
24 | }
25 | },
26 | "files": [
27 | "src/main.ts"
28 | ],
29 | "include": [
30 | "**/*.d.ts"
31 | ]
32 | }
33 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Dependency directory
2 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
3 | /node_modules
4 | /bower_components
5 | yarn.lock
6 |
7 | # IDEs and editors
8 | /.idea
9 | /.vscode
10 | .project
11 | .classpath
12 | *.launch
13 | .settings/
14 |
15 | # misc
16 | /.sass-cache
17 | /connect.lock
18 | /coverage/*
19 | /libpeerconnection.log
20 | npm-debug.log
21 |
22 | # ignore build and dist for now
23 | /dist
24 | /temp
25 | /demo/dist
26 | /demo/temp
27 | /logs
28 |
29 | #System Files
30 | .DS_Store
31 | Thumbs.db
32 |
33 |
34 | /demo/e2e/*.js
35 | /demo/e2e/*.map
36 | src/**/*.js
37 | src/**/*.map
38 | scripts/**/*.js
39 | scripts/**/*.map
40 |
41 | # Typing #
42 | /src/typings/tsd/
43 | /typings/**
44 | /tsd_typings/
45 |
46 | package-lock.json
--------------------------------------------------------------------------------
/projects/demo/src/app.module.ts:
--------------------------------------------------------------------------------
1 | import 'froala-editor/js/plugins.pkgd.min.js';
2 |
3 | import { FormsModule, ReactiveFormsModule } from '@angular/forms';
4 |
5 | import { AppComponent } from './app/app.component';
6 | import { BrowserModule } from '@angular/platform-browser';
7 | import { CommonModule } from '@angular/common';
8 | import { FroalaComponent } from "./app/froala.component";
9 | import { FroalaEditorModule } from 'angular-fraola-wysiwyg';
10 | import { FroalaViewModule } from 'angular-fraola-wysiwyg';
11 | import { NgModule } from '@angular/core';
12 |
13 | @NgModule({
14 | declarations: [AppComponent, FroalaComponent],
15 | imports: [BrowserModule, CommonModule, FormsModule, ReactiveFormsModule, FroalaEditorModule, FroalaViewModule],
16 | bootstrap: [AppComponent]
17 | })
18 | export class AppModule {
19 | }
20 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | git:
2 | depth: false
3 | quiet: false
4 | language: generic
5 | dist: bionic
6 | sudo: required
7 | branches:
8 | only:
9 | - /dev*/
10 | - /AO-dev*/
11 | - /QA*/
12 | - /QE*/
13 | - /RC*/
14 | - /Release-Master*/
15 | env:
16 | - SHORT_COMMIT= `git rev-parse --short=7 ${TRAVIS_COMMIT}`
17 | before_install:
18 | - echo $TRAVIS_BRANCH
19 | - echo $PWD
20 | - echo $TRAVIS_COMMIT
21 | - echo $BUILD_REPO_NAME
22 | jobs:
23 | include:
24 | if: commit_message =~ /(deploy-yes)/
25 | script:
26 | - chmod u+x push-image-to-nexus.sh && bash push-image-to-nexus.sh
27 | - chmod u+x deploy_sdk.sh && bash deploy_sdk.sh
28 | - chmod u+x publish-npm.sh && bash publish-npm.sh
29 |
30 | notifications:
31 | email:
32 | recipients:
33 | - harasunu.narayan@froala.com
34 | on_success: always
35 | on_failure: always
36 |
--------------------------------------------------------------------------------
/projects/library/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "declaration": true,
5 | "module": "es2020",
6 | "target": "es2020",
7 | "baseUrl": "./",
8 | "stripInternal": true,
9 | "emitDecoratorMetadata": true,
10 | "experimentalDecorators": true,
11 | "moduleResolution": "node",
12 | "outDir": "../build",
13 | "rootDir": ".",
14 | "lib": [
15 | "es2020",
16 | "dom"
17 | ],
18 | "skipLibCheck": true,
19 | "types": []
20 | },
21 | "angularCompilerOptions": {
22 | "compilationMode": "partial",
23 | "annotateForClosureCompiler": true,
24 | "strictMetadataEmit": true,
25 | "skipTemplateCodegen": true,
26 | "flatModuleOutFile": "angular-froala-wysiwyg.js",
27 | "flatModuleId": "angular-froala-wysiwyg"
28 | },
29 | "files": [
30 | "./src/index.ts"
31 | ]
32 | }
33 |
--------------------------------------------------------------------------------
/projects/demo/src/app/froala.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, forwardRef } from '@angular/core';
2 | import {ControlValueAccessor, NG_VALUE_ACCESSOR} from "@angular/forms";
3 |
4 | @Component({
5 | selector: 'froala-component',
6 | template: `
7 |
8 | `,
9 | providers: [
10 | {
11 | provide: NG_VALUE_ACCESSOR,
12 | useExisting: forwardRef(() => FroalaComponent),
13 | multi: true
14 | }
15 | ],
16 | standalone: false
17 | })
18 | export class FroalaComponent implements ControlValueAccessor {
19 |
20 | constructor() {
21 |
22 | }
23 |
24 | // Begin ControlValueAccesor methods.
25 | onChange = (_) => {};
26 | onTouched = () => {};
27 |
28 | // Form model content changed.
29 | writeValue(content: any): void {
30 | this.model = content;
31 | }
32 |
33 | registerOnChange(fn: (_: any) => void): void { this.onChange = fn; }
34 | registerOnTouched(fn: () => void): void { this.onTouched = fn; }
35 | // End ControlValueAccesor methods.
36 |
37 | model: any;
38 |
39 | config: Object = {
40 | charCounterCount: false
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular-froala-wysiwyg-base",
3 | "version": "4.7.1",
4 | "description": "Angular 19+ versions bindings for Froala WYSIWYG HTML rich text editor",
5 | "main": "bundles/angular-froala-wysiwyg.umd.js",
6 | "typings": "index.d.ts",
7 | "module": "index.js",
8 | "scripts": {
9 | "demo.serve": "ng serve --host 0.0.0.0 --disable-host-check angular-froala-wysiwyg-demo",
10 | "demo.build": "ng build angular-froala-wysiwyg-demo",
11 | "build": "ng build angular-froala-wysiwyg && cp README.md dist/",
12 | "start": "npm run demo.serve"
13 | },
14 | "repository": {
15 | "type": "git",
16 | "url": "https://github.com/froala/angular-froala-wysiwyg.git"
17 | },
18 | "keywords": [
19 | "angular19",
20 | "ng19",
21 | "froala",
22 | "html",
23 | "text",
24 | "editor",
25 | "wysiwyg",
26 | "rich editor",
27 | "rich text editor",
28 | "rte",
29 | "javascript"
30 | ],
31 | "author": "Froala Labs (https://www.froala.com/)",
32 | "license": "MIT",
33 | "bugs": {
34 | "url": "https://github.com/froala/angular-froala-wysiwyg/issues"
35 | },
36 | "dependencies": {
37 | "font-awesome": "^4.7.0",
38 | "froala-editor": "^4.7.1",
39 | "tslib": "^2.8.1"
40 | },
41 | "peerDependencies": {},
42 | "devDependencies": {
43 | "@angular-devkit/build-angular": "^19.0.1",
44 | "@angular/cli": "^19.0.1",
45 | "@angular/common": "^19.0.0",
46 | "@angular/compiler": "^19.0.0",
47 | "@angular/compiler-cli": "^19.0.0",
48 | "@angular/core": "^19.0.0",
49 | "@angular/forms": "^19.0.0",
50 | "@angular/language-service": "^19.0.0",
51 | "@angular/platform-browser": "^19.0.0",
52 | "@angular/platform-browser-dynamic": "^19.0.0",
53 | "@angular/router": "^19.0.0",
54 | "@types/node": "^18.11.9",
55 | "@types/tapable": "^2.2.1",
56 | "@types/webpack": "^5.28.5",
57 | "classlist.js": "^1.1.20150312",
58 | "ng-packagr": "^19.0.1",
59 | "rxjs": "^7.8.1",
60 | "ts-helpers": "^1.1.2",
61 | "typescript": "~5.6.3",
62 | "zone.js": "~0.15.0"
63 | }
64 | }
--------------------------------------------------------------------------------
/publish-npm.sh:
--------------------------------------------------------------------------------
1 |
2 | #
3 | # Publish to Nexus NPM repository if it's not a pull request
4 | #
5 |
6 | if [ ${TRAVIS_PULL_REQUEST} != "false" ]; then echo "Not publishing a pull request !!!" && exit 0; fi
7 |
8 | npm config set strict-ssl false
9 | npm install -g npm-cli-login
10 | npm-cli-login --scope @froala-org -u ${NEXUS_USER} -p ${NEXUS_USER_PWD} -e dummy-email@noemail@froala.com -r ${NEXUS_URL}/repository/Froala-npm
11 |
12 |
13 | echo "seting up nexus as default registry to publish ..."
14 |
15 | npm-cli-login -u ${NEXUS_USER} -p ${NEXUS_USER_PWD} -e dummy-email@noemail@froala.com -r ${NEXUS_URL}/repository/Froala-npm
16 |
17 | PACKAGE_NAME=`jq '.name' version.json | tr -d '"'`
18 | PACKAGE_VERSION=`jq '.version' version.json | tr -d '"'`
19 | echo "Package name : ${PACKAGE_NAME}"
20 |
21 | export DEFAULT_NAME=`cat projects/library/package.json | jq '.name '`
22 | export DEFAULT_NAME=`sed -e 's/^"//' -e 's/"$//' <<<"$DEFAULT_NAME"`
23 | echo ${DEFAULT_NAME}
24 | export ANGULAR_EDITOR_NAME=${DEFAULT_NAME}-${TRAVIS_BRANCH}
25 |
26 | wget --no-check-certificate --user ${NEXUS_USER} --password ${NEXUS_USER_PWD} https://nexus.tools.froala-infra.com/repository/Froala-npm/${PACKAGE_NAME}/-/${PACKAGE_NAME}-${PACKAGE_VERSION}.tgz
27 |
28 | npm install -f
29 | npm run build
30 |
31 | ls -la
32 |
33 | cd dist
34 |
35 | jq --arg newval "$ANGULAR_EDITOR_NAME" '.name |= $newval' package.json > tmp.json && mv tmp.json package.json
36 | jq --arg froalaeditor "file:${PACKAGE_NAME}-${PACKAGE_VERSION}.tgz" '.dependencies["froala-editor"] |= $froalaeditor' package.json > new.file && cat new.file > package.json && rm -f new.file
37 | jq '.publishConfig |= . + {"registry": "https://nexus.tools.froala-infra.com/repository/Froala-npm/" }' package.json > new.file && cat new.file > package.json && rm -f new.file
38 |
39 | echo " Angular demo package.json file: " && cat package.json
40 |
41 | npm publish
42 |
43 | echo "Published ${ANGULAR_EDITOR_NAME} to nexus "
44 |
45 | echo "Please create/verify branch update ${TRAVIS_BRANCH} for https://github.com/froala/ionic-froala-demo-mcs/blob/devops/version.json and update version.json with ${ANGULAR_EDITOR_NAME} and version "
46 |
--------------------------------------------------------------------------------
/push-image-to-nexus.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | export BRANCH_NAME=`echo "${TRAVIS_BRANCH}" | tr '[:upper:]' '[:lower:]'`
3 | case "${BRANCH_NAME}" in
4 | dev*) echo "Branch ${TRAVIS_BRANCH} is eligible for CI/CD" ;;
5 | ao-dev*)echo "Branch ${TRAVIS_BRANCH} is eligible for CI/CD" ;;
6 | qa*) echo "Branch ${TRAVIS_BRANCH} is eligible for CI/CD" ;;
7 | qe*) echo "Branch ${TRAVIS_BRANCH} is eligible for CI/CD" ;;
8 | rc*) echo "Branch ${TRAVIS_BRANCH} is eligible for CI/CD" ;;
9 | release-master*) echo "Branch ${TRAVIS_BRANCH} is eligible for CI/CD" ;;
10 | ft*) echo "Branch ${TRAVIS_BRANCH} is eligible for CI" ;;
11 | bf*) echo "Branch ${TRAVIS_BRANCH} is eligible for CI" ;;
12 | *) echo "Not a valid branch name for CI/CD" && exit -1;;
13 | esac
14 |
15 | echo $TRAVIS_BRANCH
16 | echo ${DEPLOYMENT_SERVER}
17 | export SHORT_COMMIT=`git rev-parse --short=7 ${TRAVIS_COMMIT}`
18 | echo "short commit $SHORT_COMMIT"
19 | sudo apt-get update
20 | sudo apt-get install -y jq
21 | IMAGE_NAME=`echo "${BUILD_REPO_NAME}_${TRAVIS_BRANCH}" | tr '[:upper:]' '[:lower:]'`
22 | PACKAGE_NAME=`jq '.name' version.json | tr -d '"'`
23 | PACKAGE_VERSION=`jq '.version' version.json | tr -d '"'`
24 | echo "Package name : ${PACKAGE_NAME}"
25 | jq --arg froalaeditor "file:${PACKAGE_NAME}-${PACKAGE_VERSION}.tgz" '.dependencies["froala-editor"] |= $froalaeditor' package.json > new.file && cat new.file > package.json && rm -f new.file
26 | echo "verify package"
27 | cat package.json
28 | docker build -t ${IMAGE_NAME}:${SHORT_COMMIT} --build-arg PackageName=${PACKAGE_NAME} --build-arg PackageVersion=${PACKAGE_VERSION} --build-arg NexusUser=${NEXUS_USER} --build-arg NexusPassword=${NEXUS_USER_PWD} .
29 | sleep 3
30 | docker image ls
31 | echo "uploading to nexus ${PACKAGE_NAME}, if not a new PR"
32 | if [ ${TRAVIS_PULL_REQUEST} != "false" ]; then echo "Not publishing a pull request !!!" && exit 0; fi
33 | docker login -u ${NEXUS_USER} -p ${NEXUS_USER_PWD} ${NEXUS_CR_TOOLS_URL}
34 | docker tag ${IMAGE_NAME}:${SHORT_COMMIT} ${NEXUS_CR_TOOLS_URL}/froala-${IMAGE_NAME}:${PACKAGE_VERSION}
35 | docker push ${NEXUS_CR_TOOLS_URL}/froala-${IMAGE_NAME}:${PACKAGE_VERSION}
--------------------------------------------------------------------------------
/angular.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3 | "version": 1,
4 | "newProjectRoot": "projects",
5 | "projects": {
6 | "angular-froala-wysiwyg": {
7 | "root": "projects/library",
8 | "projectType": "library",
9 | "architect": {
10 | "build": {
11 | "builder": "@angular-devkit/build-angular:ng-packagr",
12 | "options": {
13 | "project": "projects/library/ng-package.json",
14 | "tsConfig": "projects/library/tsconfig.json"
15 | }
16 | }
17 | }
18 | },
19 | "angular-froala-wysiwyg-demo": {
20 | "root": "projects/demo",
21 | "sourceRoot": "projects/demo/src",
22 | "projectType": "application",
23 | "architect": {
24 | "build": {
25 | "builder": "@angular-devkit/build-angular:browser",
26 | "options": {
27 | "allowedCommonJsDependencies":[
28 | "froala-editor",
29 | "core-js",
30 | "zone.js"
31 | ],
32 | "outputPath": "dist-demo",
33 | "index": "projects/demo/src/index.html",
34 | "main": "projects/demo/src/main.ts",
35 | "tsConfig": "projects/demo/tsconfig.json",
36 | "assets": [
37 | "projects/demo/src/image.jpg"
38 | ],
39 | "styles": [
40 | "node_modules/froala-editor/css/froala_editor.pkgd.css"
41 | ],
42 | "scripts": []
43 | },
44 | "configurations": {
45 | "production": {
46 | "budgets": [
47 | {
48 | "type": "anyComponentStyle",
49 | "maximumWarning": "6kb"
50 | }
51 | ],
52 | "optimization": false,
53 | "outputHashing": "all",
54 | "sourceMap": false,
55 | "namedChunks": false,
56 | "aot": true,
57 | "extractLicenses": true,
58 | "vendorChunk": false,
59 | "buildOptimizer": true
60 | }
61 | }
62 | },
63 | "serve": {
64 | "builder": "@angular-devkit/build-angular:dev-server",
65 | "options": {
66 | "buildTarget": "angular-froala-wysiwyg-demo:build"
67 | },
68 | "configurations": {}
69 | },
70 | "extract-i18n": {
71 | "builder": "@angular-devkit/build-angular:extract-i18n",
72 | "options": {
73 | "buildTarget": "angular-froala-wysiwyg-demo:build"
74 | }
75 | },
76 | "lint": {
77 | "builder": "@angular-devkit/build-angular:tslint",
78 | "options": {
79 | "tsConfig": [],
80 | "exclude": []
81 | }
82 | }
83 | }
84 | },
85 | "angular-froala-wysiwyg-demo-e2e": {
86 | "root": "demo/e2e",
87 | "sourceRoot": "demo/e2e",
88 | "projectType": "application"
89 | }
90 | },
91 |
92 | "schematics": {
93 | "@schematics/angular:component": {
94 | "prefix": "",
95 | "style": "css"
96 | },
97 | "@schematics/angular:directive": {
98 | "prefix": ""
99 | }
100 | },
101 | "cli": {
102 | "analytics": false
103 | }
104 | }
--------------------------------------------------------------------------------
/projects/demo/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 | import {FormControl, FormGroup, Validators} from '@angular/forms';
3 |
4 | import FroalaEditor from 'froala-editor';
5 |
6 | @Component({
7 | selector: 'app-demo',
8 | template: `
9 |
10 | Angular adapter for the Froala WYSIWYG editor
11 |
12 |
Sample 1: Inline Edit
13 |
14 |
15 |
16 |
17 |
Sample 2: Full Editor
18 |
19 |
Rendered Content:
20 |
21 |
22 |
23 |
Sample 3: Two way binding
24 |
25 |
26 |
27 |
28 |
Sample 4: Manual Initialization
29 |
30 |
31 |
32 |
33 |
34 |
35 |
Sample 5: Editor on 'img' tag. Two way binding.
36 |
![]()
37 |
![]()
38 |
Model Obj:
39 |
{{imgModel | json}}
40 |
41 |
42 |
Sample 6: Editor on 'button' tag
43 |
44 |
Model Obj:
45 |
{{buttonModel | json}}
46 |
47 |
48 |
Sample 7: Editor on 'input' tag
49 |
50 |
Model Obj:
51 |
{{inputModel | json}}
52 |
53 |
54 |
Sample 8: Editor on 'a' tag. Manual Initialization
55 |
56 |
57 |
60 |
Model Obj:
61 |
{{linkModel | json}}
62 |
63 |
64 |
65 |
Sample 9: Editor with reactive forms
66 |
76 |
77 |
78 |
79 |
80 |
Sample 10: Editor wrapped in a component with reactive forms
81 |
88 |
89 |
90 |
91 |
92 |
Sample 11: Add Custom Button
93 |
94 |
95 |
96 | `,
97 | standalone: false
98 | })
99 |
100 | export class AppComponent implements OnInit {
101 |
102 | ngOnInit () {
103 | FroalaEditor.DefineIcon('alert', { SVG_KEY: 'help' });
104 | FroalaEditor.RegisterCommand('alert', {
105 | title: 'Hello',
106 | focus: false,
107 | undo: false,
108 | refreshAfterCallback: false,
109 |
110 | callback: function () {
111 | alert('Hello!');
112 | }
113 | });
114 | }
115 |
116 | // Sample 1 models
117 | public titleOptions: Object = {
118 | placeholderText: 'Edit Your Content Here!',
119 | charCounterCount: false,
120 | toolbarInline: true,
121 | events: {
122 | "initialized": () => {
123 | console.log('initialized');
124 | },
125 | "contentChanged": () => {
126 | console.log("content changed");
127 | }
128 | }
129 | }
130 | public myTitle: string;
131 | onBlurMethod()
132 | {
133 | console.log(this.myTitle);
134 | }
135 |
136 |
137 | // Sample 2 model
138 | public content: string = 'My Document\'s Title';
139 |
140 |
141 | // Sample 3 model
142 | public twoWayContent;
143 |
144 | // Sample 4 models
145 | public sample3Text;
146 | public initControls;
147 | public deleteAll;
148 | public initialize(initControls) {
149 | this.initControls = initControls;
150 | this.deleteAll = function() {
151 | this.initControls.getEditor().html.set();
152 | this.initControls.getEditor().undo.reset();
153 | this.initControls.getEditor().undo.saveStep();
154 | };
155 | }
156 |
157 | // Sample 5 model
158 | public imgModel: Object = {
159 | src: '/image.jpg'
160 | };
161 |
162 | public imgOptions: Object = {
163 | angularIgnoreAttrs: ['style', 'ng-reflect-froala-editor', 'ng-reflect-froala-model'],
164 | immediateAngularModelUpdate: true,
165 | events: {
166 | "contentChanged": () => {
167 | }
168 | }
169 | }
170 |
171 | // Sample 6 model
172 | public buttonModel: Object = {
173 | innerHTML: 'Click Me'
174 | };
175 |
176 | // Sample 7 models
177 | public inputModel: Object = {
178 | placeholder: 'I am an input!'
179 | };
180 |
181 | // Sample 8 model
182 | linkInitControls;
183 | initializeLink(linkInitControls) {
184 | this.linkInitControls = linkInitControls;
185 | }
186 |
187 | public linkModel: Object = {
188 | href: 'https://www.froala.com/wysiwyg-editor'
189 | };
190 |
191 | // Sample 9
192 | formControls = {
193 | formModel: new FormControl('Hello World', Validators.minLength(2)),
194 | };
195 | form:any = new FormGroup(this.formControls);
196 | get formModel(): any { return this.form.get('formModel'); }
197 | onSubmit(): void {
198 | console.log(this.form.value);
199 | }
200 | setValue() { this.form.setValue({formModel: 'Default text'}); }
201 |
202 | // Sample 10
203 | form2 = new FormGroup({
204 | formModel: new FormControl('Hello World', Validators.minLength(2)),
205 | });
206 | get form2Model(): any { return this.form2.get('formModel'); }
207 | onSubmit2(): void {
208 | console.log(this.form2.value);
209 | }
210 | setValue2() { this.form2.setValue({formModel: 'Default text'}); }
211 |
212 | // Sample 11
213 | // Depending on your screen size you may want to use a specific toolbar dimension or all of them.
214 |
215 | public options: Object = {
216 | charCounterCount: true,
217 | toolbarButtons: ['bold', 'italic', 'underline', 'paragraphFormat','alert'],
218 | toolbarButtonsXS: ['bold', 'italic', 'underline', 'paragraphFormat','alert'],
219 | toolbarButtonsSM: ['bold', 'italic', 'underline', 'paragraphFormat','alert'],
220 | toolbarButtonsMD: ['bold', 'italic', 'underline', 'paragraphFormat','alert'],
221 | };
222 | }
223 |
--------------------------------------------------------------------------------
/deploy_sdk.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Steps
4 | # Identify the build agent. Check whether build agent is same as deployment server
5 | # Login to build server and build, run, check the new changes.
6 | # --force-recreate for docker-compose
7 | # --no-cache for docker build
8 | # -f for npm install
9 | # -v --rmi all for docker compose down
10 |
11 | if [ "${TRAVIS_PULL_REQUEST}" != "false" ]; then echo "Not deploying on a pull request !!!" && exit 0; fi
12 |
13 | # Define the global variables
14 | BRANCH_NAME=$(echo "${TRAVIS_BRANCH}" | tr '[:upper:]' '[:lower:]')
15 | PACKAGE_VERSION="$(jq '.version' version.json | tr -d '"')"
16 | IMAGE_NAME="$(echo "froala-${BUILD_REPO_NAME}_${TRAVIS_BRANCH}:${PACKAGE_VERSION}" | tr '[:upper:]' '[:lower:]')"
17 | BASE_DOMAIN="froala-infra.com"
18 | AO_IDENTIFIER="${TRAVIS_BRANCH}"
19 | BRANCH_LENGHT=$(echo "${TRAVIS_BRANCH}" |awk '{print length}')
20 | LW_REPO_NAME=$(echo "${BUILD_REPO_NAME}" | tr '[:upper:]' '[:lower:]' | sed -e 's/-//g' -e 's/\.//g' -e 's/_//g')
21 | CT_INDEX=0
22 | MAX_DEPLOYMENTS_NR=0
23 | SDK_ENVIRONMENT=""
24 | DEPLOYMENT_SERVER=""
25 | SERVICE_NAME=""
26 | CONTAINER_NAME=""
27 | OLDEST_CONTAINER=""
28 |
29 | # Copy the ssh key
30 | echo "${SSH_KEY}" | base64 --decode > /tmp/sshkey.pem
31 | chmod 400 /tmp/sshkey.pem
32 |
33 | # Select the deployment server based on the branch.
34 | case "${BRANCH_NAME}" in
35 | dev*) SDK_ENVIRONMENT="dev" && DEPLOYMENT_SERVER="${FROALA_SRV_DEV}";;
36 | ao-dev*) SDK_ENVIRONMENT="dev" && DEPLOYMENT_SERVER="${FROALA_SRV_DEV}";;
37 | qa*) SDK_ENVIRONMENT="qa" && DEPLOYMENT_SERVER="${FROALA_SRV_QA}";;
38 | qe*) SDK_ENVIRONMENT="qe" && DEPLOYMENT_SERVER="${FROALA_SRV_QE}";;
39 | rc*) SDK_ENVIRONMENT="stg" && DEPLOYMENT_SERVER="${FROALA_SRV_STAGING}";;
40 | release-master*) SDK_ENVIRONMENT="stg" && DEPLOYMENT_SERVER=${FROALA_SRV_STAGING};;
41 | ft*) echo "Building only on feature branch ${TRAVIS_BRANCH}... will not deploy..." && exit 0;;
42 | bf*) echo "Building only on bugfix branch ${TRAVIS_BRANCH}... will not deploy..." && exit 0;;
43 | *) echo "Not a deployment branch" && exit 1;;
44 | esac
45 |
46 | # Set the short branch name
47 | if [ "${BRANCH_LENGHT}" -lt 18 ]; then
48 | SHORT_TRAVIS_BRANCH="${TRAVIS_BRANCH}"
49 | else
50 | SHORT_TRAVIS_BRANCH="${TRAVIS_BRANCH:0:8}${TRAVIS_BRANCH: -8}"
51 | fi
52 | LW_SHORT_TRAVIS_BRANCH="$(echo "${SHORT_TRAVIS_BRANCH}" | sed -e 's/-//g' -e 's/\.//g' -e 's/_//g' | tr '[:upper:]' '[:lower:]')"
53 |
54 | # Get the maximum allowed deployment for given environment
55 | function max_allowed_deployment(){
56 | echo "getting max deployments for environment ${SDK_ENVIRONMENT}"
57 | MAX_DEPLOYMENTS_NR=$(jq --arg sdkenvironment "${SDK_ENVIRONMENT}" '.[$sdkenvironment]' version.json | tr -d '"')
58 | echo "Max allowed deployments: ${MAX_DEPLOYMENTS_NR}"
59 | }
60 | max_allowed_deployment
61 |
62 | # Get the total numbers of deployed container for given environment
63 | function existing_deployments(){
64 | echo "Checking the existing number of running container(s)"
65 | EXISTING_DEPLOYMENTS_NR=$(ssh -o "StrictHostKeyChecking no" -i /tmp/sshkey.pem "${SSH_USER}"@"${DEPLOYMENT_SERVER}" "sudo docker ps | grep -i ${LW_REPO_NAME}-${AO_IDENTIFIER}" | wc -l)
66 | echo "Number of existing deployment: ${EXISTING_DEPLOYMENTS_NR}"
67 | }
68 | existing_deployments
69 |
70 | # Get the old container name, no of deployments, and generate the new index and container name
71 | function generate_container_name(){
72 |
73 | DEPL=$(ssh -o "StrictHostKeyChecking no" -i /tmp/sshkey.pem "${SSH_USER}"@"${DEPLOYMENT_SERVER}" sudo docker ps | grep -i "${LW_REPO_NAME}"-"${AO_IDENTIFIER}")
74 | echo "Containers running for ${AO_IDENTIFIER}: ${DEPL}"
75 | echo "${DEPL}" > file.txt
76 |
77 | echo "Getting indexes of oldest and latest deployed containers for ${AO_IDENTIFIER}"
78 | CT_LOWER_INDEX=$(awk -F'-' '{print $NF }' < file.txt | sort -nk1 | head -1)
79 | CT_HIGHER_INDEX=$(awk -F'-' '{print $NF }' < file.txt | sort -nk1 | tail -1)
80 | echo "Lowest index : ${CT_LOWER_INDEX} ; and Highest index : ${CT_HIGHER_INDEX}"
81 |
82 | if [ -z "${DEPL}" ]; then
83 | echo "First deployment. Setting the container name."
84 | CT_INDEX=1
85 | CONTAINER_NAME="${LW_REPO_NAME}-${AO_IDENTIFIER}-${CT_INDEX}"
86 | SERVICE_NAME="${LW_REPO_NAME}-${LW_SHORT_TRAVIS_BRANCH}"
87 | else
88 | echo "Multiple deployments detected. Setting the container name (old and new)"
89 | CT_INDEX=${CT_HIGHER_INDEX} && CT_INDEX=$((CT_INDEX+1))
90 | OLDEST_CONTAINER="${LW_REPO_NAME}-${AO_IDENTIFIER}-${CT_LOWER_INDEX}"
91 | CONTAINER_NAME="${LW_REPO_NAME}-${AO_IDENTIFIER}-${CT_INDEX}"
92 | SERVICE_NAME="${LW_REPO_NAME}-${LW_SHORT_TRAVIS_BRANCH}-${CT_INDEX}"
93 | echo "New index: ${CT_INDEX}"
94 | fi
95 | }
96 | generate_container_name
97 |
98 | # Print useful details.
99 | echo -e "\n"
100 | echo "----------------------------------------------------------------------"
101 | echo " Selected environment: ${SDK_ENVIRONMENT}. "
102 | echo " Deployment server: ${DEPLOYMENT_SERVER}. "
103 | echo " Max allowed deployments: ${MAX_DEPLOYMENTS_NR}. "
104 | echo " Number of existing deployment: ${EXISTING_DEPLOYMENTS_NR} "
105 | echo " Oldest container name: ${OLDEST_CONTAINER} "
106 | echo " Container name for this deployment: ${CONTAINER_NAME} "
107 | echo "----------------------------------------------------------------------"
108 | echo -e "\n"
109 |
110 | # Set the deployment URL
111 | DEPLOYMENT_URL="${CONTAINER_NAME}.${SDK_ENVIRONMENT}.${BASE_DOMAIN}"
112 |
113 | # Modify the compose file and run the docker-compose.
114 | function deploy(){
115 |
116 | # Copy the docker-compose template to docker-compose.yml
117 | cp docker-compose.yml.template docker-compose.yml
118 |
119 | # Replace the sample values
120 | sed -i "s/ImageName/${NEXUS_CR_TOOLS_URL}\/${IMAGE_NAME}/g" docker-compose.yml
121 | sed -i "s/UrlName/${DEPLOYMENT_URL}/g" docker-compose.yml
122 | sed -i "s/ServiceName/${SERVICE_NAME}/g" docker-compose.yml
123 | sed -i "s/PortNum/${CONTAINER_SERVICE_PORTNO}/g" docker-compose.yml
124 | sed -i "s/ContainerName/${CONTAINER_NAME}/g" docker-compose.yml
125 |
126 | echo -e "\n"
127 | echo "Below is the content of docker-compose.yml"
128 | echo "-------------------------------------------------"
129 | cat docker-compose.yml
130 | echo "-------------------------------------------------"
131 | echo -e "\n"
132 |
133 | # Remove the old docker-compose from deployment_server
134 | ssh -o "StrictHostKeyChecking no" -i /tmp/sshkey.pem "${SSH_USER}"@"${DEPLOYMENT_SERVER}" "if [ -d /services/${SERVICE_NAME} ]; then rm -rf /services/${SERVICE_NAME}; fi && mkdir /services/${SERVICE_NAME}"
135 |
136 | # Copy the latest docker-compose file to deployment_server
137 | scp -o "StrictHostKeyChecking no" -i /tmp/sshkey.pem docker-compose.yml "${SSH_USER}"@"${DEPLOYMENT_SERVER}":/services/"${SERVICE_NAME}"/docker-compose.yml
138 |
139 | # Run docker-compose pull on deployment_server
140 | ssh -o "StrictHostKeyChecking no" -i /tmp/sshkey.pem "${SSH_USER}"@"${DEPLOYMENT_SERVER}" "cd /services/${SERVICE_NAME}/ && sudo docker-compose pull"
141 | sleep 10
142 |
143 | # Run docker-compose up on deployment_server
144 | ssh -o "StrictHostKeyChecking no" -i /tmp/sshkey.pem "${SSH_USER}"@"${DEPLOYMENT_SERVER}" "cd /services/${SERVICE_NAME}/ && sudo docker-compose up -d --force-recreate"
145 | sleep 60
146 |
147 | RET_CODE=$(curl -k -s -o /tmp/notimportant.txt -w "%{http_code}" https://"${DEPLOYMENT_URL}")
148 | echo "validation code: $RET_CODE for https://${DEPLOYMENT_URL}"
149 | if [ "${RET_CODE}" -ne 200 ]; then
150 | echo "Deployment validation failed!!! Please check pipeline logs."
151 | exit 1
152 | else
153 | echo -e "\n\tService available at URL: https://${DEPLOYMENT_URL}\n"
154 | fi
155 | }
156 |
157 | # If existing deployment less than max deployment then just deploy don't remove old container.
158 | if [ "${EXISTING_DEPLOYMENTS_NR}" -lt "${MAX_DEPLOYMENTS_NR}" ]; then
159 | deploy
160 | fi
161 |
162 | # If existing deployment equals max deployment then delete oldest container.
163 | if [ "${EXISTING_DEPLOYMENTS_NR}" -ge "${MAX_DEPLOYMENTS_NR}" ]; then
164 |
165 | echo "Maximum deployments reached on ${SDK_ENVIRONMENT} environment for ${BUILD_REPO_NAME}."
166 | echo "Stopping container ${OLDEST_CONTAINER} ..."
167 |
168 | if ! ssh -o "StrictHostKeyChecking no" -i /tmp/sshkey.pem "${SSH_USER}"@"${DEPLOYMENT_SERVER}" sudo docker stop "${OLDEST_CONTAINER}"; then
169 | echo "Failed to stop the ${OLDEST_CONTAINER} container"
170 | fi
171 | echo "Successfully stopped the ${OLDEST_CONTAINER} container."
172 |
173 | if ! ssh -o "StrictHostKeyChecking no" -i /tmp/sshkey.pem "${SSH_USER}"@"${DEPLOYMENT_SERVER}" sudo docker rm -f "${OLDEST_CONTAINER}"; then
174 | echo "Failed to remove the ${OLDEST_CONTAINER} container"
175 | fi
176 | echo "Successfully removed the ${OLDEST_CONTAINER} container."
177 |
178 | echo "Deploying the service: ${SERVICE_NAME}"
179 | deploy && sleep 30
180 | echo "Deployment completed."
181 | fi
182 |
183 |
--------------------------------------------------------------------------------
/projects/library/src/editor/editor.directive.ts:
--------------------------------------------------------------------------------
1 | import { ControlValueAccessor, NG_VALUE_ACCESSOR } from "@angular/forms";
2 | import { Directive, ElementRef, EventEmitter, forwardRef, Input, NgZone, Output, PLATFORM_ID, Inject } from '@angular/core';
3 | import { isPlatformBrowser } from "@angular/common";
4 |
5 | @Directive({
6 | selector: '[froalaEditor]',
7 | exportAs: 'froalaEditor',
8 | providers: [
9 | {
10 | provide: NG_VALUE_ACCESSOR,
11 | useExisting: forwardRef(() => FroalaEditorDirective),
12 | multi: true
13 | }
14 | ],
15 | standalone: false
16 | })
17 | export class FroalaEditorDirective implements ControlValueAccessor {
18 |
19 | // editor options
20 | private _opts: any = {
21 | immediateAngularModelUpdate: false,
22 | angularIgnoreAttrs: null
23 | };
24 |
25 | private _element: any;
26 |
27 | private SPECIAL_TAGS: string[] = ['img', 'button', 'input', 'a'];
28 | private INNER_HTML_ATTR: string = 'innerHTML';
29 | private _hasSpecialTag: boolean = false;
30 |
31 | // editor element
32 | private _editor: any;
33 |
34 | // initial editor content
35 | private _model: string;
36 |
37 | private _editorInitialized: boolean = false;
38 |
39 | private _oldModel: string = null;
40 |
41 | constructor(el: ElementRef, private zone: NgZone, @Inject(PLATFORM_ID) private platformId: Object) {
42 |
43 | let element: any = el.nativeElement;
44 |
45 | // check if the element is a special tag
46 | if (this.SPECIAL_TAGS.indexOf(element.tagName.toLowerCase()) != -1) {
47 | this._hasSpecialTag = true;
48 | }
49 | this._element = element;
50 |
51 | this.zone = zone;
52 | }
53 |
54 | // Begin ControlValueAccesor methods.
55 | onChange = (_: any) => {
56 | };
57 | onTouched = () => {
58 | };
59 |
60 | // Form model content changed.
61 | writeValue(content: any): void {
62 | this.updateEditor(content);
63 | if(content){
64 | this.setup();
65 | }
66 | }
67 |
68 | registerOnChange(fn: (_: any) => void): void {
69 | this.onChange = fn;
70 | }
71 |
72 | registerOnTouched(fn: () => void): void {
73 | this.onTouched = fn;
74 | }
75 |
76 | // End ControlValueAccesor methods.
77 |
78 | // froalaEditor directive as input: store the editor options
79 | @Input() set froalaEditor(opts: any) {
80 | this._opts = this.clone( opts || this._opts);
81 | this._opts = {...this._opts};
82 | }
83 |
84 | // TODO: replace clone method with better possible alternate
85 | private clone(item) {
86 | const me = this;
87 | if (!item) { return item; } // null, undefined values check
88 |
89 | let types = [ Number, String, Boolean ],
90 | result;
91 |
92 | // normalizing primitives if someone did new String('aaa'), or new Number('444');
93 | types.forEach(function(type) {
94 | if (item instanceof type) {
95 | result = type( item );
96 | }
97 | });
98 |
99 | if (typeof result == "undefined") {
100 | if (Object.prototype.toString.call( item ) === "[object Array]") {
101 | result = [];
102 | item.forEach(function(child, index, array) {
103 | result[index] = me.clone( child );
104 | });
105 | } else if (typeof item == "object") {
106 | // testing that this is DOM
107 | if (item.nodeType && typeof item.cloneNode == "function") {
108 | result = item.cloneNode( true );
109 | } else if (!item.prototype) { // check that this is a literal
110 | if (item instanceof Date) {
111 | result = new Date(item);
112 | } else {
113 | // it is an object literal
114 | result = {};
115 | for (var i in item) {
116 | result[i] = me.clone( item[i] );
117 | }
118 | }
119 | } else {
120 | if (false && item.constructor) {
121 | result = new item.constructor();
122 | } else {
123 | result = item;
124 | }
125 | }
126 | } else {
127 | result = item;
128 | }
129 | }
130 | return result;
131 | }
132 | // froalaModel directive as input: store initial editor content
133 | @Input() set froalaModel(content: any) {
134 | this.updateEditor(content);
135 | }
136 |
137 | private stringify(obj) {
138 | let cache = [];
139 | let str = JSON.stringify(obj, function(key, value) {
140 | if (typeof value === "object" && value !== null) {
141 | if (cache.indexOf(value) !== -1) {
142 | // Circular reference found, discard key
143 | return;
144 | }
145 | // Store value in our collection
146 | cache.push(value);
147 | }
148 | return value;
149 | });
150 | cache = null; // reset the cache
151 | return str;
152 | }
153 |
154 | // Update editor with model contents.
155 | private updateEditor(content: any) {
156 | if (this.stringify(this._oldModel) == this.stringify(content)) {
157 | return;
158 | }
159 |
160 | if (!this._hasSpecialTag) {
161 | this._oldModel = content;
162 | } else {
163 | this._model = content;
164 | }
165 |
166 | if (this._editorInitialized) {
167 | if (!this._hasSpecialTag) {
168 | this._editor.html.set(content);
169 | } else {
170 | this.setContent();
171 | }
172 | } else {
173 | if (!this._hasSpecialTag) {
174 | this._element.innerHTML = content || '';
175 | } else {
176 | this.setContent();
177 | }
178 | }
179 | }
180 |
181 | // froalaModel directive as output: update model if editor contentChanged
182 | @Output() froalaModelChange: EventEmitter = new EventEmitter();
183 |
184 | // froalaInit directive as output: send manual editor initialization
185 | @Output() froalaInit: EventEmitter