diff --git a/apps/demo-angular/package.json b/apps/demo-angular/package.json index 79fa198..931a8e2 100644 --- a/apps/demo-angular/package.json +++ b/apps/demo-angular/package.json @@ -9,18 +9,19 @@ "@angular/platform-browser": "file:../../node_modules/@angular/platform-browser", "@angular/platform-browser-dynamic": "file:../../node_modules/@angular/platform-browser-dynamic", "@angular/router": "file:../../node_modules/@angular/router", + "@finalsite/rich-text-editor": "file:../../dist/packages/rich-text-editor", "@nativescript/angular": "file:../../node_modules/@nativescript/angular", "@nativescript/core": "file:../../node_modules/@nativescript/core", + "@nota/nativescript-webview-ext": "^8.0.2", "nativescript-theme-core": "file:../../node_modules/nativescript-theme-core", "reflect-metadata": "file:../../node_modules/reflect-metadata", "rxjs": "file:../../node_modules/rxjs", - "zone.js": "file:../../node_modules/zone.js", - "@finalsite/rich-text-editor": "file:../../dist/packages/rich-text-editor" + "zone.js": "file:../../node_modules/zone.js" }, "devDependencies": { "@angular/compiler-cli": "file:../../node_modules/@angular/compiler-cli", "@nativescript/android": "7.0.1", - "@nativescript/ios": "7.2.0", + "@nativescript/ios": "^8.3.3", "@nativescript/webpack": "~4.1.0", "@ngtools/webpack": "file:../../node_modules/@ngtools/webpack", "typescript": "~4.0.0" diff --git a/apps/demo-angular/src/app.module.ts b/apps/demo-angular/src/app.module.ts index c869e4d..743f564 100644 --- a/apps/demo-angular/src/app.module.ts +++ b/apps/demo-angular/src/app.module.ts @@ -1,6 +1,8 @@ import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core'; import { NativeScriptModule } from '@nativescript/angular'; +import {WebViewExtModule} from "@nota/nativescript-webview-ext/angular" + import { AppComponent } from './app.component'; import { AppRoutingModule } from './app-routing.module'; import { HomeComponent } from './home.component'; @@ -9,6 +11,6 @@ import { HomeComponent } from './home.component'; schemas: [NO_ERRORS_SCHEMA], declarations: [AppComponent, HomeComponent], bootstrap: [AppComponent], - imports: [NativeScriptModule, AppRoutingModule], + imports: [NativeScriptModule, AppRoutingModule, WebViewExtModule], }) export class AppModule {} diff --git a/apps/demo-angular/src/assets/html/default.html b/apps/demo-angular/src/assets/html/default.html new file mode 100644 index 0000000..45cf1a2 --- /dev/null +++ b/apps/demo-angular/src/assets/html/default.html @@ -0,0 +1,40 @@ + + + + + + + CKEditor + + + + +
+ + diff --git a/apps/demo-angular/src/assets/js/ckeditor4.js b/apps/demo-angular/src/assets/js/ckeditor4.js new file mode 100644 index 0000000..b850c4d --- /dev/null +++ b/apps/demo-angular/src/assets/js/ckeditor4.js @@ -0,0 +1,165 @@ +// bridge interface for a regular content editable div +let nsWebViewBridge; +const waitCKEDITOR = setInterval(function () { + if (!window.CKEDITOR) return; + clearInterval(waitCKEDITOR); + + nsWebViewBridge = window.nsWebViewBridge; + if (nsWebViewBridge) { + initBridge(); + } else { + window.addEventListener('ns-bridge-ready', function (e) { + nsWebViewBridge = e.detail; + initBridge(); + }); + } +}, 10); + +const insertHeadScript = function (src) { + var externalScript = document.createElement('script'); + externalScript.setAttribute('src', src); + document.head.appendChild(externalScript); +}; + +const insertHeadCSS = function (src) { + var externalCSS = document.createElement('link'); + externalCSS.setAttribute('rel', 'stylesheet'); + externalCSS.setAttribute('type', 'text/css'); + externalCSS.setAttribute('href', src); + document.head.appendChild(externalCSS); +}; + +let currentSavedSelection; +const saveSelectionPromise = function () { + currentSavedSelection = CKEDITOR.instances.editor.getSelection().createBookmarks(); + return Promise.resolve(); +}; + +const restoreSelectionPromise = function () { + CKEDITOR.instances.editor.getSelection().selectBookmarks(currentSavedSelection); + return Promise.resolve(); +}; + +const getHtmlPromise = function () { + return Promise.resolve(CKEDITOR.instances.editor.getData()); +}; + +function initBridge() { + // android can end up reloading the html a lot and end up in a weird state somehow :/ + if (CKEDITOR.instances.editor) CKEDITOR.instances.editor.destroy(); + + const editorDiv = document.getElementById('editor'); + + // disable UI things that we're replacing with native buttons + const editorInstance = CKEDITOR.inline('editor', { + extraPlugins: 'justify,indentblock,indentlist', + removePlugins: 'liststyle,tableselection,tabletools,tableresize,contextmenu,toolbar', + allowedContent: true, + toolbar: [], + }); + + nsWebViewBridge.on('sourceChanged', function (data) { + editorInstance.setData(data); + }); + + nsWebViewBridge.on('done', function (data) { + editorInstance.focusManager.blur(true); + editorInstance.getSelection().removeAllRanges(); + editorDiv.blur(); + }); + + /* + * handle regular commands that dont take arguments + */ + const CKE_COMMAND_MAP = { + insertorderedlist: 'numberedlist', + insertunorderedlist: 'bulletedlist', + }; + const commonListeners = ['undo', 'redo', 'removeFormat', 'bold', 'underline', 'italic', 'justifyleft', 'justifycenter', 'justifyright', 'insertorderedlist', 'insertunorderedlist', 'outdent', 'indent']; + commonListeners.forEach((event) => { + nsWebViewBridge.on(event, (value) => { + value = value || null; + event = CKE_COMMAND_MAP[event] || event; + editorInstance.execCommand(event, false, value); + }); + }); + + /* + * Commands that take an argument are usually just CKEDITOR styles applied to selected text + */ + const CKE_COMMAND_STYLE_MAP = { + formatblock: (value) => new CKEDITOR.style({ element: value }), + createLink: (value) => new CKEDITOR.style({ element: 'a', attributes: { href: value }, type: CKEDITOR.STYLE_INLINE }), + backcolor: (value) => new CKEDITOR.style({ element: 'span', styles: { 'background-color': value } }), + fontname: (value) => { + return new CKEDITOR.style({ + element: 'span', + styles: { 'font-family': value }, + overrides: [ + { + element: 'font', + attributes: { face: null }, + }, + ], + }); + }, + fontsize: (value) => { + return new CKEDITOR.style({ + element: 'span', + styles: { 'font-size': value }, + overrides: [ + { + element: 'font', + attributes: { size: null }, + }, + ], + }); + }, + forecolor: (value) => { + return new CKEDITOR.style({ + element: 'span', + styles: { color: value }, + overrides: [ + { + element: 'font', + attributes: { color: null }, + }, + ], + }); + }, + }; + + Object.keys(CKE_COMMAND_STYLE_MAP).forEach((event) => { + nsWebViewBridge.on(event, (value) => { + if (!value) return; + editorInstance.applyStyle(CKE_COMMAND_STYLE_MAP[event](value)); + }); + }); + + editorInstance.on('instanceReady', () => { + editorInstance.on( + 'doubleclick', + function (evt) { + // TODO: emit this to the native side maybe? + return false; + }, + null, + null, + 1 + ); // last param gives this priority + + editorInstance.on('focus', function (event) { + nsWebViewBridge.emit('focus'); + }); + + editorInstance.on('blur', function (event) { + nsWebViewBridge.emit('blur'); + }); + + editorInstance.on('change', function (event) { + nsWebViewBridge.emit('input', editorInstance.getData()); + }); + + nsWebViewBridge.emit('ready'); + }); +} diff --git a/apps/demo-angular/src/assets/js/contenteditable.js b/apps/demo-angular/src/assets/js/contenteditable.js new file mode 100644 index 0000000..1228f98 --- /dev/null +++ b/apps/demo-angular/src/assets/js/contenteditable.js @@ -0,0 +1,158 @@ +// bridge interface for a regular content editable div + +const nsWebViewBridge = window.nsWebViewBridge; + +if (nsWebViewBridge) { + initBridge(); +} else { + window.addEventListener('ns-bridge-ready', function (e) { + const nsWebViewBridge = e.detail; + initBridge(); + }); +} + +const insertHeadScript = function (src) { + var externalScript = document.createElement('script'); + externalScript.setAttribute('src', src); + document.head.appendChild(externalScript); +}; + +const insertHeadCSS = function (src) { + var externalCSS = document.createElement('link'); + externalCSS.setAttribute('rel', 'stylesheet'); + externalCSS.setAttribute('type', 'text/css'); + externalCSS.setAttribute('href', src); + document.head.appendChild(externalCSS); +}; + +let currentSavedSelection; +const saveSelectionPromise = function () { + const editorInstance = document.getElementById('editor'); + const range = window.getSelection().getRangeAt(0); + const preSelectionRange = range.cloneRange(); + preSelectionRange.selectNodeContents(editorInstance); + preSelectionRange.setEnd(range.startContainer, range.startOffset); + const start = preSelectionRange.toString().length; + + currentSavedSelection = { + start: start, + end: start + range.toString().length, + }; + return Promise.resolve(); +}; + +const restoreSelectionPromise = function () { + const editorInstance = document.getElementById('editor'); + let charIndex = 0, + range = document.createRange(); + range.setStart(editorInstance, 0); + range.collapse(true); + let nodeStack = [editorInstance], + node, + foundStart = false, + stop = false; + + while (!stop && (node = nodeStack.pop())) { + if (node.nodeType == 3) { + const nextCharIndex = charIndex + node.length; + if (!foundStart && currentSavedSelection.start >= charIndex && currentSavedSelection.start <= nextCharIndex) { + range.setStart(node, currentSavedSelection.start - charIndex); + foundStart = true; + } + if (foundStart && currentSavedSelection.end >= charIndex && currentSavedSelection.end <= nextCharIndex) { + range.setEnd(node, currentSavedSelection.end - charIndex); + stop = true; + } + charIndex = nextCharIndex; + } else { + let i = node.childNodes.length; + while (i--) { + nodeStack.push(node.childNodes[i]); + } + } + } + + const sel = window.getSelection(); + sel.removeAllRanges(); + sel.addRange(range); + + return Promise.resolve(); +}; + +const getHtmlPromise = function () { + const editorInstance = document.getElementById('editor'); + return Promise.resolve(editorInstance.innerHTML); +}; + +function initBridge() { + const editorInstance = document.getElementById('editor'); + + editorInstance.addEventListener( + 'blur', + () => { + nsWebViewBridge.emit('blur'); + }, + false + ); + editorInstance.addEventListener( + 'focus', + () => { + nsWebViewBridge.emit('focus'); + }, + false + ); + editorInstance.addEventListener( + 'input', + () => { + nsWebViewBridge.emit('input', editorInstance.innerHTML); + }, + false + ); + + nsWebViewBridge.on('sourceChanged', function (data) { + editorInstance.innerHTML = data; + }); + + nsWebViewBridge.on('focus', function () { + editorInstance.focus(); + }); + + nsWebViewBridge.on('done', function () { + window.getSelection().removeAllRanges(); + editorInstance.blur(); + }); + + nsWebViewBridge.on('fontsize', (value) => { + document.execCommand('fontsize', false, '7'); + const fontElements = document.getElementsByTagName('font'); + for (let i = 0, len = fontElements.length; i < len; ++i) { + if (fontElements[i].size == '7') { + fontElements[i].removeAttribute('size'); + fontElements[i].style.fontSize = value; + } + } + editorInstance.dispatchEvent(new Event('input')); + }); + + nsWebViewBridge.on('fontname', (value) => { + document.execCommand('fontsize', false, '7'); + const fontElements = document.getElementsByTagName('font'); + for (let i = 0, len = fontElements.length; i < len; ++i) { + if (fontElements[i].size == '7') { + fontElements[i].removeAttribute('size'); + fontElements[i].style.fontFamily = value; + } + } + editorInstance.dispatchEvent(new Event('input')); + }); + + const commonListeners = ['undo', 'redo', 'removeFormat', 'bold', 'underline', 'italic', 'justifyleft', 'justifycenter', 'justifyright', 'insertorderedlist', 'insertunorderedlist', 'outdent', 'indent', 'createLink', 'formatblock', 'forecolor', 'backcolor']; + commonListeners.forEach((event) => { + nsWebViewBridge.on(event, (value) => { + value = value || null; + document.execCommand(event, false, value); + }); + }); + + nsWebViewBridge.emit('ready'); +} diff --git a/apps/demo-angular/src/plugin-demos/rich-text-editor.component.html b/apps/demo-angular/src/plugin-demos/rich-text-editor.component.html index dff21c8..117ec47 100644 --- a/apps/demo-angular/src/plugin-demos/rich-text-editor.component.html +++ b/apps/demo-angular/src/plugin-demos/rich-text-editor.component.html @@ -1,8 +1,7 @@ - - - - - - - + + + + + + diff --git a/apps/demo-angular/src/plugin-demos/rich-text-editor.component.ts b/apps/demo-angular/src/plugin-demos/rich-text-editor.component.ts index c9debbc..aaa5536 100644 --- a/apps/demo-angular/src/plugin-demos/rich-text-editor.component.ts +++ b/apps/demo-angular/src/plugin-demos/rich-text-editor.component.ts @@ -8,10 +8,24 @@ import {} from '@finalsite/rich-text-editor'; }) export class RichTextEditorComponent { demoShared: DemoSharedRichTextEditor; + _editorContent: string = + '

leonardo

Leonardo

Nicknamed Leo, is a fictional superhero and one of the four main characters in the Teenage Mutant Ninja Turtles comics and related media.

He is often depicted wearing a blue bandanna. His signature weapons are two Ninjatos, commonly confused as Katanas. Leonardo is the eldest brother and the leader of the group. He is the most skilled, the most serious, the most spiritual, the most mature, the most disciplined and the most in-line with Splinter's teachings and thoughts. Like all of the brothers, he is named after an Italian Renaissance artist, in this case Leonardo da Vinci. Leonardo da Vinci is widely considered the most diversely skilled individual of the Renaissance period, and as such Leonardo is also considered the most diversely skilled ninja turtle. In the Mirage comics, all four of the Turtles wear red masks, but for the creators to tell them apart, he was written and redrawn to have an ocean-blue mask.

Raphael

Raphael

Nicknamed Raph, is a fictional superhero and one of the four main characters of the Teenage Mutant Ninja Turtles comics and all related media. He is generally depicted as the second oldest/mid-middle-child of the turtle brothers, but has once been portrayed as the eldest.

He is usually depicted wearing a red eye mask; in this regard he is the only turtle to retain the color in all media, whereas the others each received a different color. Raphael wields twin sai, the points of which are usually sharpened, as his primary weapon. Raphael is most famous for his temperamental and cynical personality, being short-tempered, aggressive, sullen, maddened, sarcastic, and rebellious. He is portrayed in most interaction as speaking with a Brooklyn accent. It may be a coincidence, but the fact that he has a bad and fiery attitude and temper and the fact that his mask is still red may be linked, since the color red is typically associated with anger.

The origin of Raphael's anger is not always fully explored, but in some incarnations appears to stem partly from the realization that they are the only creatures of their kind and ultimately alone. He also has a somewhat rival relationship with his only older brother Leonardo because he is seen as the group's leader. Raphael also gives his younger and youngest brother Michelangelo a hard time because of Michelangelo’s fiery optimism. He is the second eldest of the turtles, and second-in-command. Like all of the brothers, he is named after a Renaissance artist; in this case, he is named after the 16th-century Italian painter Raphael. In 2011, Raphael placed 23rd on IGN's Top 100 Comic Book Heroes, a list that did not feature any of his brothers. He is the only Teenage Turtle brother whose name does not end in the letter "O".

[https://en.wikipedia.org/wiki/Teenage_Mutant_Ninja_Turtles]

'; constructor(private _ngZone: NgZone) {} ngOnInit() { this.demoShared = new DemoSharedRichTextEditor(); } + + onViewSource() { + alert(this._editorContent) + } + + get editorContent() { + return this._editorContent; + } + + set editorContent(content) { + this._editorContent = content + } } diff --git a/apps/demo-angular/src/plugin-demos/rich-text-editor.module.ts b/apps/demo-angular/src/plugin-demos/rich-text-editor.module.ts index e03b975..f28d503 100644 --- a/apps/demo-angular/src/plugin-demos/rich-text-editor.module.ts +++ b/apps/demo-angular/src/plugin-demos/rich-text-editor.module.ts @@ -1,9 +1,10 @@ import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core'; import { NativeScriptCommonModule, NativeScriptRouterModule } from '@nativescript/angular'; import { RichTextEditorComponent } from './rich-text-editor.component'; +import { NativeScriptRichTextEditorModule } from '@finalsite/rich-text-editor/angular' @NgModule({ - imports: [NativeScriptCommonModule, NativeScriptRouterModule.forChild([{ path: '', component: RichTextEditorComponent }])], + imports: [NativeScriptCommonModule, NativeScriptRichTextEditorModule, NativeScriptRouterModule.forChild([{ path: '', component: RichTextEditorComponent }])], declarations: [RichTextEditorComponent], schemas: [NO_ERRORS_SCHEMA], }) diff --git a/apps/demo-angular/webpack.config.js b/apps/demo-angular/webpack.config.js index 77e424b..283e687 100644 --- a/apps/demo-angular/webpack.config.js +++ b/apps/demo-angular/webpack.config.js @@ -329,7 +329,7 @@ module.exports = (env) => { verbose: !!verbose, }), // Copy assets - new CopyWebpackPlugin([...copyTargets, { from: { glob: '**/*.jpg', dot: false } }, { from: { glob: '**/*.png', dot: false } }], copyIgnore), + new CopyWebpackPlugin([...copyTargets, { from: { glob: 'assets/**', dot: false } }, { from: { glob: 'fonts/**', dot: false } }, { from: { glob: '**/*.jpg', dot: false } }, { from: { glob: '**/*.png', dot: false } }], copyIgnore), new nsWebpack.GenerateNativeScriptEntryPointsPlugin('bundle'), // For instructions on how to set up workers with webpack // check out https://github.com/nativescript/worker-loader diff --git a/apps/demo-vue/.editorconfig b/apps/demo-vue/.editorconfig new file mode 100644 index 0000000..84ba4fa --- /dev/null +++ b/apps/demo-vue/.editorconfig @@ -0,0 +1,19 @@ +root = true + +[*] +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +charset = utf-8 + +[*.json] +indent_style = space +indent_size = 2 + +[*.js] +indent_style = space +indent_size = 2 + +[*.ts] +indent_style = space +indent_size = 2 \ No newline at end of file diff --git a/apps/demo-vue/.gitignore b/apps/demo-vue/.gitignore new file mode 100644 index 0000000..1cb1231 --- /dev/null +++ b/apps/demo-vue/.gitignore @@ -0,0 +1,28 @@ +# NativeScript +hooks/ +node_modules/ +platforms/ + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# General +.DS_Store +.AppleDouble +.LSOverride +.idea +.cloud +.project +tmp/ +typings/ + +# Visual Studio Code +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json diff --git a/apps/demo-vue/.vscode/extensions.json b/apps/demo-vue/.vscode/extensions.json new file mode 100644 index 0000000..2a163b8 --- /dev/null +++ b/apps/demo-vue/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["nativescript.nativescript"] +} diff --git a/apps/demo-vue/App_Resources/Android/app.gradle b/apps/demo-vue/App_Resources/Android/app.gradle new file mode 100644 index 0000000..5b26299 --- /dev/null +++ b/apps/demo-vue/App_Resources/Android/app.gradle @@ -0,0 +1,25 @@ +// You can add your native dependencies here +dependencies { +// implementation 'androidx.multidex:multidex:2.0.1' +} + +android { + // compileSdkVersion 32 + // buildToolsVersion "32.0.0" + // ndkVersion "" + + defaultConfig { + minSdkVersion 17 + // targetSdkVersion 32 + + // Version Information + versionCode 1 + versionName "1.0.0" + + generatedDensities = [] + } + + aaptOptions { + additionalParameters "--no-version-vectors" + } +} diff --git a/apps/demo-vue/App_Resources/Android/before-plugins.gradle b/apps/demo-vue/App_Resources/Android/before-plugins.gradle new file mode 100644 index 0000000..9faffb8 --- /dev/null +++ b/apps/demo-vue/App_Resources/Android/before-plugins.gradle @@ -0,0 +1,15 @@ +// this configurations is loaded before building plugins, as well as before building +// the app - this is where you can apply global settings and overrides + +project.ext { + // androidXAppCompat = "1.4.1" + // androidXExifInterface = "1.3.3" + // androidXFragment = "1.4.1" + // androidXMaterial = "1.5.0" + // androidXMultidex = "2.0.1" + // androidXTransition = "1.4.1" + // androidXViewPager = "1.0.0" + + // useKotlin = true + // kotlinVersion = "1.6.0" +} diff --git a/apps/demo-vue/App_Resources/Android/src/main/AndroidManifest.xml b/apps/demo-vue/App_Resources/Android/src/main/AndroidManifest.xml new file mode 100644 index 0000000..6601773 --- /dev/null +++ b/apps/demo-vue/App_Resources/Android/src/main/AndroidManifest.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/demo-vue/App_Resources/Android/src/main/res/drawable-hdpi/background.png b/apps/demo-vue/App_Resources/Android/src/main/res/drawable-hdpi/background.png new file mode 100644 index 0000000..bbefbf4 Binary files /dev/null and b/apps/demo-vue/App_Resources/Android/src/main/res/drawable-hdpi/background.png differ diff --git a/apps/demo-vue/App_Resources/Android/src/main/res/drawable-hdpi/logo.png b/apps/demo-vue/App_Resources/Android/src/main/res/drawable-hdpi/logo.png new file mode 100644 index 0000000..e788deb Binary files /dev/null and b/apps/demo-vue/App_Resources/Android/src/main/res/drawable-hdpi/logo.png differ diff --git a/apps/demo-vue/App_Resources/Android/src/main/res/drawable-ldpi/background.png b/apps/demo-vue/App_Resources/Android/src/main/res/drawable-ldpi/background.png new file mode 100644 index 0000000..f6a08ee Binary files /dev/null and b/apps/demo-vue/App_Resources/Android/src/main/res/drawable-ldpi/background.png differ diff --git a/apps/demo-vue/App_Resources/Android/src/main/res/drawable-ldpi/logo.png b/apps/demo-vue/App_Resources/Android/src/main/res/drawable-ldpi/logo.png new file mode 100644 index 0000000..e4cac1a Binary files /dev/null and b/apps/demo-vue/App_Resources/Android/src/main/res/drawable-ldpi/logo.png differ diff --git a/apps/demo-vue/App_Resources/Android/src/main/res/drawable-mdpi/background.png b/apps/demo-vue/App_Resources/Android/src/main/res/drawable-mdpi/background.png new file mode 100644 index 0000000..0c90f0f Binary files /dev/null and b/apps/demo-vue/App_Resources/Android/src/main/res/drawable-mdpi/background.png differ diff --git a/apps/demo-vue/App_Resources/Android/src/main/res/drawable-mdpi/logo.png b/apps/demo-vue/App_Resources/Android/src/main/res/drawable-mdpi/logo.png new file mode 100644 index 0000000..ce3c3a4 Binary files /dev/null and b/apps/demo-vue/App_Resources/Android/src/main/res/drawable-mdpi/logo.png differ diff --git a/apps/demo-vue/App_Resources/Android/src/main/res/drawable-nodpi/splash_screen.xml b/apps/demo-vue/App_Resources/Android/src/main/res/drawable-nodpi/splash_screen.xml new file mode 100644 index 0000000..ada77f9 --- /dev/null +++ b/apps/demo-vue/App_Resources/Android/src/main/res/drawable-nodpi/splash_screen.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/apps/demo-vue/App_Resources/Android/src/main/res/drawable-xhdpi/background.png b/apps/demo-vue/App_Resources/Android/src/main/res/drawable-xhdpi/background.png new file mode 100644 index 0000000..3541570 Binary files /dev/null and b/apps/demo-vue/App_Resources/Android/src/main/res/drawable-xhdpi/background.png differ diff --git a/apps/demo-vue/App_Resources/Android/src/main/res/drawable-xhdpi/logo.png b/apps/demo-vue/App_Resources/Android/src/main/res/drawable-xhdpi/logo.png new file mode 100644 index 0000000..88267df Binary files /dev/null and b/apps/demo-vue/App_Resources/Android/src/main/res/drawable-xhdpi/logo.png differ diff --git a/apps/demo-vue/App_Resources/Android/src/main/res/drawable-xxhdpi/background.png b/apps/demo-vue/App_Resources/Android/src/main/res/drawable-xxhdpi/background.png new file mode 100644 index 0000000..abb0fc7 Binary files /dev/null and b/apps/demo-vue/App_Resources/Android/src/main/res/drawable-xxhdpi/background.png differ diff --git a/apps/demo-vue/App_Resources/Android/src/main/res/drawable-xxhdpi/logo.png b/apps/demo-vue/App_Resources/Android/src/main/res/drawable-xxhdpi/logo.png new file mode 100644 index 0000000..55800c9 Binary files /dev/null and b/apps/demo-vue/App_Resources/Android/src/main/res/drawable-xxhdpi/logo.png differ diff --git a/apps/demo-vue/App_Resources/Android/src/main/res/drawable-xxxhdpi/background.png b/apps/demo-vue/App_Resources/Android/src/main/res/drawable-xxxhdpi/background.png new file mode 100644 index 0000000..1089775 Binary files /dev/null and b/apps/demo-vue/App_Resources/Android/src/main/res/drawable-xxxhdpi/background.png differ diff --git a/apps/demo-vue/App_Resources/Android/src/main/res/drawable-xxxhdpi/logo.png b/apps/demo-vue/App_Resources/Android/src/main/res/drawable-xxxhdpi/logo.png new file mode 100644 index 0000000..0703f90 Binary files /dev/null and b/apps/demo-vue/App_Resources/Android/src/main/res/drawable-xxxhdpi/logo.png differ diff --git a/apps/demo-vue/App_Resources/Android/src/main/res/drawable/ic_launcher_foreground.xml b/apps/demo-vue/App_Resources/Android/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..fd826a3 --- /dev/null +++ b/apps/demo-vue/App_Resources/Android/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/apps/demo-vue/App_Resources/Android/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/apps/demo-vue/App_Resources/Android/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..7353dbd --- /dev/null +++ b/apps/demo-vue/App_Resources/Android/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/apps/demo-vue/App_Resources/Android/src/main/res/mipmap-hdpi/ic_launcher.png b/apps/demo-vue/App_Resources/Android/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..69948d2 Binary files /dev/null and b/apps/demo-vue/App_Resources/Android/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/apps/demo-vue/App_Resources/Android/src/main/res/mipmap-mdpi/ic_launcher.png b/apps/demo-vue/App_Resources/Android/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..90a58cd Binary files /dev/null and b/apps/demo-vue/App_Resources/Android/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/apps/demo-vue/App_Resources/Android/src/main/res/mipmap-xhdpi/ic_launcher.png b/apps/demo-vue/App_Resources/Android/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..70a2a0d Binary files /dev/null and b/apps/demo-vue/App_Resources/Android/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/apps/demo-vue/App_Resources/Android/src/main/res/mipmap-xxhdpi/ic_launcher.png b/apps/demo-vue/App_Resources/Android/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..1ee5a94 Binary files /dev/null and b/apps/demo-vue/App_Resources/Android/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/apps/demo-vue/App_Resources/Android/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/apps/demo-vue/App_Resources/Android/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..66e9d4b Binary files /dev/null and b/apps/demo-vue/App_Resources/Android/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/apps/demo-vue/App_Resources/Android/src/main/res/values-v21/colors.xml b/apps/demo-vue/App_Resources/Android/src/main/res/values-v21/colors.xml new file mode 100644 index 0000000..da5ca2f --- /dev/null +++ b/apps/demo-vue/App_Resources/Android/src/main/res/values-v21/colors.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/apps/demo-vue/App_Resources/Android/src/main/res/values-v21/styles.xml b/apps/demo-vue/App_Resources/Android/src/main/res/values-v21/styles.xml new file mode 100644 index 0000000..04d8a06 --- /dev/null +++ b/apps/demo-vue/App_Resources/Android/src/main/res/values-v21/styles.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + diff --git a/apps/demo-vue/App_Resources/Android/src/main/res/values-v29/styles.xml b/apps/demo-vue/App_Resources/Android/src/main/res/values-v29/styles.xml new file mode 100644 index 0000000..9a2a79d --- /dev/null +++ b/apps/demo-vue/App_Resources/Android/src/main/res/values-v29/styles.xml @@ -0,0 +1,18 @@ + + + + + + + + + \ No newline at end of file diff --git a/apps/demo-vue/App_Resources/Android/src/main/res/values/colors.xml b/apps/demo-vue/App_Resources/Android/src/main/res/values/colors.xml new file mode 100644 index 0000000..78c4a51 --- /dev/null +++ b/apps/demo-vue/App_Resources/Android/src/main/res/values/colors.xml @@ -0,0 +1,14 @@ + + + + #F5F5F5 + + + #757575 + + + #65ADF1 + + + + diff --git a/apps/demo-vue/App_Resources/Android/src/main/res/values/ic_launcher_background.xml b/apps/demo-vue/App_Resources/Android/src/main/res/values/ic_launcher_background.xml new file mode 100644 index 0000000..c5d5899 --- /dev/null +++ b/apps/demo-vue/App_Resources/Android/src/main/res/values/ic_launcher_background.xml @@ -0,0 +1,4 @@ + + + #FFFFFF + \ No newline at end of file diff --git a/apps/demo-vue/App_Resources/Android/src/main/res/values/styles.xml b/apps/demo-vue/App_Resources/Android/src/main/res/values/styles.xml new file mode 100644 index 0000000..4f91b61 --- /dev/null +++ b/apps/demo-vue/App_Resources/Android/src/main/res/values/styles.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + diff --git a/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/Contents.json b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..1a8b0e6 --- /dev/null +++ b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "icon-20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "icon-20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "icon-29.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "icon-29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "icon-29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "icon-40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "icon-40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "icon-60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "icon-60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "icon-20.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "icon-20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "icon-29.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "icon-29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "icon-40.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "icon-40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "icon-76.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "icon-76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "icon-83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "icon-1024.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-1024.png b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-1024.png new file mode 100644 index 0000000..b46c8bb Binary files /dev/null and b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-1024.png differ diff --git a/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-20.png b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-20.png new file mode 100644 index 0000000..d73288a Binary files /dev/null and b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-20.png differ diff --git a/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-20@2x.png b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-20@2x.png new file mode 100644 index 0000000..c8d24cd Binary files /dev/null and b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-20@2x.png differ diff --git a/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-20@3x.png b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-20@3x.png new file mode 100644 index 0000000..1b00c84 Binary files /dev/null and b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-20@3x.png differ diff --git a/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29.png b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29.png new file mode 100644 index 0000000..72a1641 Binary files /dev/null and b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29.png differ diff --git a/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@2x.png b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@2x.png new file mode 100644 index 0000000..05ab752 Binary files /dev/null and b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@2x.png differ diff --git a/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@3x.png b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@3x.png new file mode 100644 index 0000000..ee72082 Binary files /dev/null and b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-29@3x.png differ diff --git a/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40.png b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40.png new file mode 100644 index 0000000..2859288 Binary files /dev/null and b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40.png differ diff --git a/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png new file mode 100644 index 0000000..88824fa Binary files /dev/null and b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png differ diff --git a/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@3x.png b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@3x.png new file mode 100644 index 0000000..02a930c Binary files /dev/null and b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-40@3x.png differ diff --git a/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png new file mode 100644 index 0000000..d7b077f Binary files /dev/null and b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png differ diff --git a/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png new file mode 100644 index 0000000..2f872dd Binary files /dev/null and b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png differ diff --git a/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76.png b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76.png new file mode 100644 index 0000000..7fb23a7 Binary files /dev/null and b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76.png differ diff --git a/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png new file mode 100644 index 0000000..cb04c36 Binary files /dev/null and b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png differ diff --git a/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-83.5@2x.png b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-83.5@2x.png new file mode 100644 index 0000000..e882226 Binary files /dev/null and b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/AppIcon.appiconset/icon-83.5@2x.png differ diff --git a/apps/demo-vue/App_Resources/iOS/Assets.xcassets/Contents.json b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/apps/demo-vue/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/Contents.json b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/Contents.json new file mode 100644 index 0000000..ab5edd0 --- /dev/null +++ b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchScreen-AspectFill.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchScreen-AspectFill@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchScreen-AspectFill@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/apps/demo-vue/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill.png b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill.png new file mode 100644 index 0000000..cb35cfa Binary files /dev/null and b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill.png differ diff --git a/apps/demo-vue/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill@2x.png b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill@2x.png new file mode 100644 index 0000000..6eefb9a Binary files /dev/null and b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill@2x.png differ diff --git a/apps/demo-vue/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill@3x.png b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill@3x.png new file mode 100644 index 0000000..0ef5102 Binary files /dev/null and b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/LaunchScreen.AspectFill.imageset/LaunchScreen-AspectFill@3x.png differ diff --git a/apps/demo-vue/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/Contents.json b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/Contents.json new file mode 100644 index 0000000..444d715 --- /dev/null +++ b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchScreen-Center.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchScreen-Center@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchScreen-Center@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/apps/demo-vue/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center.png b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center.png new file mode 100644 index 0000000..280c30e Binary files /dev/null and b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center.png differ diff --git a/apps/demo-vue/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center@2x.png b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center@2x.png new file mode 100644 index 0000000..f984b9e Binary files /dev/null and b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center@2x.png differ diff --git a/apps/demo-vue/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center@3x.png b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center@3x.png new file mode 100644 index 0000000..95d86f3 Binary files /dev/null and b/apps/demo-vue/App_Resources/iOS/Assets.xcassets/LaunchScreen.Center.imageset/LaunchScreen-Center@3x.png differ diff --git a/apps/demo-vue/App_Resources/iOS/Info.plist b/apps/demo-vue/App_Resources/iOS/Info.plist new file mode 100644 index 0000000..ea3e3ea --- /dev/null +++ b/apps/demo-vue/App_Resources/iOS/Info.plist @@ -0,0 +1,47 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + ${PRODUCT_NAME} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIRequiresFullScreen + + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/apps/demo-vue/App_Resources/iOS/LaunchScreen.storyboard b/apps/demo-vue/App_Resources/iOS/LaunchScreen.storyboard new file mode 100644 index 0000000..c4e5a3f --- /dev/null +++ b/apps/demo-vue/App_Resources/iOS/LaunchScreen.storyboard @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/demo-vue/App_Resources/iOS/build.xcconfig b/apps/demo-vue/App_Resources/iOS/build.xcconfig new file mode 100644 index 0000000..0d38fe0 --- /dev/null +++ b/apps/demo-vue/App_Resources/iOS/build.xcconfig @@ -0,0 +1,6 @@ +// You can add custom settings here +// for example you can uncomment the following line to force distribution code signing +// CODE_SIGN_IDENTITY = iPhone Distribution +// To build for device with XCode you need to specify your development team. +// DEVELOPMENT_TEAM = YOUR_TEAM_ID; +ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; diff --git a/apps/demo-vue/app/app.js b/apps/demo-vue/app/app.js new file mode 100644 index 0000000..f37ae73 --- /dev/null +++ b/apps/demo-vue/app/app.js @@ -0,0 +1,10 @@ +import Vue from 'nativescript-vue' + +import Home from './components/Home' + +import RichTextEditor from "@finalsite/rich-text-editor/vue" +RichTextEditor.install(Vue) + +new Vue({ + render: (h) => h('frame', [h(Home)]), +}).$start() diff --git a/apps/demo-vue/app/app.scss b/apps/demo-vue/app/app.scss new file mode 100644 index 0000000..9c3948e --- /dev/null +++ b/apps/demo-vue/app/app.scss @@ -0,0 +1,21 @@ +@import '@nativescript/theme/core'; +@import '@nativescript/theme/default'; + +// Place any CSS rules you want to apply on both iOS and Android here. +// This is where the vast majority of your CSS code goes. + +// Font icon class +.fab { + font-family: 'Font Awesome 5 Brands', 'fa-brands-400'; + font-weight: 400; +} + +.fas { + font-family: 'Font Awesome 5 Free', 'fa-solid-900'; + font-weight: 900; +} + +.far { + font-family: 'Font Awesome 5 Free', 'fa-regular-400'; + font-weight: 400; +} diff --git a/apps/demo-vue/app/assets/html/default.html b/apps/demo-vue/app/assets/html/default.html new file mode 100644 index 0000000..45cf1a2 --- /dev/null +++ b/apps/demo-vue/app/assets/html/default.html @@ -0,0 +1,40 @@ + + + + + + + CKEditor + + + + +
+ + diff --git a/apps/demo-vue/app/assets/js/ckeditor4.js b/apps/demo-vue/app/assets/js/ckeditor4.js new file mode 100644 index 0000000..b850c4d --- /dev/null +++ b/apps/demo-vue/app/assets/js/ckeditor4.js @@ -0,0 +1,165 @@ +// bridge interface for a regular content editable div +let nsWebViewBridge; +const waitCKEDITOR = setInterval(function () { + if (!window.CKEDITOR) return; + clearInterval(waitCKEDITOR); + + nsWebViewBridge = window.nsWebViewBridge; + if (nsWebViewBridge) { + initBridge(); + } else { + window.addEventListener('ns-bridge-ready', function (e) { + nsWebViewBridge = e.detail; + initBridge(); + }); + } +}, 10); + +const insertHeadScript = function (src) { + var externalScript = document.createElement('script'); + externalScript.setAttribute('src', src); + document.head.appendChild(externalScript); +}; + +const insertHeadCSS = function (src) { + var externalCSS = document.createElement('link'); + externalCSS.setAttribute('rel', 'stylesheet'); + externalCSS.setAttribute('type', 'text/css'); + externalCSS.setAttribute('href', src); + document.head.appendChild(externalCSS); +}; + +let currentSavedSelection; +const saveSelectionPromise = function () { + currentSavedSelection = CKEDITOR.instances.editor.getSelection().createBookmarks(); + return Promise.resolve(); +}; + +const restoreSelectionPromise = function () { + CKEDITOR.instances.editor.getSelection().selectBookmarks(currentSavedSelection); + return Promise.resolve(); +}; + +const getHtmlPromise = function () { + return Promise.resolve(CKEDITOR.instances.editor.getData()); +}; + +function initBridge() { + // android can end up reloading the html a lot and end up in a weird state somehow :/ + if (CKEDITOR.instances.editor) CKEDITOR.instances.editor.destroy(); + + const editorDiv = document.getElementById('editor'); + + // disable UI things that we're replacing with native buttons + const editorInstance = CKEDITOR.inline('editor', { + extraPlugins: 'justify,indentblock,indentlist', + removePlugins: 'liststyle,tableselection,tabletools,tableresize,contextmenu,toolbar', + allowedContent: true, + toolbar: [], + }); + + nsWebViewBridge.on('sourceChanged', function (data) { + editorInstance.setData(data); + }); + + nsWebViewBridge.on('done', function (data) { + editorInstance.focusManager.blur(true); + editorInstance.getSelection().removeAllRanges(); + editorDiv.blur(); + }); + + /* + * handle regular commands that dont take arguments + */ + const CKE_COMMAND_MAP = { + insertorderedlist: 'numberedlist', + insertunorderedlist: 'bulletedlist', + }; + const commonListeners = ['undo', 'redo', 'removeFormat', 'bold', 'underline', 'italic', 'justifyleft', 'justifycenter', 'justifyright', 'insertorderedlist', 'insertunorderedlist', 'outdent', 'indent']; + commonListeners.forEach((event) => { + nsWebViewBridge.on(event, (value) => { + value = value || null; + event = CKE_COMMAND_MAP[event] || event; + editorInstance.execCommand(event, false, value); + }); + }); + + /* + * Commands that take an argument are usually just CKEDITOR styles applied to selected text + */ + const CKE_COMMAND_STYLE_MAP = { + formatblock: (value) => new CKEDITOR.style({ element: value }), + createLink: (value) => new CKEDITOR.style({ element: 'a', attributes: { href: value }, type: CKEDITOR.STYLE_INLINE }), + backcolor: (value) => new CKEDITOR.style({ element: 'span', styles: { 'background-color': value } }), + fontname: (value) => { + return new CKEDITOR.style({ + element: 'span', + styles: { 'font-family': value }, + overrides: [ + { + element: 'font', + attributes: { face: null }, + }, + ], + }); + }, + fontsize: (value) => { + return new CKEDITOR.style({ + element: 'span', + styles: { 'font-size': value }, + overrides: [ + { + element: 'font', + attributes: { size: null }, + }, + ], + }); + }, + forecolor: (value) => { + return new CKEDITOR.style({ + element: 'span', + styles: { color: value }, + overrides: [ + { + element: 'font', + attributes: { color: null }, + }, + ], + }); + }, + }; + + Object.keys(CKE_COMMAND_STYLE_MAP).forEach((event) => { + nsWebViewBridge.on(event, (value) => { + if (!value) return; + editorInstance.applyStyle(CKE_COMMAND_STYLE_MAP[event](value)); + }); + }); + + editorInstance.on('instanceReady', () => { + editorInstance.on( + 'doubleclick', + function (evt) { + // TODO: emit this to the native side maybe? + return false; + }, + null, + null, + 1 + ); // last param gives this priority + + editorInstance.on('focus', function (event) { + nsWebViewBridge.emit('focus'); + }); + + editorInstance.on('blur', function (event) { + nsWebViewBridge.emit('blur'); + }); + + editorInstance.on('change', function (event) { + nsWebViewBridge.emit('input', editorInstance.getData()); + }); + + nsWebViewBridge.emit('ready'); + }); +} diff --git a/apps/demo-vue/app/assets/js/contenteditable.js b/apps/demo-vue/app/assets/js/contenteditable.js new file mode 100644 index 0000000..1228f98 --- /dev/null +++ b/apps/demo-vue/app/assets/js/contenteditable.js @@ -0,0 +1,158 @@ +// bridge interface for a regular content editable div + +const nsWebViewBridge = window.nsWebViewBridge; + +if (nsWebViewBridge) { + initBridge(); +} else { + window.addEventListener('ns-bridge-ready', function (e) { + const nsWebViewBridge = e.detail; + initBridge(); + }); +} + +const insertHeadScript = function (src) { + var externalScript = document.createElement('script'); + externalScript.setAttribute('src', src); + document.head.appendChild(externalScript); +}; + +const insertHeadCSS = function (src) { + var externalCSS = document.createElement('link'); + externalCSS.setAttribute('rel', 'stylesheet'); + externalCSS.setAttribute('type', 'text/css'); + externalCSS.setAttribute('href', src); + document.head.appendChild(externalCSS); +}; + +let currentSavedSelection; +const saveSelectionPromise = function () { + const editorInstance = document.getElementById('editor'); + const range = window.getSelection().getRangeAt(0); + const preSelectionRange = range.cloneRange(); + preSelectionRange.selectNodeContents(editorInstance); + preSelectionRange.setEnd(range.startContainer, range.startOffset); + const start = preSelectionRange.toString().length; + + currentSavedSelection = { + start: start, + end: start + range.toString().length, + }; + return Promise.resolve(); +}; + +const restoreSelectionPromise = function () { + const editorInstance = document.getElementById('editor'); + let charIndex = 0, + range = document.createRange(); + range.setStart(editorInstance, 0); + range.collapse(true); + let nodeStack = [editorInstance], + node, + foundStart = false, + stop = false; + + while (!stop && (node = nodeStack.pop())) { + if (node.nodeType == 3) { + const nextCharIndex = charIndex + node.length; + if (!foundStart && currentSavedSelection.start >= charIndex && currentSavedSelection.start <= nextCharIndex) { + range.setStart(node, currentSavedSelection.start - charIndex); + foundStart = true; + } + if (foundStart && currentSavedSelection.end >= charIndex && currentSavedSelection.end <= nextCharIndex) { + range.setEnd(node, currentSavedSelection.end - charIndex); + stop = true; + } + charIndex = nextCharIndex; + } else { + let i = node.childNodes.length; + while (i--) { + nodeStack.push(node.childNodes[i]); + } + } + } + + const sel = window.getSelection(); + sel.removeAllRanges(); + sel.addRange(range); + + return Promise.resolve(); +}; + +const getHtmlPromise = function () { + const editorInstance = document.getElementById('editor'); + return Promise.resolve(editorInstance.innerHTML); +}; + +function initBridge() { + const editorInstance = document.getElementById('editor'); + + editorInstance.addEventListener( + 'blur', + () => { + nsWebViewBridge.emit('blur'); + }, + false + ); + editorInstance.addEventListener( + 'focus', + () => { + nsWebViewBridge.emit('focus'); + }, + false + ); + editorInstance.addEventListener( + 'input', + () => { + nsWebViewBridge.emit('input', editorInstance.innerHTML); + }, + false + ); + + nsWebViewBridge.on('sourceChanged', function (data) { + editorInstance.innerHTML = data; + }); + + nsWebViewBridge.on('focus', function () { + editorInstance.focus(); + }); + + nsWebViewBridge.on('done', function () { + window.getSelection().removeAllRanges(); + editorInstance.blur(); + }); + + nsWebViewBridge.on('fontsize', (value) => { + document.execCommand('fontsize', false, '7'); + const fontElements = document.getElementsByTagName('font'); + for (let i = 0, len = fontElements.length; i < len; ++i) { + if (fontElements[i].size == '7') { + fontElements[i].removeAttribute('size'); + fontElements[i].style.fontSize = value; + } + } + editorInstance.dispatchEvent(new Event('input')); + }); + + nsWebViewBridge.on('fontname', (value) => { + document.execCommand('fontsize', false, '7'); + const fontElements = document.getElementsByTagName('font'); + for (let i = 0, len = fontElements.length; i < len; ++i) { + if (fontElements[i].size == '7') { + fontElements[i].removeAttribute('size'); + fontElements[i].style.fontFamily = value; + } + } + editorInstance.dispatchEvent(new Event('input')); + }); + + const commonListeners = ['undo', 'redo', 'removeFormat', 'bold', 'underline', 'italic', 'justifyleft', 'justifycenter', 'justifyright', 'insertorderedlist', 'insertunorderedlist', 'outdent', 'indent', 'createLink', 'formatblock', 'forecolor', 'backcolor']; + commonListeners.forEach((event) => { + nsWebViewBridge.on(event, (value) => { + value = value || null; + document.execCommand(event, false, value); + }); + }); + + nsWebViewBridge.emit('ready'); +} diff --git a/apps/demo-vue/app/components/Home.vue b/apps/demo-vue/app/components/Home.vue new file mode 100644 index 0000000..957300f --- /dev/null +++ b/apps/demo-vue/app/components/Home.vue @@ -0,0 +1,38 @@ + + + + + diff --git a/apps/demo-vue/app/fonts/fa-brands-400.ttf b/apps/demo-vue/app/fonts/fa-brands-400.ttf new file mode 100644 index 0000000..0a30775 Binary files /dev/null and b/apps/demo-vue/app/fonts/fa-brands-400.ttf differ diff --git a/apps/demo-vue/app/fonts/fa-regular-400.ttf b/apps/demo-vue/app/fonts/fa-regular-400.ttf new file mode 100644 index 0000000..b5414de Binary files /dev/null and b/apps/demo-vue/app/fonts/fa-regular-400.ttf differ diff --git a/apps/demo-vue/app/fonts/fa-solid-900.ttf b/apps/demo-vue/app/fonts/fa-solid-900.ttf new file mode 100644 index 0000000..53c8f36 Binary files /dev/null and b/apps/demo-vue/app/fonts/fa-solid-900.ttf differ diff --git a/apps/demo-vue/jsconfig.json b/apps/demo-vue/jsconfig.json new file mode 100644 index 0000000..c904a96 --- /dev/null +++ b/apps/demo-vue/jsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "baseUrl": "./", + "paths": { + "~/*": ["app/*"], + "@/*": ["app/*"] + } + }, + "include": ["app/**/*"] +} diff --git a/apps/demo-vue/nativescript.config.ts b/apps/demo-vue/nativescript.config.ts new file mode 100644 index 0000000..8964bec --- /dev/null +++ b/apps/demo-vue/nativescript.config.ts @@ -0,0 +1,11 @@ +import { NativeScriptConfig } from '@nativescript/core'; + +export default { + id: 'org.nativescript.demovue', + appPath: 'app', + appResourcesPath: 'App_Resources', + android: { + v8Flags: '--expose_gc', + markingMode: 'none' + } +} as NativeScriptConfig; \ No newline at end of file diff --git a/apps/demo-vue/package.json b/apps/demo-vue/package.json new file mode 100644 index 0000000..502b266 --- /dev/null +++ b/apps/demo-vue/package.json @@ -0,0 +1,18 @@ +{ + "name": "demo-vue", + "main": "app/app.js", + "version": "1.0.0", + "private": true, + "dependencies": { + "@finalsite/rich-text-editor": "file:../../dist/packages/rich-text-editor", + "@nativescript/core": "~8.3.0", + "@nativescript/theme": "~3.0.2", + "@nota/nativescript-webview-ext": "^8.0.2", + "nativescript-vue": "~2.9.0" + }, + "devDependencies": { + "@nativescript/ios": "8.3.3", + "@nativescript/webpack": "~5.0.6", + "nativescript-vue-template-compiler": "~2.9.0" + } +} diff --git a/apps/demo-vue/webpack.config.js b/apps/demo-vue/webpack.config.js new file mode 100644 index 0000000..a561e0e --- /dev/null +++ b/apps/demo-vue/webpack.config.js @@ -0,0 +1,12 @@ +const webpack = require("@nativescript/webpack"); + +module.exports = (env) => { + webpack.init(env); + + // Learn how to customize: + // https://docs.nativescript.org/webpack + + return webpack.resolveConfig(); +}; + + diff --git a/apps/demo/package.json b/apps/demo/package.json index 5b02c8d..4f5aa59 100644 --- a/apps/demo/package.json +++ b/apps/demo/package.json @@ -10,7 +10,7 @@ }, "devDependencies": { "@nativescript/android": "7.0.1", - "@nativescript/ios": "7.2.0", + "@nativescript/ios": "^8.3.3", "@nativescript/webpack": "~4.1.0", "typescript": "~4.0.0" } diff --git a/packages/rich-text-editor/README.md b/packages/rich-text-editor/README.md index c889253..1377bc6 100644 --- a/packages/rich-text-editor/README.md +++ b/packages/rich-text-editor/README.md @@ -59,11 +59,88 @@ And include the css file _Important_ In order for the toolbar to display correctly you must use a GridLayout or RootLayout as your root layout +In your component's component file, initialize your editor's html: + +``` +editorContent: string = '

leonardo

Leonardo

; +``` + +_Ensure that there your app is wrapped in a GridLayout. See demo for an example_ +Include the xmlns: + +``` +xmlns:RIE="@finalsite/rich-text-editor" +``` + +Then, include the text editor & editor's html in your component's html file: + +``` + +``` + +#### Add Custom Toolbar Buttons + +``` + +