Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consider allowing multiple editors on the same page & to use the same toolbar. #633

Open
u12206050 opened this issue Apr 20, 2016 · 58 comments
Labels

Comments

@u12206050
Copy link

When having more than one editor on a page, each one currently seems to require their own toolbar. If I try to assign a previously assigned toolbar then the events don't work for the second editor.

Steps for Reproduction

  1. Create one toolbar
  2. Create two editors
  3. Assign both editors the same toolbar.

Expected behavior: Would be easy enough to simply keep track of which editor was last active and apply and changes to that editor eg. Changing font size etc.

Actual behavior: The tool bar seems broken as soon as the second editor is attached to it. Only the second editor is actually usable, because when trying to type in the first one, the cursor jumps to the second one.

@jhchen
Copy link
Member

jhchen commented Nov 3, 2016

What is the use case for this? And why is that use case not solved with just hiding the respective toolbar and require there be one and only one toolbar?

@m1kelynn
Copy link

This is something that I am looking for also.

I am trying to incorporate Quill into a webpage builder. I'm hoping to have Quill handle the content and have another way to control the background images of the sections. Ideally the toolbar would be attached to the top and not connected to the editable areas. Maybe there's another way to do this?

quill-edit

@Thileepan
Copy link

@m1kelynn Did you managed to solve the issue with multiple editors with single toolbar in your case? Eager to know if something you could share.

@dkirchhof
Copy link

Hello,
I got a similar use case and managed it by implementing my own toolbar.
When the editor content / cursor changes, it will get the current formattings.

this.quill.on("editor-change", (eventName, ...args) =>
{
	if(this.quill.getSelection())
	{
		this.currentFormats = this.quill.getFormat();
	}
});

The toolbar buttons will call a format function.

format(format, params)
{
	if(this.currentFormats[format] && (!params || this.currentFormats[format] == params))
	{
		this.quill.format(format, false, Quill.sources.USER);
	}
	else
	{
		this.quill.format(format, params, Quill.sources.USER)
	}
}

Then I bind the style of the toolbar button to the currentFormats variable.

@TheWizz
Copy link

TheWizz commented Jun 11, 2017

@mrgrimmig, I have a hard time following what you did to solve this problem. I need to do something similar, and would really appreciate some clarification or a workinf code example, if possible.

Thanks!

-JM

@dkirchhof
Copy link

Sorry for my weird response.
Actually i'm using polymer and bind current formats to the toolbar to update the buttons autmatically, but i've made a small example without any dependencies to clarify my answer.

<!DOCTYPE html>
<html>
<head>
    <script src="https://cdn.quilljs.com/1.2.6/quill.js"></script>
    <link href="https://cdn.quilljs.com/1.2.6/quill.snow.css" rel="stylesheet">

    <style>

        .active {
            background: green;
        }

    </style>
</head>
<body>
    
    <button id="bold" onclick="onBoldClick()">Bold</button>

    <div id="editor1">
        <p>Hello World!</p>
        <p>Some initial <strong>bold</strong> text</p>
        <p><br></p>
    </div>

    <div id="editor2">
        <p>Hello World!</p>
        <p>Some initial <strong>bold</strong> text</p>
        <p><br></p>
    </div>
    
    <script>

        var currentEditor; // selected / focused editor
        var currentFormats; // save the current formattings

        createEditor("#editor1");
        createEditor("#editor2");

        function createEditor(selector)
        {
            let quill = new Quill(selector, { });
            
            quill.on("editor-change", (eventName, ...args) =>
            {
                currentEditor = quill;
                updateButtons();
            });
        }

        // get current formattings to style the toolbar buttons
        function updateButtons()
        {
            if(currentEditor.getSelection())
            {
                currentFormats = currentEditor.getFormat();

                if(currentFormats.bold)
                {
                    bold.classList.add("active");
                }
                else
                {
                    bold.classList.remove("active");
                }
            }
        }

        // if selected text is bold => unbold it - if it isn't => bold it
        function onBoldClick()
        {
            if(!currentFormats || !currentEditor)
            {
                return;
            }

            if(currentFormats.bold)
            {
                currentEditor.format("bold", false);
            }
            else
            {
                currentEditor.format("bold", true);                
            }
        }
        
    </script>

