How to insert vue component into contenteditable div - vue.js

I want to create simple wysiwyg editor with vue. I have found only one real wysiwyg editor created on vue.js. Here it is __https://quasar.dev/vue-components/editor (But I didn't find there ability to insert image). Others vue wysiwyg editors is only wrappers to tinymce or ckeditor etc.
I am planning to create SIMPLE vue-editor using base commands from example from mozilla developer site. Here it is https://codepen.io/chrisdavidmills/pen/gzYjag .
At first I want to know how to insert vue components into contenteditable div. What I mean? For example, I want to create editor plugin which will insert image on toolbar icon click. Inserted image should be with attached events (click event), it could be resizable etc. The base idea to this I found in answer here https://stackoverflow.com/a/59326255/1581741 , (author #AJT82 ). He gave me example of inserting vue-component (image) into contenteditable div. Here it is https://codesandbox.io/s/vue-template-m1ypk .
So, I have next questions.
User open empty editor and insert component into it. I need something to store to database.
1) What exactly should I store to database?
2) Stored text with images should be rendered somewhere at the site as article for viewing only. This means I should have generated html (for example, <img src="" />). How I will take it from inserted vue-component?
3) User can edit stored earlier code from editor. How to insert (inserted and stored to database earlier) vue-component again?
I am lost in this questions.

I made you an example showing how you can inject absolutely anything into any WYSIWYG component (except for really bad ones :)
Using your first choice of WYSIWYG editor, and probably the slickest of them all...
https://quasar.dev/vue-components/editor
Here you can see how easy it is to inject a random cat image for example. You could pop up a dialog and ask for an image name, you could allow the user to upload an image, wait for a promise that returns the link, then insert that image via the returned link, or do even wilder things.
https://codepen.io/njsteele/pen/wvBNYJY
The component render is handled here:
<!-- Here is where we render the component and capture it's output... -->
<div ref="renderComponent" v-show="false">
<!-- Due to limitation of codepen, must not self-close -->
<component :is="renderThisComponent" v-bind="renderTheseProps">
</component>
</div>
Clicking "Insert Random Cat" will insert a random animated cat GIF from Cats As A Service.
Clicking Insert Quasar Components will let you select from a q-icon component, and an animated indeterminate progress circle. You can also add your own components. This works with absolutely any Vue component, but it will not update it once it's been rendered in your WYSIWYG editor, and it's plain HTML after that. I also used a ref render, which works but it's basic, to show you how easy it is to accomplish. I would instead upgrade this to a proxy component so it never has to get rendered into the DOM the first time or wait for a $nextTick.
You can also see you can inject tokens (although this came from the Quasar playground). It shows how you can inject vars you might have related to the current user/etc.
If you want, you can also allow users to build their own components, or allow user-created templates to be injected, you can also insert a Emoji list, or even #mentions, which can insert live-views into if that user is currently online, etc.
Since this functionality is both really powerful and easy to implement it in theory, I wrote a really ultra-tiny and bug-free template generator that you can extend to infinity (372 bytes). It's also safe for users, as it only uses function lists you pre-allow for your users.
Grab the source here and use it in your projects if you would like...
https://github.com/onexdata/nano-var-template

Related

Vuejs Hide/Show Elements refreshes when Routes change

I have been developing a Vue project and something caught my attention today. I used checkboxes with some sytling (I use them as toggle switches) throughout the project and thanks to these elements, I show or hide some elements and components. Toggle elements control specific data within each component. When the data istrue, some elements are displayed on the page and when false, they are hidden. What I noticed today is a little interesting. There is probably a simple solution, but although I have been searching the internet for a while, I haven't found a solution yet.
Here is the thing;
Let's say I am at the About page of my project. I used my toggle switches and now some of my elements and some sub components are displaying in the About.vue. Then I go and visit my Services.vue page and showing and hiding some elements and sub components as well. By the way, almost all of these pages have forms and I save these forms to local storage. When I return to My About page from my Services page, I see that the elements I activated have been restored. In other words, each component welcomes me with its default state when it is returned from another component. What I want to see is, If I go and check some checkboxes to show some element, No matter how long I roam between other routes, I want those elements to remain visible or hidden when I come back. For example, a toggle element must be activated to write a username and password on a component. After activating the toggle element, the user types the username and password and clicks the Save button. Then he continues to browse many areas of the project and when he returns, he sees that the toggle element is inactive and the username and password are not entered. I don't want it to be that way. How do I fix this?
you can use vuex for solved this problem.
https://vuex.vuejs.org/
Vuex is a state management pattern + library for Vue.js applications. It serves as a centralized store for all the components in an application, with rules ensuring that the state can only be mutated in a predictable fashion. It also integrates with Vue's official devtools extension (opens new window)to provide advanced features such as zero-config time-travel debugging and state snapshot export / import.

How to update slider values?

I'd like to update valuemax value on a slider that people can only choose a value from 1 to 3, not to 5 like it is now. I have 'inspect the element' on the page, and got something like this:
<div dojoattachpoint="sliderHandle,focusNode" class="dijitSliderImageHandle dijitSliderImageHandleH" dojoattachevent="onmousedown:_onHandleClick" wairole="slider" valuemin="1" valuemax="5" role="slider" aria-valuenow="3" tabindex="0" aria-labelledby="years_label" aria-valuemin="1" aria-valuemax="5" style="position: absolute;"></div>
I'm trying to find file/place on where that value can be updated in the code, however I'm not able to figure it out.
Assuming you have access to the source code for this application, change the javascript code that creates this slider widget.
You're looking at the DOM for the page in your example. You can use the minimum and maximum properties, which translates to some of the values you see in the DOM. See the Dojo dijit/form/Slider documentation (takes you to 1.6 since it looks like you're using an older version of dojo because of the use of dojoattachpoint, those names changed in later versions of Dojo).
If you're not sure what class or widget this is in the source, look for the id element further up in the dom. Often that will have the package and class name as part of the id. Looking at the developer tools to see what files were loaded on the networking tab might give you a clue, if the application hasn't gone through any customer build or packaging to optimize it.

