Ace editor is showing icons twice with autocomplete - reactjs

So I'm having an issue with Ace editor where certain autocompletions have doubled icons like so
I am creating a custom autocompleter like so:
const customCompleter = {
identifierRegexps: [/[a-zA-Z_0-9\.\$\-\u00A2-\uFFFF]/],
getCompletions: (
editor: Ace.Editor,
session: Ace.EditSession,
pos: Ace.Point,
prefix: string,
callback: Ace.CompleterCallback
): void => {
var completions: any[] = [];
completions.push({
value: "custom",
className: "iconable"
});
if (prefix == "custom.") {
RList = ["custom.Base64Decode",
"custom.AnotherMethod",
"custom.Method3",
"custom.TestingFunction"
];
RList.forEach(function (w) {
completions.push({
value: w,
className: "iconable"
});
});
}
callback(null, completions);
}
}
langTools.addCompleter(customCompleter);
So when I'm pushing to completions i add a className of "iconable". The CSS file then looks like this:
.ace_iconable:after {
font-family: "Font Awesome 5 Free";
content: "\f1b2";
display: inline-block;
padding-right: 10px;
padding-left: 10px;
vertical-align: middle;
font-weight: 900;
}
Not sure why this would be the case, but if anyone has run into this before please let me know!
Thanks

Looks like you can actually just change the css a touch.
You can use .ace_iconable:last-child:after and it will stop the icon being duplicated.
Looks like multiple spans are used when the autocomplete is picking up on a completion which starts halfway through a word. (E.g. User types "a", autocomplete suggests "bad")
This means that the icon would be displayed twice.

Related

Getting ClassList value of null when toggling mobile menu

I'm working on building a responsive mobile navigation menu, and ran into an error with toggling open/close
The way I decided to go about it is to add className="show" that has a property of display: block to what's currently active, and className="hide" with a property of display: none.
This is my set up:
import {MenuOpen, MenuClose} from '../assets/AssetsIndex';
function menuActive() {
let menu = document.getElementById('mobile-menu');
let menuOpen = document.getElementById('menu-open');
let menuClose = document.getElementById('menu-close');
menu.classList.contains('active') ? open() : close();
function close() {
menu.classList.add('active');
menuClose.classList.add('show');
menuOpen.classList.add('hide');
menu.style.transform = 'translateX(0%)';
}
function open() {
menu.classList.remove('active');
menuOpen.classList.add('show');
menuClose.classList.add('hide');
menu.style.transform = 'translateX(100%)';
}
}
Initializing the menu icon with the class name:
<MenuOpen className='menu show' onClick={menuActive} id='menu-resting' />
<MenuClose className='menu hide' onClick={menuActive} id='menu-open' />
Scss:
.menu {
cursor: pointer;
margin: 0 auto;
position: absolute;
right: 2%;
z-index: 100;
&:hover path {
fill: #fff;
}
path {
fill: #fff;
}
}
.show {
display: block;
}
.hide {
display: none;
}
Error:
I went about displaying the menu container in the same way, so I'm not sure why I can't do the same with an SVG element. I've tried adding the properties with JS but ran into the same issue of the property value is null.
If anyone can tell me what I'm doing wrong that would be greatly appreciated.
There is no element with id menu-close in your code. Probably a typo. Assuming id prop of the MenuClose component is the id of the underlying element you have menu-open there.
Also, I would suggest using state hook for controlling whether the Menu is open or closed.

how to replace 'selected text' => 'decorated text' in react / textarea? i can't get exact location(index) of 'selected text'

i'm trying to build some text editor with react
i'm not native in english, so sorry about below question
what i want to do is like this below
(it's 'notion' page gif)
if user drag text with mouse(or with keyboard) to set a block in some texts,
popup menu(to edit 'seleted texts') show
i'm stuck at first one.
i can get whole text and selected text
let wholeText = whole.anchorNode.childNodes[0].defaultValue;
let selectedText = window.getSelection().toString();
but i can't get 'exact location' of selectedText in wholeText
here's my code (react, styled-component)
import { useState, useEffect } from 'react';
import styled from 'styled-components';
import autosize from 'autosize';
export default function TextBox({ id, index, content, handleContentInput }) {
const [currentContent, setCurrentContent] = useState(content);
const [areaHeight, setAreaHeight] = useState(25);
useEffect(() => {
autosize(document.querySelector(`.TextBoxWrap_${id}`));
}, [currentContent]);
return (
<TextBoxContainer
className={`TextBoxContainer_${id}`}
areaHeight={areaHeight}
onClick={() => {
document.querySelector(`.TextBoxContainer_${id}`).focus();
}}
>
<TextBoxWrap
className={`TextBoxWrap_${id}`}
areaHeight={areaHeight}
onChange={(event) => {
setCurrentContent(event.target.value);
}}
onBlur={() => handleContentInput(id, index, currentContent)}
onKeyUp={() => {
let newHeight = document.querySelector(`.TextBoxWrap_${id}`)
.clientHeight;
setAreaHeight(newHeight);
}}
onMouseUp={() => {
let whole = window.getSelection();
if (!whole) return;
let range = whole.getRangeAt(0);
console.log({ whole, range });
let wholeText = whole.anchorNode.childNodes[0].defaultValue;
let selectedText = whole.toString();
console.log({ wholeText, selectedText });
let start = range.startOffset; // Start position
let end = range.endOffset; // End position
console.log({ start, end });
}}
value={currentContent}
></TextBoxWrap>
</TextBoxContainer>
);
}
const TextBoxContainer = styled.div`
max-width: 890px;
width: 100%;
height: ${(props) => `${props.areaHeight}px`};
border: 1px solid black;
margin: 3px;
padding: 2px;
`;
const TextBoxWrap = styled.textarea`
/* border: 1px solid black; */
box-sizing: 'border-box';
border: none;
outline: none;
width: 100%;
min-height: 20px;
height: 20px;
/* padding: 2x; */
box-shadow: none;
display: block;
overflow: hidden; // Removes scrollbar
resize: none;
font-size: 18px;
/* line-height: 1.5em; */
/* font-family: Georgia, 'Malgun Gothic', serif; */
`;
inside of onMouseUp, it works like this
console.log({ wholeText, selectedText }); : works fine
console.log({ start, end }); : always 0, 0
wholeText.indexOf(selectedText) was my option, but indexOf() gives me just 'first' index matches,
so, even if i want "aaaaaa'a'aa" but indexOf will give me '0' (=> "'a'aaaaaaaaaa")
what i was thinking,
get the 'exact index(location)', and cut wholeText with it
decorate selectedText with popup box (return html element? like <span style{{color: 'red'}}>${selectedText}
then, combine these three items (wholeText_front, decorated_selectedText, wholeText_back)
and, to place popup menu div right above seleted texts
which means, i need 'selected one's location
how can i do this? plz give me advice
thank you!
posts i read before post this question
How to find index of selected text in getSelection() using javascript?
How to get the start and end points of selection in text area?
replace selected text in contenteditable div
Replacing selected text - HTML / JavaScript
Select Text & highlight selection or get selection value (React)
i might have some solution for my question, so post this answer myself
in this question(How to get the start and end points of selection in text area?), 'Tim Down' answered with getInputSelection function.
getInputSelection needs el as parameter, and i thought this is some kind of 'html element'
so, from this question(get id of focused element using javascript
), i got a hint : document.activeElement
and, i tried getInputSelection(document.activeElement) and got an object like { start: (number), end: (number) }

Using Font Awesome in ui.bootstrap.rating

How can I use Font Awesome in ui.bootstrap.rating?
I found out, that when I add state-on="'fa-star'" state-off="'fa-star-o'" to and changed class="glyphicon" to class="fa" in ui-bootstrap-tpls it works.
But I guess there is a more custom way to change the class of the icons.
Yeah as you are doing with setting state-off and state-on is their recommended manner. If you are going to have lots of the ratings on a page, I would just create a custom template and over-ride the stock template. Here is a post custom templates
I had Font Awesome and so didnt want to include Glyphicons.
uib.bootstrap Version: 1.3.3 - 2016-05-22 uses limited Glyphicons, so this is what i added to my css
.glyphicon {
display: inline-block;
font: normal normal normal 14px/1 FontAwesome;
font-size: inherit;
text-rendering: auto;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.glyphicon-star:before {
content: "\f005";
}
/**
copied from
.fa-star:before {
content: "\f005";
}
*/
.glyphicon-star-empty::before {
content: "\f006";
}
.glyphicon-chevron-right:before {
content: "\f054";
}
.glyphicon-chevron-left:before {
content: "\f053";
}
.glyphicon-chevron-up:before {
content: "\f077";
}
.glyphicon-chevron-down:before {
content: "\f078";
}
i.e. added css from Font Awesome 4.6.3 to appropriate glyphicon names
Now i dont know if this code will break on version of Font Awesome

ExtJS: setDisabled(true) makes fields too dim / transparent to read

When I set a form field into the disabled state using setDisabled or the disabled: true config, for example:
form.getComponent(1).setDisabled(true);
it makes the field unreadable due to the transparency. Is there a good way to improve the look and feel of my disabled fields?
This Worked for me:)
.x-item-disabled {
filter : '' !important;
}
A quick solution is to change the opacity setting in the ext-all.css (or ext-all-debug.css) file. The default setting seems to be:
.x-item-disabled .x-form-trigger {
filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=30);
opacity: 0.3; }
If you change the opacity values to 0.6 you get a readable form.
Obviously not ideal as you are changing the core framework files but I certainly didn't find a quicker way to correct this.
I did something similar to y'all..
in ExtJS
{
xtype: 'combobox',
name: 'comboTest',
store: "ComboTest",
fieldLabel: "testCombo",
queryMode: "local",
displayField: "display",
valueField: "value",
disabledCls: "disabledComboTestCls" // you are now totally overriding the disabled class as set by .x-item-disabled
}
In you CSS file
.disabledComboTestCls {
-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";
filter: alpha(opacity=50);
-moz-opacity:0.5;
-khtml-opacity: 0.5;
opacity: 0.5;
}
.disabledComboTestCls input {
font-weight: bold;
color: #888888;
}
And this works well.
We use an override on Ext.form.Field, which hides the triggers etc, and then we add a css class. We then style the component, because the disabled function of ExtJS is indeed not readable enough.
Here is example code:
var originalRender = Ext.form.Field.prototype.onRender;
Ext.override(Ext.form.Field, {
UxReadOnly: false,
UxDisplayOnly: function (displayOnly, cls) {
// If no parameter, assume true
var displayOnly = (displayOnly === false) ? false : true;
if (displayOnly) {
// If a class name is passed in, use that, otherwise use the default one.
// The classes are defined in displayOnly.html for this example
var cls = (cls) ? cls : 'x-form-display-only-field';
// Add or remove the class
this.addClass(cls);
// Set the underlying DOM element's readOnly attribute
this.setReadOnly(displayOnly);
this.editable = false;
// Get this field's xtype (ie what kind of field is it?)
var xType = this.getXType();
if (xType == 'combo' | xType == 'combobox' | xType == 'Ext.ux.Combo' | xType == 'Ext.ux.ComboSearch') {
this.addClass('x-form-display-only-combo');
this.hideTrigger = true;
this.on('expand', function (field) {
if (field.hideTrigger)
field.collapse();
});
}
else if (xType == 'datefield') {
this.addClass('x-form-display-only-datefield');
this.hideTrigger = true;
this.on('expand', function () {
if (this.hideTrigger)
this.collapse();
});
this.editable = false;
} //elseif for each component u want readonly enabled
else {
this.addClass('x-form-display-only-other');
}
// For fields that have triggers (eg date,time,dateTime),
// show/hide the trigger
if (this.trigger) {
this.trigger.setDisplayed(!displayOnly);
}
} else {
this.UxFullField(cls);
}
},
afterRender: function () {
var me = this;
me.UxDisplayOnly(me.UxReadOnly, 'x-form-display-only-field');
this.callParent(arguments);
},
UxFullField: function (cls) {
// If a class name is passed in, use that, otherwise use the default one.
// The classes are defined in displayOnly.html for this example
var cls = (cls) ? cls : 'x-form-display-only-field';
this.removeCls(cls);
// Set the underlying DOM element's readOnly attribute
this.setReadOnly(false);
this.editable = true;
// Get this field's xtype (ie what kind of field is it?)
var xType = this.getXType();
if (xType == 'combo' | xType == 'combobox' | xType == 'Ext.ux.Combo' | xType == 'Ext.ux.ComboSearch') {
this.removeCls('x-form-display-only-combo');
this.setHideTrigger(false);
}
else if (xType == 'datefield') {
this.removeCls('x-form-display-only-datefield');
this.setHideTrigger(false);
this.editable = true;
}//elseif for each component u want readonly enabled
else {
this.removeCls('x-form-display-only-other');
}
// For fields that have triggers (eg date,time,dateTime),
// show/hide the trigger
if (this.trigger) {
this.setHideTrigger(false);
}
}
});
With css you hide stuff like borders etc...
.x-form-display-only-field{}
.x-form-display-only-other input, .x-form-display-only-other select { background: transparent !important; border: 1px solid transparent !important; cursor: pointer; cursor: default; font-weight: bold; background-image: none !important; background-color: transparent !important; }
.x-form-display-only-combo input, .x-form-display-only-combo select { background: transparent !important; border: 1px solid transparent !important; cursor: pointer; cursor: default; font-weight: bold; background-image: none !important; background-color: transparent !important; }
.x-form-display-only-datefield input, .x-form-display-only-datefield select { background: transparent !important; border: 1px solid transparent !important; cursor: pointer; cursor: default; font-weight: bold; background-image: none !important; background-color: transparent !important; }
.x-form-display-only-file input, .x-form-display-only-file select { background: transparent !important; border: 1px solid transparent !important; cursor: pointer; cursor: default; font-weight: bold; background-image: none !important; background-color: transparent !important; }
.x-form-display-only-checkbox { }
.x-form-display-only-radiogroup { }
Now you can add your field the following way:
Ext.create('Ext.form.field.Text', {
name: 'example',
UxReadOnly: true
});
For you Googlers, these answers are outdated if you're on Ext 5 and up. There's now a readOnly bool. The field looks exactly the same, but the value isn't editable.
documentation

Extjs checkcolumn disable for some rows, based on value

I have a grid, with checkcolumn. It's dataIndex is, for example, 'checked'.
I want to disable or hide checkboxes for some rows, where another value, 'can_be_checked' for example, is false/empty.
Renderer is already defined in checkcolumn, messing with it breaks generation of checkbox.
How can I do it?
You may hide the checkbox just inside the renderer, for example:
column.renderer = function(val, m, rec) {
if (rec.get('can_be_checked') == 'FALSE'))
return '';
else
return (new Ext.ux.CheckColumn()).renderer(val);
};
I was looking for a solution to this and came across this question, but no workable solution anywhere to show a disabled checkbox instead of NO checkbox as covered in the other answer. It was kind of involved but here's what I did (for 4.1.0):
I found that the extjs\examples\ux\css\CheckHeader.css file that
is used by Ext.ux.CheckColumn does not have a disabled class, so I
had to modify it to be more like the standard checkbox styling
contained in ext-all.css (which does include a disabled checkbox
class).
I had to extend Ext.ux.CheckColumn to prevent events being
fired from disabled checkboxes.
Finally, I had to provide my own renderer to apply the disabled
class according to my logic.
The code is as follows.
Modified CheckHeader.css:
.x-grid-cell-checkcolumn .x-grid-cell-inner {
padding-top: 4px;
padding-bottom: 2px;
line-height: 14px;
}
.x-grid-with-row-lines .x-grid-cell-checkcolumn .x-grid-cell-inner {
padding-top: 3px;
}
.x-grid-checkheader {
width: 13px;
height: 13px;
background-image: url('../images/checkbox.gif');
background-repeat: no-repeat;
background-color: transparent;
overflow: hidden;
padding: 0;
border: 0;
display: block;
margin: auto;
}
.x-grid-checkheader-checked {
background-position: 0 -13px;
}
.x-grid-checkheader-disabled {
background-position: -39px 0;
}
.x-grid-checkheader-checked-disabled {
background-position: -39px -13px;
}
.x-grid-checkheader-editor .x-form-cb-wrap {
text-align: center;
}
The background-image url above points to this image which normally ships with extjs 4.1.0 at: extjs\resources\themes\images\default\form\checkbox.gif.
The extended Ext.ux.CheckColumn class so that events will not get fired from disabled checkcolumns:
Ext.define('MyApp.ux.DisableCheckColumn', {
extend: 'Ext.ux.CheckColumn',
alias: 'widget.disablecheckcolumn',
/**
* Only process events for checkboxes that do not have a "disabled" class
*/
processEvent: function(type, view, cell, recordIndex, cellIndex, e) {
var enabled = Ext.query('[class*=disabled]', cell).length == 0,
me = this;
if (enabled) {
me.callParent(arguments);
}
},
});
Implementation with custom renderer to apply disabled class according to my own logic:
column = {
xtype: 'disablecheckcolumn',
text: myText,
dataIndex: myDataIndex,
renderer: function(value, meta, record) {
var cssPrefix = Ext.baseCSSPrefix,
cls = [cssPrefix + 'grid-checkheader'],
disabled = // logic to disable checkbox e.g.: !can_be_checked
if (value && disabled) {
cls.push(cssPrefix + 'grid-checkheader-checked-disabled');
} else if (value) {
cls.push(cssPrefix + 'grid-checkheader-checked');
} else if (disabled) {
cls.push(cssPrefix + 'grid-checkheader-disabled');
}
return '<div class="' + cls.join(' ') + '"> </div>';
}
};
Using extjs 5 it is easier to return defaultRenderer in renderer method for target checkboxes and '' for others.
renderer: function (value, metaData, record) {
return (record.isLeaf()) ? '' : this.defaultRenderer(value, metaData);
}
Such won't render checkbox itself but all the events (i.e. checkchange, itemclick, etc) will be remained. If you don't want them either, you may disable them in beforesmth event, for example
onBeforeCheckRequestsChange: function(me, rowIndex, checked, eOpts) {
var row = me.getView().getRow(rowIndex),
record = me.getView().getRecord(row);
return !record.isLeaf();
},
I found the solution to the problem of the checkbox not clickable when usign Aniketos code, you have to make sure that in your code of the column you specify the xtype: 'checkcolumn, that will do the trick
I also ran into this problem and to take it a step further I needed to have a tooltip show over the checkbox. Here's the solution I came up with that seems to be the least invasive on the existing checkcolumn widget...
renderer: function (value, metaData, record) {
// Add a tooltip to the cell
metaData.tdAttr = (record.get("someColumn") === "") ? 'data-qtip="A tip here"' : 'data-qtip="Alternate tip here"';
if (record.get("someColumn") === "") {
metaData.tdClass += " " + this.disabledCls;
}
// Using the built in defaultRenderer of the checkcolumn
return this.defaultRenderer(value, metaData);
}

Resources