</body>
</html>

@benjismith
Copy link

benjismith commented Jul 20, 2017

I'd love to talk about my use-case here as well...

I'm using Quill as the text-editing component of a word-processor, which may have multiple documents onscreen at the same time. But all the instances should share the same toolbar. For example, here's a screenshot containing three Quill instances, one for the main document, and two containing margin comments:

Shaxpir Screenshot

Whenever the user clicks from one editor to another, the toolbar should update itself to reflect the active/enabled/disabled status of each button. And any toolbar clicks should be directed to the currently-focused editor instance.

Although some of the toolbar buttons correspond with Quill formatting functions, there are other toolbar buttons for non-Quill functionality, and those should continue to be enabled even when there are no active Quill editors onscreen at all.

Right now, I'm implementing my own toolbar, completely separate from Quill, and managing the active/enabled/disabled state of all the toolbar buttons myself. But it's pretty ugly, and I'd love to help Quill address this use case a little better.

Thank you for an incredible open-source project! I appreciate all your hard work.

@jhchen
Copy link
Member

jhchen commented Aug 28, 2017

Sounds like there is sufficient demand for this feature. Can someone propose an API that would fit solve their needs? Short code snippets using the API and high level descriptions of what they do and don't do would be helpful.

@TheWizz
Copy link

TheWizz commented Aug 28, 2017

Perhaps some inspiration could be taken from the TextAngular editor, which has this feature.

https://github.com/textAngular/textAngular

See specifically "a toolbar can be linked to multiple editors" in the accompanying wiki:

https://github.com/textAngular/textAngular/wiki/Customising-The-Toolbar

-JM

@benjismith
Copy link

benjismith commented Sep 4, 2017

I don't think we need to change the API very much. The only things I really need are:

  1. The ability to attach and detach Quill from additional DOM containers.
  2. The ability to retrieve an editor instance by DOM selector.
  3. New events for editor attachment and detachment, as well as focus and unfocus between editor instances.