Binding some Vue code to existing, server-side generated HTML

I have an old-style, multiple-page website, with a multiple steps checkout process. This all works with JS disabled, and it is critical that it keeps doing so.
The checkout form has no JS at all, at the moment, and I'd like to improve it progressively (eg. dynamically showing or hiding fields, doing live validation, etc...).
I have already wrapped the entire website with an #app div, and I mounted a Vue instance to it. Then I created a few components which work correctly (but are not critical, so if JS is disabled then the whole thing keeps working and the components are just empty).
Now I have a long checkout form which is generated server-side (say: <form id='address-form'>).
The best course would be to put it into a component (say <checkout-form>) and use it. I can't do this, because 1) the form is generated server-side 2) it needs to work without JS.
Ideally, I would love to create a component with no template, and attach it to the existing HTML.
Is this even possible?
Edit: continuing to dig the Internet, I found this tutorial. This is exactly my problem, but if this is the only way to do it, then I will revert to JQuery :) Manually duplicating the entire HTML (one server side, the other in Vue) is definitely not a good idea.

Is there a recommended way to have all the HTML pre-loaded for SEO purposes while using VueJS, without using SSR?

As the title implies, I need solid SEO and thus I need to have all the HTML loaded on my site on initial load. However, because the backend is written in PHP, and because it would be more work to write my Vue components with the server in mind, I don't want to use server-side rendering (SSR).
That leaves me with the option to send HTML over the wire, the "old school" way. What I am thinking of doing is writing each page's HTML like normal, but make one of the root html elements a Vue element in order to "upgrade" it. So the initial load downloads the finalized HTML, with all the data (tables, lists, etc already populated), but then after all the scripts are loaded, javascript can take over to make things easier and give a better UI experience. This poses a few questions, however:
Am I limited to a single component, the root? It'd be nice to still have many sub-components that would each have their own state. Perhaps inline templates can be used somehow?
Vue templates have their own templating system, like the mustache braces for displaying variables {{ myVar }}. Will I not be able to use them? The one way I can think of is to create a Vue template (that can be loaded from an external script) that is identical to the part of the HTML that it "takes over". The downside is that I'd have to maintain that component both in the original HTML and in the vue template.
Are there any good examples of what I'm trying to accomplish here?
Edit: I want to clarify that I'm aware I can put in various components here and there throughout the page. This still poses the question of how to make those components already start out rendered. Better yet would be to turn the whole page into Vue, much like an SPA.
I need solid SEO and thus I need to have all the HTML loaded on my site on initial load.
This is not entirely true. Google (80% of search traffic) easily parses SPAs now, so SSR purely for SEO isn't required anymore.
But to answer your question in general, you should check out Laracast's Vue.js series. They go in-depth on how to use PHP with Vue.js (including templating and variables).
I'd ask what it is you want to achieve with Javascript/Vue.js in your page. If everything is already rendered in PHP, does Vue provide a simple UX enhancement or takes over most of the page's heavy lifting (navigation, etc.)? If you have no reactive data and want Vue to simply be a controller for rendered components, then knock yourself out, although it might be approaching an 'overkill' scenario.
Have you looked into Prerender SPA Plugin ( https://github.com/chrisvfritz/prerender-spa-plugin )?
It is offered in the Vue documentation as a viable alternative to server side rendering ( https://v2.vuejs.org/v2/guide/ssr.html#SSR-vs-Prerendering )
Recently I've developed a multi-page application using Vue, here is how i tried to solve the SEO (Maybe this can help you ):
Htmls of header and footer (and other main common components) are packed to the page.html(eg: home.html, search.html).
Script and style are of header and footer imported in page.js(eg: home.js, search.js).
Add div.seo-zone to page.html's div#app, which includes the main SEO data(using some h1,h2,p,div and so on), and add
.seo-zone {
display: none;
}
in your css.
4. Make sure your app's root component's el is '#app'(each page's main content can be a Vue app).
Develop your app as usual.
After Vue rendered, the div.seo-zone will be replaced with your Vue components (although it can not be seen)

Aurelia popover checkbox checked.bind not reflecting on the view model

We have implemented checkbox in popover. There we are using checked.bind , but in the view model its not reflecting its value on change of the checkboxes.
Sample Gist Run Provided below:
Gist Run
Thanks in Advance
Programmatically injected HTML needs to be compiled manually
The integration with bootstrap I provided to you earlier cannot do this. The bootstrap plugin assigns the innerHTML property of the popover and it does this outside of aurelia's rendering pipeline. The HTML is therefore not compiled by aurelia, which is why bindings (and other aurelia behaviors) will not work.
The templating framework takes care of this for you automatically as long as you are following conventions (such as custom elements). In any other case you'll need to manually work with the ViewCompiler.
In case you're interested, you can see an example with programmatically generated HTML in this gist. Also see this question if you want to know more about it. I do not recommend it in this scenario however.
Use aurelia-dialog
A tooltip (or popover) is just that: a tip on how to use the tool. It should not need more than some plain markup, text and styling (of course this is subjective to some degree, and some people may disagree)
For collecting user input in-between pages or screens, I'd argue a modal dialog is a better fit because of its property to "pop out" more and to de-emphasize the rest of the screen until the user either proceeds or cancels.
More importantly, by using aurelia-dialog your bindings and behaviors will simply work because, well, it's an aurelia plugin :-)