Need a way to toggle a class for a paragraph (block) with custom button - quill

I am trying to make a simple button that toggles a class on the selected paragraph. In this case for a spoiler function, that marks up the paragraph differently.
I haven't been able to find any straightforward answers to this. Is there really no simple way to do that?
Best I have come up with is using a ClassAttributor, but that seems to insist on using a prefix for the class which bugs me a little for semantic reasons.

You can extend the block blot and change the class name.
class Content extends Block {}
Content.blotName = 'content';
Content.tagName = 'div';
Content.className = 'hiii';
Quill.register(Content, true);
Check this jsFiddle:
https://jsfiddle.net/hassansalem/kmxzh3tn/2/
I hope it is what you are searching for. ✌️

Related

ExtJS ref to panel element with specific title

I am working on a project in ExtJS 4.2 written in the MVC pattern. I need a reference to a specific item inside MyViewport (extended from the class Ext.container.Viewport). The item which needs to be referenced from within the controller has the Class MyPanel (extended from "Ext.Panel"). Problem is there are several items with the same class, so simply doing a standart ExtJs-component-query like,
//inside myController.js
refs: [
...
{ref: 'specificItem', selector: 'MyViewport_alias > myPanel_alias'},
...
]
wont get me a reference to the item. Thats why i thought of retrieving the reference by something like this, since the items using MyPanel-class have a property title:
//inside myController.js
refs: [
...
{ref: 'specificItem',
selector: 'MyViewport_alias > myPanel_alias > title="title of specific item"'},
...
]
But i coulnd't find any examples on retrieving items as references by using their properties as parts of the component query other than this.
Has someone experience with this kind of problem?
Component queries in ExtJS are very similar to CSS query selectors. You could find a component by a specific property with syntax similar to: "... > [title=My Component Title]" - that said, using the "title" sounds like really bad practice.
At worst, as a visible part of the user-interface it's very sensitive to change - easily breaking your application and at best it immediately limits your application's language-support and configurability.
Ideally you should be utilising the itemId property as a more robust way of referencing components.
» fiddle
I hadn't noticed that 4.2 didn't support attribute selectors - the component query functionality seems to have always drawn inspiration from CSS though, so unfortunately if it's only a recent development it doesn't look like there's any way to do what you want using this method.
You'd have to manually fetch the component and/or create your own reference. You can select by xtype / alias in 4.2 and then apply a filter to the result, for example:
Ext.Array.filter(Ext.ComponentQuery.query('panel'), function(x){
return !!x.title.match('Sub Panel 2');
}).shift();
( Obviously no use in a controller's refs )
» fiddle
... this is however ugly - all the more reason to use itemId's properly. There was already an example of this in action in the first fiddle. All you need to do is assign an alphanumeric string (no spaces) to the property - these don't strictly need to be unique but it's generally preferable. Then in your selector simply prefix a hash # in front of the string which indicates to the engine that you are looking for a component with a specific ID.
itemId selectors definitely work in 4.2 so without seeing your code I can only speculate as to what the problem is. In your post you are using > which narrows the query to direct descendants only. Are you absolutely sure that the component you are looking for is a child of myPanel_alias and not wrapped up in another container? i.e.
"myPanel_alias #myItemId" <-- try this
"myPanel_alias > #myItemId" <-- instead of this

Can AngularJS ngClass expressions be nested?

I'm new to AngularJS and have been assigned a maintenance task on an app we've inherited (originally developed for us by a third-party).
At the left of a header row in a table is a small button showing either a plus (+) or minus (-) symbol to indicate whether it will expand or collapse the section when clicked. It does this using ngClass as follows.
ng-class="{false:'icon-plus',true:'icon-minus'}[day.expanded]"
I have to remove the button when there is no data in the section and thus no ability to expand. There is already a class (.plus-placeholder) for this and I was wondering if the expressions that ngClass uses can be nested to allow something like this
ng-class="{false:'plus-placeholder',true:{false:'icon-plus',true:'icon-minus'}[day.expanded]}[day.hasTrips]"
which would allow me to add a hasTrips property to day to accomplish the task.
If this is not possible I think I will need to add a property something like expandoState that returns strings 'collapsed', 'expanded' and 'empty'. so I can code the ngClass like this
ng-class="{'collapsed':'icon-plus','expanded':'icon-minus','empty':'plus-placeholder'}[day.expandoState]"
And perhaps this is a cleaner way to do it in any case. Any thoughts/suggestions? Should it be relevant, the app is using AngularJS v1.0.2.
You certainly can do either of the two options you have mentioned. The second is far preferable to the first in terms of readable code.
The expandoState property you mention should probably be a property or a method placed on the scope. Your attribute would then read something like
ng-class="{'collapsed':'icon-plus','expanded':'icon-minus','empty':'plus-placeholder'}[expandoState()]"
To put this method on the scope you would need to find the relevant controller. This will probably be wherever day is assigned to the scope. Just add
$scope.expandoState = function() {
// Return current state name, based on $scope.day
};
Alternatively, you could write a method on the controller like
$scope.buttonClass = function() {
// Return button class name, based on $scope.day
};
that just returns the class to use. This will let you write the logic from your first option in a much more readable fashion. Then you can use
ng-class="buttonClass()"

In backbone marionette is there a way to tell if a view is already shown in a region?

Given something like this:
View = Backbone.Marionette.ItemView.extend({ });
myView = new View();
//region already exists
myLayout.region.show(myView)
//some time later this gets called again:
myLayout.region.show(myView)
I can see currentView in the docs but this only seems to apply at initialisation. Once a view is shown can I query the region to see the view? Either the view instance or type would be helpful. Looking in Chrome's debugger I can't see any properties/methods on the region that would help.
The motive for wanting to do this is so I don't show a static item view in a region again if it is already displayed as this can (especially if images are involved) cause a slight flickering effect on the screen.
Thanks
--Justin Wyllie
you can add a condition before calling show method:
if (myLayout.region.currentView != myView)
myLayout.region.show(myView)
so if you'll try to call show with the same View it wont be shown.
if you want to call region.show(myView) once you can check in this way:
if (_.isUndefined(myLayout.region.currentView))
myLayout.region.show(myView)
You can check the isClosed and $el attributes of the view. Something like
if (myView.isClosed || _.isUndefined(myView.$el)) {
myLayout.region.show(myView);
}
This is the same way the region checks to see if the view is closed or not:
show: function(view) {
this.ensureEl();
var isViewClosed = view.isClosed || _.isUndefined(view.$el);
...
I'm going out on a limb here and assuming that the OP's question is based on app behavior when navigating to different parts of the app via an anchor tag in the navigation or something similar.
This is how I found the question and I thought briefly that the answers would save my day. Although both answers so far are correct they do not quite solve the problem I was having. I wanted to display a persistent navigation bar. However, I did not want it to display on the login page. I was hopeful that detecting if a Region was already shown or not I'd be able to properly let the display logic take care of this.
As it turns out we were both on the right track to implement Regions as this provides granular control, but even after implementing the above I found that my nav bar would still "flicker" and essentially completely reload itself.
The answer is actually a bit ridiculous. Somehow in all the Backbone tutorials and research I've been doing the last two weeks I never came across the need to implement a javascript interface to interrupt normal link behavior. Whenever a navigation item was clicked the entire app was reloading. The routing was functioning so the content was correct, but the flicker was maddening.
I added the following to my app.js file right after the Backbone.history.start({pushState: true}); code:
// Holy crap this is SOOO important!
$(document).on("click", "a[href^='/']", function(event) {
if (!event.altKey && !event.ctrlKey && !event.metaKey && !event.shiftKey) {
event.preventDefault();
var url = $(event.currentTarget).attr("href").replace(/^\//, "");
Backbone.history.navigate(url, { trigger: true });
}
});
Check out this article for some explanation about the keyPress detection stuff. http://dev.tenfarms.com/posts/proper-link-handling
Boom! After adding this stuff in my app no longer completely reloads!
Disclaimer: I am very new to Backbone and the fact that the above was such a revelation for me makes me think that I may be doing something wrong elsewhere and this behavior should already exist in Backbone. If I've made a giant error here please comment and help me correct it.

Marionette.js: Should regions replace instead of insert?

The default behavior of marionette.js is to append a template into the element specified by the regions selector. However, I usually end up having to create a special region type and override the appendHtml function to do a replace instead.
That is not too difficult, but why is append the default?
I usually will create the layout template with an empty div to specify where the region should go. Then I replace that div with sub template when I show it.
I guess am wondering if there I'm missing the design pattern for templates that makes append more intuitive.
Thanks for the help.
Update:
So I usually will have some view for something I want rendered into the page and will want to todd n element onto the page where I want it. I will do javascript that will look something like this:
ReplaceRegion = Marionette.Region.extend({
open: function(view){
this.$el.replaceWith(view.el);
}
});
App = new Backbone.Marionette.Application();
App.addRegions({
myRegion: {
selector: "#someRegion",
regionType: ReplaceRegion
}
};
var view = new CoolWidgetView();
App.myRegion.show(view);
And then somewhere in my html I'll throw an empty div in the mix where I want my template to show up.
<div id="mywidget"></div>
Now if it is the only child element, I can use a selector that would just be the parent, but that becomes more tricky when the view i'm inserting has siblings.
Also, I'm not really asking for a change to the default, as much as I'm wondering if there's a better way to insert items where you would like them in your layouts. I'm still relatively new to the layout and design of these things so anything helps!
Thanks Derick for writing great software!
Marionette regions provide both a show and a close method. Have you tried closing the region before you show the new one?
Marionette.Region docs

backbone.js: encapsulating view functions?

Pretty new to backbone.js so forgive me of my ignorance. I'm wondering, is there a way to encapsulate functions within the View class specifically?
I ask because when setting default events...
events {
'click .something' : 'doSomething'
}
... I'd prefer to have doSomething be nested in an encapsulating object for optimal organization. For example:
ui: {
doSomething: function() {}
}
But then I can't seem to get the default events to work.
events {
'click .something' : 'ui.doSomething' // this doesn't work
}
Any help is greatly appreciated. Or, if you can tell me why I shouldn't be doing this then I'd appreciate that, as well. Thanks!
Looking through the source that binds the events (delegateEvents) which is called from the constructor, it is pretty clear that it works on variables with in the scope of the object.
http://documentcloud.github.com/backbone/docs/backbone.html#section-118
You could, however, override delegateEvents to be a bit smarter... You could parse the value for dots and chain your tokens. You could even check the type of the value and use an actual function in place of the string. That might give you better control the way you want.
More info on the delegateEvents function: http://documentcloud.github.com/backbone/#View-delegateEvents

Resources