Here's a quick example of creating the root Quill object, registering event handlers, attaching a few editors, selecting them for focus, and detaching from them again.

    let quill = new Quill({ toolbar : "#toolbar" });

    quill.on('editor-attach', function(e) { console.log("attached to:" + e.getEditorId());
    quill.on('editor-detach', function(e) { console.log("detached from:" + e.getEditorId());
    quill.on('editor-focus', function(e) { console.log("focused:" + e.getEditorId());
    quill.on('editor-unfocus', function(e) { console.log("unfocused:" + e.getEditorId());

    quill.attach('#editor-a');
    quill.attach('#editor-b');

    var editorA = quill.getEditorInstance('#editor-a");
    editorA.focus();

    var editorB = quill.getEditorInstance('#editor-b");
    editorB.focus();

    quill.detach('#editor-b');
    quill.detach('#editor-a');

The current Quill constructor, which accepts an editor ID...

    let quill = new Quill("#editor", { toolbar : "#toolbar" });

...could continue to be supported, as a shorthand for the more verbose version:

    let quill = new Quill({ toolbar : "#toolbar" });
    quill.attach("#editor");

It might also be nice to declare which toolbar buttons are enabled and disabled for each editor instance, possibly with something like this:

    let quill = new Quill({ toolbar : "#toolbar" });
    quill.attach("#editor", { enabled : [ "#button-bold", "#button-italic" ] });

However, I'd also be happy to add the enable/disable logic to my own event-handler code for the focus and unfocus events.

@jhchen
Copy link
Member

jhchen commented Sep 6, 2017

To be clear you are proposing that let quill = new Quill({ toolbar : "#toolbar" }); would not create a Quill editor and instead create an editor-less toolbar?

Quill.find is already an API method (though currently experimental) by the way.

@benjismith
Copy link

Yep, that's what I'm suggesting!

Maybe most users will typically include an editor selector in the constructor let quill = new Quill("#editor", { toolbar : "#toolbar" }); but I think it would be very handy to startup Quill without an editor.

In my application, the toolbar is always present from startup onward, even before the user creates their first document. As soon as they create a new document, or navigate into their existing content, I create new Quill editors and manually update the toolbar based on the selection and formatting state within that editor.

In my ideal scenario, calling let quill = new Quill({ toolbar : "#toolbar" }); essentially just creates an editor factory, configured with a particular Parchment schema.

@jhchen
Copy link
Member

jhchen commented Sep 11, 2017

Hmm the thing is Quill is the editor with optional modules, one of which is the toolbar. So new Quill not making an editor would be a dramatic departure.

@benjismith
Copy link

I totally understand, and I'm 100% open to other designs. The one I suggested just seems the most natural to me, as a user. But I'd love to see other proposals too!

@fmpenz
Copy link

fmpenz commented Oct 15, 2017

Would it be possible to make multiple editors work if created with the same toolbar?

`var quill1 = new Quill('#editor1', {
modules: { toolbar: '#toolbar' },
theme: 'snow'
});

var quill2 = new Quill('#editor2', {
modules: { toolbar: '#toolbar' },
theme: 'snow'
});`

@jhchen
Copy link
Member

jhchen commented Oct 16, 2017

If you click a button in the toolbar what editor would it modify? Both?

@fmpenz
Copy link

fmpenz commented Oct 16, 2017

If you click a button in the toolbar only the editor which lastly had focus should be modified.
The Shared Toolbar feature in CKE shows how it could be done.

@TheWizz
Copy link

TheWizz commented Nov 15, 2017

Has there been any progress on this feature? I would really like to switch to Quill from what I'm using today (TextAngular). Anything I can do to help out moving this forward?

-JM

@sconix
Copy link

sconix commented Nov 15, 2017

We would love to see this feature as well. For now I have made an Angular wrapper library (ngx-quill-wrapper) that allows this, but the way it handles it is bit hacky and definitely not optimal.

@TheWizz
Copy link

TheWizz commented Nov 15, 2017

I'm usinbn AngularJS, so unfortunately I can't use your wrapper. But I think the idea of separating the toolbar from the editor (at least as an option) is well thought out. Hopefully, we'll see this as part of Quill itself in a not-too-distant future, since this is really something that ought to be done independently of any specific framework wrapper.

@jhchen
Copy link
Member

jhchen commented Nov 20, 2017

I don't believe anyone is working on it and I probably will not get to it as there are other higher priority items at the moment. If someone with this use case wants to take it on please do. I am happy to give feedback on specific proposals but do not have the bandwidth to give general guidance for those new to Quill.

@umairrazzaq
Copy link

Hello guys, hope this message everyone fine.

Good topic/issue to cover here. I've implement and managed to add some buttons in toolbar by manual way which are functional as it should be, but I'm still facing some issues like Color, Font Size & Font Family etc.

Demo link: Codepen

Now what i need is to make Color, Font Size & Font Family button functional. Please review and suggest me. Thanks

@PawelGlow
Copy link

Would love to see this feature as well. At the moment I have to create a toolbar for every Quill editor as trying to use a single toolbar leaves the previous editor toolbar event handlers attached. After hours of trying to "hack it out", I finally created an editor + toolbar for every area I wanted to allow editing.

I was also wondering if I can use the addContainer API method, but the docs are not specific enough for me to quickly understand what it does.

Overall, Quill is amazing btw :)

@PawelGlow
Copy link

I see this topic has not moved, too bad. Any example on how to use the addContainer API method?

@Onouriis
Copy link

Onouriis commented Jun 29, 2019

Ok, so I encountered the same issue with this solution:
addRange(): The given range isn't in document.
When I create the new editor, the previous is already destroyed but it seems listeners still continue to work and I cannot use the new editor with the global toolbar.

@PawelGlow
Copy link

@Onouriis It's difficult to help without a code snipped. Do you clear your HTML and reset it?

// clean DOM and set content
document.getElementById('previousBoxId').classList.remove('ql-container');
document.getElementById('previousBoxId').innerHTML = content;

@Onouriis
Copy link

@PawelGlow I founded a nasty solution.
My toolbar was not destroy between each editor I create. So, listeners are applied on the toolbar each time I create a new editor.
My solution is to destroy the toolbar when editor is destroy and recreate the toolbar immediately.
I think it's not the best solution but I don't know how to remove all listeners without destroy the toolbar.

@PawelGlow
Copy link

@Onouriis Yes, that's correct. You need to destroy the toolbar HTML to remove the event listeners. I was also not able to find a better solution in the Quill docs but I have a very large app which handles 50+ toolbars and destroying the toolbar then creating a new one each time I create a new Quill instance has not caused any issues.

@Onouriis
Copy link

@PawelGlow Thanks for your help and your advices.

@Yexan
Copy link

Yexan commented Dec 2, 2019

Hi,

I'm using ngx-quill, an Angular 2+ wrapper for Quill and I'm facing an issue trying to "refresh" the content of the toolbar dynamically.

Here is a link of the issue with a couple of exemples : KillerCodeMonkey/ngx-quill#662

To give you a bit more of a context, I've many different editable zones on my interface and to avoid to create a lot of Quill instances I've many "display only" zones and when I click on one of them I display a Quill editor at the same place as the display zone.
With this trick everything works really fine and is pretty lightweight.

But, the thing is that those zones can have different configuration options, which mean a different toolbar content.
The issue is that when you declare a Quill instance with a custom toolbar, it needs to be already rendered in the DOM and I can't find a way to re-render the content of the toolbar dynamically.
And this is a serious issue because when a custom toolbar is created, select elements are replaced by custom elements span.ql-picker and some ql-picker-options.

I would like to know if there is a way to trigger the "re-templating" of the toolbar content.

@bbottema
Copy link

This is also my exact use case. Is there any hope on getting this feature any time soon? I'm also leveraging Quill through ngx-quill btw.

@Yexan
Copy link

Yexan commented Dec 31, 2019

Hi @bbottema,
I'm not sure they will ever implement this sadly 😞
Have you had a look at the issue I mentioned on ngx-quill repo, I've send a couple of exemples in stackblitz.
If you want the same config between editable zone (same fonts / fonnt sizes allowed, ...) you can trick the thing by using some quill view to display your zones and one instance of quill-editor that you will hide an show on click on a display zone.
But if you need different configs between zones, it will be like hell to refresh the toolbar.
I'll put back the issue here, feel free to ask.
Cheers

@minzojian
Copy link

minzojian commented Feb 10, 2020

I don't think we need to change the API very much. The only things I really need are:

  1. The ability to attach and detach Quill from additional DOM containers.
  2. The ability to retrieve an editor instance by DOM selector.
  3. New events for editor attachment and detachment, as well as focus and unfocus between editor instances.

Here's a quick example of creating the root Quill object, registering event handlers, attaching a few editors, selecting them for focus, and detaching from them again.

    let quill = new Quill({ toolbar : "#toolbar" });

    quill.on('editor-attach', function(e) { console.log("attached to:" + e.getEditorId());
    quill.on('editor-detach', function(e) { console.log("detached from:" + e.getEditorId());
    quill.on('editor-focus', function(e) { console.log("focused:" + e.getEditorId());
    quill.on('editor-unfocus', function(e) { console.log("unfocused:" + e.getEditorId());

    quill.attach('#editor-a');
    quill.attach('#editor-b');

    var editorA = quill.getEditorInstance('#editor-a");
    editorA.focus();

    var editorB = quill.getEditorInstance('#editor-b");
    editorB.focus();

    quill.detach('#editor-b');
    quill.detach('#editor-a');

The current Quill constructor, which accepts an editor ID...

    let quill = new Quill("#editor", { toolbar : "#toolbar" });

...could continue to be supported, as a shorthand for the more verbose version:

    let quill = new Quill({ toolbar : "#toolbar" });
    quill.attach("#editor");

It might also be nice to declare which toolbar buttons are enabled and disabled for each editor instance, possibly with something like this:

    let quill = new Quill({ toolbar : "#toolbar" });
    quill.attach("#editor", { enabled : [ "#button-bold", "#button-italic" ] });

However, I'd also be happy to add the enable/disable logic to my own event-handler code for the focus and unfocus events.

@benjismith @jhchen
i totally agree with this proposal.
in my case,i have lots of small textbox in the page that need to be edited(consider it is a design application like Canva.com did), i don't wanna make a mass of Quill instances one by one (thinking that would be a waste of memory), but use the same (only one) instance ATTACH to the textbox which is focused.
by the way, looks Canva.com is just using Quill to deal with the textbox editing, i found they are using 'Quill Editor v2.0.0-dev.18',
is there any new features in v2 to support dynamic attach?
PS, the newest version in Github is v2.0.0-dev.03 what the heck about v2.0.0-dev.18

@minzojian
Copy link

i found @Yexan give a hack way to archive.
i was thinking the same way, it could be a feasible solution so far.

https://stackblitz.com/edit/ng-quill-editor?file=src/app/app.component.ts

@Yexan
Copy link

Yexan commented Feb 10, 2020

@minzojian Yes if you have the same config between your zones it's doable.
If you need different configs between zones with the same toolbar it won't be a piece of cake.
Or at least I didn't see how to do it for now, if someone achieve it feel free to tag me 😊

@markgarbers
Copy link

@PawelGlow thanks for your suggestion... I came to the same conclusion after going through the same process as you. Worked a treat and much more efficient than running multiple Quill editors at the same time.

@itz-vivekpawar
Copy link

I have three editors in My Webpage

Here my Js File

`!function(o){"use strict";

var e=Quill.import("formats/font");

e.whitelist=["sofia","slabo","roboto","inconsolata","ubuntu"],

Quill.register(e,!0);

new Quill("#bubble-container .editor",{bounds:"#bubble-container .editor",modules:{formula:!0,syntax:!0},theme:"bubble"}),

new Quill("#snow-container .editor",{bounds:"#snow-container .editor",modules:{formula:!0,syntax:!0,toolbar:"#snow-container .quill-toolbar"},theme:"snow"}),

new Quill("#full-container .editor",{bounds:"#full-container .editor",modules:{formula:!0,syntax:!0,toolbar:[[{font:[]},{size:[]}],["bold","italic","underline","strike"],[{color:[]},{background:[]}],[{script:"super"},{script:"sub"}],[{header:"1"},{header:"2"},"blockquote","code-block"],[{list:"ordered"},{list:"bullet"},{indent:"-1"},{indent:"+1"}],["direction",{align:[]}],["link","image","video","formula"],["clean"]]},theme:"snow"});o("select[class^='ql-'], input[data-link]").addClass("browser-default")}((window,document,jQuery));`

@PawelGlow
Copy link

I have three editors in My Webpage

Here my Js File

`!function(o){"use strict";

var e=Quill.import("formats/font");

e.whitelist=["sofia","slabo","roboto","inconsolata","ubuntu"],

Quill.register(e,!0);

new Quill("#bubble-container .editor",{bounds:"#bubble-container .editor",modules:{formula:!0,syntax:!0},theme:"bubble"}),

new Quill("#snow-container .editor",{bounds:"#snow-container .editor",modules:{formula:!0,syntax:!0,toolbar:"#snow-container .quill-toolbar"},theme:"snow"}),

new Quill("#full-container .editor",{bounds:"#full-container .editor",modules:{formula:!0,syntax:!0,toolbar:[[{font:[]},{size:[]}],["bold","italic","underline","strike"],[{color:[]},{background:[]}],[{script:"super"},{script:"sub"}],[{header:"1"},{header:"2"},"blockquote","code-block"],[{list:"ordered"},{list:"bullet"},{indent:"-1"},{indent:"+1"}],["direction",{align:[]}],["link","image","video","formula"],["clean"]]},theme:"snow"});o("select[class^='ql-'], input[data-link]").addClass("browser-default")}((window,document,jQuery));`

What is the problem you are trying to solve? @itz-vivekpawar

@maxfahl
Copy link

maxfahl commented Oct 7, 2020

Hey guys!

I've created a sample React app to show how I resolved this issue. This is basically how it works:

I'm creating one instance of Quill, using a custom toolbar positioned at the top. The editor element is placed in a temporary, hidden, container. When the user double clicks any of the three text containers (Editables), the editor element will be transplanted form the temporary container to a new location inside the Editable. If a user hits the escape key, the Editable will be deactivated, moving the editor element back to the temporary container.

You can test it here: https://codesandbox.io/s/hungry-pine-o8oh9?file=/src/App.js
GitHub repo: https://github.com/maxfahl/Quill-Edit-Multiple

Feel free to use the code however you'd like.

@NervisWreck
Copy link

Hey guys!

I've created a sample React app to show how I resolved this issue. This is basically how it works:

I'm creating one instance of Quill, using a custom toolbar positioned at the top. The editor element is placed in a temporary, hidden, container. When the user double clicks any of the three text containers (Editables), the editor element will be transplanted form the temporary container to a new location inside the Editable. If a user hits the escape key, the Editable will be deactivated, moving the editor element back to the temporary container.

You can test it here: https://codesandbox.io/s/hungry-pine-o8oh9?file=/src/App.js
GitHub repo: https://github.com/maxfahl/Quill-Edit-Multiple

Feel free to use the code however you'd like.

I am not familiar with React and would like to achieve the same functionality with vanilla js, albeit without the need to double click. Any suggestions on how to do the same thing without React?

@maxfahl
Copy link

maxfahl commented Nov 26, 2020

I'm quite busy these days and will not be help you, sorry. My suggestion is that you take a look at the code, the basics of what I'm doing should be quite understandable if you're familiar with javascript.

@miczed
Copy link

miczed commented Jan 14, 2021

I went with the second option that Pawel proposed but did some slight adjustments. Every quill instance will create its own toolbar instance that will be added to a global toolbarContainer. Whenever a quill instance is selected / deselected, all the other toolbars within that global container are hidden and only the relevant one is displayed.

var toolbarOptions = [
  ['bold', 'italic', 'underline', 'strike'],        // toggled buttons
  ['blockquote', 'code-block'],

  [{ 'header': 1 }, { 'header': 2 }],               // custom button values
  [{ 'list': 'ordered'}, { 'list': 'bullet' }],
  [{ 'script': 'sub'}, { 'script': 'super' }],      // superscript/subscript
  [{ 'indent': '-1'}, { 'indent': '+1' }],          // outdent/indent
  [{ 'direction': 'rtl' }],                         // text direction

  [{ 'size': ['small', false, 'large', 'huge'] }],  // custom dropdown
  [{ 'header': [1, 2, 3, 4, 5, 6, false] }],

  [{ 'color': [] }, { 'background': [] }],          // dropdown with defaults from theme
  [{ 'font': [] }],
  [{ 'align': [] }],

  ['clean']                                         // remove formatting button
];

var quillOptions = {
  modules: {
    toolbar: toolbarOptions
  },
  theme: 'snow'
}

initQuill(document.querySelector('#editor'), document.querySelector('#toolbar'))
initQuill(document.querySelector('#editor2'),document.querySelector('#toolbar'))
initQuill(document.querySelector('#editor3'),document.querySelector('#toolbar'))
initQuill(document.querySelector('#editor4'),document.querySelector('#toolbar'))
initQuill(document.querySelector('#editor5'),document.querySelector('#toolbar'))
initQuill(document.querySelector('#editor6'),document.querySelector('#toolbar'))

function initQuill(element, globalToolbarContainer) {
  var quill = new Quill(element, quillOptions);
  quill.on('selection-change', (selection) => selectionChange(selection,quill));
  var toolbar = quill.getModule('toolbar');
  globalToolbarContainer.appendChild(toolbar.container)
  
  // search for existing toolbar and hide it
  prevToolbar = toolbar.container.previousElementSibling
  if (prevToolbar) {
    hideToolbar(prevToolbar)
  }
}


function selectionChange(selection,quill) {
  console.log("selection change",selection,quill)
  const toolbar = quill.getModule('toolbar')
  if(selection == null) {
    hideToolbar(toolbar.container)
    console.log('quill 1 lost focus')
  } else {
    showToolbar(toolbar.container)
  }
}

function hideToolbar(toolbarContainer) {
  toolbarContainer.classList.add('hidden')
}

function showToolbar(toolbarContainer) {
  // hide all other toolbars
  const siblings = getSiblings(toolbarContainer).map((elem) => elem.classList.add('hidden'))
  toolbarContainer.classList.remove('hidden')
}

function getSiblings(elem) {
	// Setup siblings array and get the first sibling
	var siblings = [];
	var sibling = elem.parentNode.firstChild;

	// Loop through each sibling and push to the array
	while (sibling) {
		if (sibling.nodeType === 1 && sibling !== elem) {
			siblings.push(sibling);
		}
		sibling = sibling.nextSibling
	}

	return siblings;
};

I created a codepen that demonstrates this solution. It seems to work quite well.

For my use case I will never have more than 5-7 quill instances at the same time so it shouldn't affect the performance that much.

@JGrimbert
Copy link

JGrimbert commented Jan 21, 2021

@Yexan @minzojian This solution dont respect the history (ctrl-z)

I did this :

        class ToolbarAlt extends Toolbar {
          resetToolbar () {
            this.container.childNodes.forEach(el => {
              const clone = el.cloneNode(true);
              el.parentNode.replaceChild(clone, el);
            });
            this.container.childNodes.forEach((input) => {
              this.attach(input);
            }, this);
          }
       }
       Quill.register('modules/toolbar', ToolbarAlt, true);

And then call it with the quill.getModule('toolbar').resetToolbar when focusin an editor.

It needs further ajustements but it seems not a bad way

@jsduffy
Copy link

jsduffy commented Feb 2, 2021

@JGrimbert could you provide a full example (like codesandbox or something) of this?

@Gnanavel76
Copy link

Gnanavel76 commented Jun 25, 2021

I found a another solution. But don't know whether it will be a efficient one.

So basically I am wrapping all the quill editors. Then I applied CSS property position:absolute to all the toolbar. Then through JavaScript I am getting the focused editor and making the corresponding toolbar visible and hiding all the remaining toolbar.

.editor-container{
  position: relative;
  padding-top: 50px;
}
.editor-container .ql-toolbar{
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  background: #fff;
}
.ql-container{
  border: 1px solid #000!important;
  margin-bottom: 1rem;
}
.d-none{
  display: none;
}
<div class="editor-container">
      <div id="editor" class="editor"></div>
      <div id="editor1" class="editor"></div>
</div>
let quill = new Quill("#editor", {
  theme: "snow",
});
let quill1 = new Quill("#editor1", {
  theme: "snow",
});

document.querySelectorAll(".editor .ql-editor").forEach((item)=>{
  item.addEventListener("click",(e)=>{
    // Getting the focused editor
    let selectedEditor = e.currentTarget.parentElement;
    let selectedEditorToolbar = selectedEditor.previousElementSibling;
    // Making the toolbar visible if already hidden.
    selectedEditorToolbar.classList.remove("d-none");
    // Hiding Toolbar of all non focused editor.
    document.querySelectorAll(".ql-toolbar").forEach((toolbar)=>{
      if(!toolbar.isEqualNode(selectedEditorToolbar)){
        toolbar.classList.add("d-none");
      }
    })
  })
})

@aghontpi
Copy link

aghontpi commented Sep 26, 2021

Woah, this is open for a long time now.

Can somebody pin the official solution to this?

@maxfahl
Copy link

maxfahl commented Sep 26, 2021

Don't think such a solution exists.

@maxfahl
Copy link

maxfahl commented Sep 26, 2021

I found a another solution. But don't know whether it will be a efficient one.
...

It's a nice solution, but you're using two toolbars instead of one for both editable areas. But if they're in the same container, it would still appear as one. Though it would be a hassle doing it this way with an unknown amount of editable areas that are all placed at diffent places.

@vishalvora
Copy link

vishalvora commented Apr 16, 2022

I have achieve the functionality with angular.

  1. I have created the editor class without toolbar
  2. I have created one common editor with toolbar and hide the text editor. This toolbar will be common for all editors.
  3. From main tool bar I have attached custom handler for all buttons.
  4. When any toolbar button clicked it will broadcast event to all editors with type of format and its value.
  5. In editor class event will be subscribed and when event received it will apply the formatting to selected text.

@TonyYu2015
Copy link

i have created a quill module about this issue, maybe it helps; https://github.com/TonyYu2015/quill-free-container

@asagaonkarsumit
Copy link

asagaonkarsumit commented Aug 10, 2022

`

<script src="https://cdn.quilljs.com/1.3.6/quill.js"></script> <title>Document</title>
Sans Serif Serif Monospace
    <span class="ql-formats">
      <select class="ql-size">
        <option value="small">Small</option>
        <option selected>Normal</option>
        <option value="large">Large</option>
      </select>
    </span>

    <span class="ql-formats">
      <select class="ql-color" title="Colour">
        <option value="rgb(255,0,0)" />
        <option value="rgb(0,255,0)" selected />
        <option value="rgb(0,0,255)" />
      </select>
    </span>

    <span class="ql-formats">
      <button class="ql-bold" id="bold">
        <span class="fa fa-bold"></span>
      </button>

      <button class="ql-italic" id="italic">
        <span class="fa fa-italic"></span>
      </button>
      <button class="ql-underline" id="underline">
        <span class="fa fa-underline"></span>
      </button>
      <button class="ql-strike" id="strike">
        <span class="fa fa-strikethrough"></span>
      </button>
    </span>

    <span class="ql-formats">
      <button class="ql-align-left" id="align-left">
        <span class="fa fa-align-left"></span>
      </button>
      <button class="ql-align-right" id="align-right">
        <span class="fa fa-align-right"></span>
      </button>
      <button class="ql-align-center" id="align-center">
        <span class="fa fa-align-center"></span>
      </button>
      <button class="ql-align-justify" id="align-justify">
        <span class="fa fa-align-justify"></span>
      </button>
    </span>

    <span class="ql-formats">
      <button type="button" class="ql-list" value="bullet">
        <span class="fa fa-list"></span>
      </button>
      <button type="button" class="ql-list" value="ordered">
        <span class="fa fa-list-ol"></span>
      </button>
    </span>

    <span class="ql-formats">
      <button type="button" class="ql-blockquote" value="blockquote">
        <span class="fa fa-quote-right"></span>
      </button>
    </span>
  </nav>
</div>

<br /><br />

<section class="row">
  <div class="col-md-6">
    <h2 class="h4 text-center">Editor #1</h2>
    <div id="editor1">
      <p>Hello World!</p>
      <p>Some initial <strong>bold</strong> text</p>
      <p>Some <em>lorem ipsum</em> text</p>
    </div>
  </div>
  <div class="col-md-6">
    <h2 class="h4 text-center">Editor #2</h2>
    <div id="editor2">
      <p>Hello World! 2</p>
      <p>Some initial <strong>bold</strong> text</p>
      <p>Some lorem ipsum text</p>
    </div>
  </div>
</section>

<section class="row mt-48">
  <div class="col-md-6">
    <h2 class="h4 text-center">Editor #3</h2>
    <div id="editor3">
      <p>Hello World! 3</p>
      <p>Some initial <strong>bold</strong> text</p>
      <p>Some <em>lorem ipsum</em> text</p>
    </div>
  </div>
  <div class="col-md-6">
    <h2 class="h4 text-center">Editor #4</h2>
    <div id="editor4">
      <p>Hello World! 4</p>
      <p>Some initial <strong>bold</strong> text</p>
      <p>Some lorem ipsum text</p>
    </div>
  </div>
</section>
<script>
  var currentEditor; // selected / focused editor
  var currentFormats; // save the current formattings
  var kk;

  createEditor("#editor1", "editor1toolbar");
  createEditor("#editor2", "editor2toolbar");
  createEditor("#editor3", "editor3toolbar");
  createEditor("#editor4", "editor4toolbar");

  function createEditor(selector, editor_div, ...args) {
    const para = document.createElement("div");
    para.innerHTML = document.getElementById("toltol").innerHTML;
    para.id = editor_div;
    para.classList.add("tt");

    document.getElementById("myDIV").appendChild(para);

    let quill = new Quill(selector, {
      modules: {
        toolbar: `#${editor_div}`,
      },
      theme: "snow",
    });

    quill.on("editor-change", () => {
      currentEditor = quill;

      [...document.getElementsByClassName("tt")].map((item) => {
        item.style.display = "none";
      });
      console.log("dd");
      document.getElementById(
        `${quill.root.parentElement.id}toolbar`
      ).style.display = "block";
    });
  }

  // get current formattings to style the toolbar buttons
  function updateButtons(TT) {
    if (TT.getSelection()) {
      currentFormats = TT.getFormat();

      //currentEditor.classList.add("active");
    }
  }
</script>
` dynamically created toolbar and hide the other toolbar and visible active tollbar

@Jayeshkarma
Copy link

Jayeshkarma commented Aug 3, 2023

it's working fine for my code example is here

https://codesandbox.io/embed/blazing-river-8s9vsl?fontsize=14&hidenavigation=1&theme=dark

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests