I'm having some problems to apply a background-color in the textarea of a ckeditor instance.
When the user clicks on submit without adding any text, it's shown a message telling him to fill all the required fields, and these required fields areas all with the text-fields set with background-color: #CFC183;.
As the ckeditor is created with javascript code, I was using it to try to check if there's any text entered in the text area. if there's no character, I apply the changes.
When I apply in the console this code:
CKEDITOR.instances.body.document.getBody().setStyle('background-color', '#CFC183');
It applies the background exactly like I want to.
So, I added this javascript code in my javascript file to try to manage it, but doesn't seems to be working. Here's my code:
var editorInstance = CKEDITOR.replace('body', { toolbar : 'Full' });
editorInstance.on("instanceReady", function (ev) {
var editorCKE = CKEDITOR.instances.body; readyMap[editorCKE] = true;
editorCKE.setReadOnly(true);
});
var hasText = CKEDITOR.instances.body.document.getBody().getChild(0).getText();
if (!hasText) {
CKEDITOR.on('instanceCreated', function(e) {
e.editor.document.getBody().setStyle('background-color', '#CFC183');
});
}
Firebug shows this error message:
TypeError: CKEDITOR.instances.body.document is undefined
I'm not that good at Javascript, so is there anything wrong with my code?
I already checked this question here, so I believe there's something wrong with my javascript code and I want your help, please.
I guess that you've got an error in this line:
var hasText = CKEDITOR.instances.body.document.getBody().getChild(0).getText();
This is because you're trying to get document element before it's ready (before instanceReady event).
The same error will be thrown here:
if (!hasText) {
CKEDITOR.on('instanceCreated', function(e) {
e.editor.document.getBody().setStyle('background-color', '#CFC183');
});
}
Again - instanceCreated is still too early. You have to move all that code to instanceReady listener. You'll have something like (I'm not sure if I understand what you're trying to achieve):
var editor = CKEDITOR.replace( 'body', { toolbar: 'Full' } );
editor.on( 'instanceReady', function( evt ) {
readyMap[ editor.name ] = true;
editor.setReadOnly( true );
var hasText = editor.document.getBody().getFirst().getText();
if ( !hasText ) {
editor.document.getBody().setStyle( 'background-color', '#CFC183' );
}
} );
As you can see, there is one more issue in your code:
readyMap[editorCKE] = true;
In JS there are no weak maps (yet, but they will be introduced soon). Only strings can be used as a keys of an object. In your case toString() method will be called on editorCKE, which returns [object Object]. That's why I added name property there.
Related
I'm attempting to replicate the content in a particular IFrame element inside of a modal to avoid unnecessary DB calls. I am invoking a clientside callback via Python (see here) that returns the index of a particular IFrame element I would like to replicate in my modal.
Here is the snippet of Python code that toggles my modal and tracks the index of the most recently clicked figure to replicate:
#app.callback(
[Output('my-modal', 'is_open'),
Output('modal-clone', 'children')],
[Input(f'button{k}', 'n_clicks_timestamp') for k in range(20)] +
[State('my-modal', 'is_open')])
def toggle_modal(*data):
clicks, is_open = data[:20], data[20]
modal_display = not is_open if any(clicks) else is_open
clicked = clicks.index(max(clicks))
return [modal_display, clicked]
app.clientside_callback(
ClientsideFunction(namespace='clientside', function_name='clone_figure'),
Output('modal-test', 'children'),
[Input('modal-clone', 'children'), Input('modal-figure', 'id')]
)
And the following Javascript:
window.dash_clientside = Object.assign({}, window.dash_clientside, {
clientside: {
clone_figure: function(clone_from, clone_to) {
source = document.getElementById(clone_from);
console.log(document.getElementById(clone_to))
console.log(document.getElementById(clone_to).contentDocument);
clone = document.getElementById(clone_to);
// set attributes of clone here using attributes from source
return null
}
}
});
Now, from my console.log() statements, I noticed the following (note that modal-clone in the screenshot corresponds to modal-figure in my example):
How is contentDocument changing between these two log statements? Any insight would be greatly appreciated, I am stumped.
It appears that you need to addEventListener() to the IFrame element:
clone_spray: function(clone_from, clone_to) {
source = document.getElementById(clone_from);
clone = document.getElementById(clone_to);
if (!clone) {return null;}
clone.addEventListener("load", function() {
// set attributes of clone here using attributes from source
I have implemented a custom math plugin and integrated it into ck5. this plugin will convert math latex to image equation and I'm able to render the converted math equation image into a ck5 editor using the below code.
editor.model.change(writer => {
const imageElement = writer.createElement('image', {
src: data.detail.imgURL
});
editor.model.insertContent(imageElement, selection);
});
Still here everything is working fine. when i'm trying to store original latex equation value in image tag as custom attribute (attribute name is data-mathml ). It strips out custom attributes.
So I have gone through the documentation and tried but was not able to add the custom attribute.
Below is my code :
class InsertImage extends Plugin {
init() {
const editor = this.editor;
const view = editor.editing.view;
const viewDocument = view.document;
// Somewhere in your plugin's init() callback:
view.addObserver( ClickObserver );
editor.ui.componentFactory.add('insertImage', locale => {
const view = new ButtonView(locale);
view.set({
label: 'Add Equations',
withText: true,
tooltip: true
});
// Callback executed once the image is clicked.
this.listenTo(view, 'execute', () => {
openModel();
});
return view;
});
window.addEventListener('setDatatoCK', function(data){
const selection = editor.model.document.selection;
editor.model.change( writer => {
const imageElement = writer.createElement( 'image', {
src: data.detail.imgURL,
'data-mthml': data.detail.latexFrmla,
} );
editor.model.insertContent( imageElement, selection );
} );
})
this.listenTo( editor.editing.view.document, 'click', ( evt, data ) => {
if ( data.domEvent.detail == 2 ) {
editorToPopupdoubleClickHandler( data.domTarget, data.domEvent );
evt.stop();
}
}, { priority: 'highest' } );
}
};
I want to add multiple attributes to the image tag. What should I do to add multiple attributes?
(Note: I'm able to create a new custom tag (tag named "math") with multiple attributes but not for image tag)
Please help me with this. this blocker for me.
Methods tried:
In order to achieve this, I have created one custom tag with multiple attributes and append image tags under this custom tag. It's working fine as expected but I want to add multiple attributes to image tag not with the custom tag.
✔️ Expected result
❌ Actual result
📃 Other details
Browser: Google Chrome Version 78.0.3904.108 (Official Build) (64-bit)
OS: macOS Mojave 10.14.6
CKEditor version: CKEditor 5
Installed CKEditor plugins: ckeditor5-editor-classic,ckeditor5-image,ckeditor5-essentials,ckeditor5-basic-styles,ckeditor5-core,ckeditor5-ui
Hope you've already found a solution to this answer. After spending several hours on searching a solution to a similar problem, I've made it working. See below:
// you have to import the insertImage fn to be able to override default imageinsert fn
import { insertImage } from '#ckeditor/ckeditor5-image/src/image/utils.js'
// this method HAVE to be automatically called when ckeditor is onready.
// You can add custom eventlistener or on the html tag just define listener:
// in Vue2 we used to do like this: <ckeditor #ready="someFnOnCkEditorReadyState()" />
someFnOnCkEditorReadyState() {
// as for img tag the options supported by ckeditor is very limited, we must define our properties to extend the used schema
editor.model.schema.extend('image', { allowAttributes: ['data-mathml'] })
// add conversion for downcast
editor.conversion.for('downcast').add(modelToViewAttributeConverter('data-mathml'))
// add conversion for upcast
editor.conversion.for('upcast').attributeToAttribute({
view: {
name: 'image',
key: 'data-mathml',
},
model: 'data-mathml',
})
}
// then you have to implement your custom image insert method
// from now on this will be your default insertImage fn
// this modification might require other modifications for example to add a custom image browser button to the toolbar
otherFnToInsertImg() {
insertImage(editor.model, {
src: image.url,
'data-mathml': 'here comes the magic',
})
}
Hope it helps someone to save some hours. ;)
My Problem:
I am trying to click options in a dropdown with Nightwatch, using sections in page objects. I'm not sure if it's a problem with the section declaration or i'm missing something scope-related. Problem is that it finds the element as visible, but when it tries to click it will throw error that it cannot locate it using recursion.
What could i try to do to fix this issue using sections?
In the test:
var myPage = browser.page.searchPageObject();
var mySection = searchPage.section.setResults;
// [finding and clicking the dropdown so it opens and displays the options]
browser.pause (3000);
browser.expect.section('#setResults').to.be.visible.before(1000);
myPage.myFunction(mySection, '18');
In the page object:
var searchKeywordCommands = {
myFunction: function (section, x) {
section.expect.element('#set18').to.be.visible.before(2000);
if (x == '18') section.click('#set18');
//[...]
};
module.exports = {
//[.. other elements and commands..]
sections: {
setResults: {
selector: '.select-theme-result', //have also tried with '.select-content' and '.select-options' but with the same result
elements: {
set18: '.select-option[data-value="18"]',
set36: '.select-option[data-value="36"]' //etc
}}}}
Here is my source code:
When i run this piece of core, it seems to find the section, finds the element visible (i also can clearly see that it opens the dropdown and shows the options) but when trying to click any option, i get the error: ERROR: Unable to locate element: Section[name=setResults], Element[name=#set18]" using: recursion
Here is the full error:
My attempts:
I have tried to declare that set18 selector as an individual element instead of inside of the section and everything works fine this way, but won't work inside of the section. I have also tried all the selectors available to define the section's selector, but it won't work with any of them.
This is what i am doing with(LOL)
I assume steps would be (find dropbox - click dropbox - select value).
var getValueElement = {
getValueSelector: function (x) {
return 'li[data-value="'+ x + '"]';
}
};
module.exports = {
//[.. other elements and commands..]
sections: {
setResults: {
commands:[getValueElement],
selector: 'div[class*="select-theme-result"', //* mean contains,sometime class is too long and unique,also because i am lazy.
elements: {
setHighlight:'li[class*="select-option-highlight"]',
setSelected:'li[class*="select-option-selected"]',
//set18: 'li[data-value="18"]',
//set36: 'li[data-value="36"]'
// i think getValueFunction is better,what if you have 100+ of set.
}}}}
In your test
var myPage = browser.page.searchPageObject();
var mySection = searchPage.section.setResults;
// [finding and clicking the dropdown so it opens and displays the options]
mySection
.click('#dropboxSelector')
.waitForElementVisible('#setHighlight',5000,false,
function(){
var set18 = mySection.getValueElement(18);
mySection.click(set18);
});
Ps:in my case(i think your case also), dropbox or any small third-party js framework which is used many times in your web app, so better create a different PageObject for it,make pageObject/section is simple as possible.
In js library use where .bind("focus.mask") and .bind("blur.mask") function which do blur and focus.
js library:
(function(a){var b=(a.browser.msie?"paste":"input")+".mask",c=window.orientation!=undefined;a.mask={definitions:{9:"[0-9]",a:"[A-Za-z]","*":"[A-Za-z0-9]"},dataName:"rawMaskFn"},a.fn.extend({caret:function(a,b){if(this.length!=0){if(typeof a=="number"){b=typeof b=="number"?b:a;return this.each(function(){if(this.setSelectionRange)this.setSelectionRange(a,b);else if(this.createTextRange){var c=this.createTextRange();c.collapse(!0),c.moveEnd("character",b),c.moveStart("character",a),c.select()}})}if(this[0].setSelectionRange)a=this[0].selectionStart,b=this[0].selectionEnd;else if(document.selection&&document.selection.createRange){var c=document.selection.createRange();a=0-c.duplicate().moveStart("character",-1e5),b=a+c.text.length}return{begin:a,end:b}}},unmask:function(){return this.trigger("unmask")},mask:function(d,e){if(!d&&this.length>0){var f=a(this[0]);return f.data(a.mask.dataName)()}e=a.extend({placeholder:"_",completed:null},e);var g=a.mask.definitions,h=[],i=d.length,j=null,k=d.length;a.each(d.split(""),function(a,b){b=="?"?(k--,i=a):g[b]?(h.push(new RegExp(g[b])),j==null&&(j=h.length-1)):h.push(null)});return this.trigger("unmask").each(function(){function v(a){var b=f.val(),c=-1;for(var d=0,g=0;d<k;d++)if(h[d]){l[d]=e.placeholder;while(g++<b.length){var m=b.charAt(g-1);if(h[d].test(m)){l[d]=m,c=d;break}}if(g>b.length)break}else l[d]==b.charAt(g)&&d!=i&&(g++,c=d);if(!a&&c+1<i)f.val(""),t(0,k);else if(a||c+1>=i)u(),a||f.val(f.val().substring(0,c+1));return i?d:j}function u(){return f.val(l.join("")).val()}function t(a,b){for(var c=a;c<b&&c<k;c++)h[c]&&(l[c]=e.placeholder)}function s(a){var b=a.which,c=f.caret();if(a.ctrlKey||a.altKey||a.metaKey||b<32)return!0;if(b){c.end-c.begin!=0&&(t(c.begin,c.end),p(c.begin,c.end-1));var d=n(c.begin-1);if(d<k){var g=String.fromCharCode(b);if(h[d].test(g)){q(d),l[d]=g,u();var i=n(d);f.caret(i),e.completed&&i>=k&&e.completed.call(f)}}return!1}}function r(a){var b=a.which;if(b==8||b==46||c&&b==127){var d=f.caret(),e=d.begin,g=d.end;g-e==0&&(e=b!=46?o(e):g=n(e-1),g=b==46?n(g):g),t(e,g),p(e,g-1);return!1}if(b==27){f.val(m),f.caret(0,v());return!1}}function q(a){for(var b=a,c=e.placeholder;b<k;b++)if(h[b]){var d=n(b),f=l[b];l[b]=c;if(d<k&&h[d].test(f))c=f;else break}}function p(a,b){if(!(a<0)){for(var c=a,d=n(b);c<k;c++)if(h[c]){if(d<k&&h[c].test(l[d]))l[c]=l[d],l[d]=e.placeholder;else break;d=n(d)}u(),f.caret(Math.max(j,a))}}function o(a){while(--a>=0&&!h[a]);return a}function n(a){while(++a<=k&&!h[a]);return a}var f=a(this),l=a.map(d.split(""),function(a,b){if(a!="?")return g[a]?e.placeholder:a}),m=f.val();f.data(a.mask.dataName,function(){return a.map(l,function(a,b){return h[b]&&a!=e.placeholder?a:null}).join("")}),f.attr("readonly")||f.one("unmask",function(){f.unbind(".mask").removeData(a.mask.dataName)}).bind("focus.mask",function(){m=f.val();var b=v();u();var c=function(){b==d.length?f.caret(0,b):f.caret(b)};(a.browser.msie?c:function(){setTimeout(c,0)})()}).bind("blur.mask",function(){v(),f.val()!=m&&f.change()}).bind("keydown.mask",r).bind("keypress.mask",s).bind(b,function(){setTimeout(function(){f.caret(v(!0))},0)}),v()})}})})(jQuery);
In my js file I want to unbind this .bind(focus.mask) and .bind(blur.mask) function ?
My Js:
function applyInputMasks() {
var $form.bind("blur.mask",function(){v(),f.val()!=m&&f.change()}) = $('form');
if ($form.size()) {
// added try catch so that if input field not found then it wont give an error
try{
//$form.find('input:not([skip-masks])[name*=cpf]').mask("999.999.999-99");
//$form.find('input:not([skip-masks])[name*=document]').mask("999.999.999-99");
$form.find('input:not([skip-masks])[name*=date]').mask("99/99/9999");
$form.find('input:not([skip-masks])[name*=postalCode]').mask("999999");
//$form.find('input:not([skip-masks])[name*=phone]').mask("999999999999");
// Postal code
var $postalCode = $form.find('input:not([skip-masks])[name*=postalCode]');
if ($postalCode.attr('skip-resolve-postalcode')) {
$postalCode.mask("999999");
} else {
$postalCode.mask("999999");
$postalCode.mask("999999", {completed: resolvePostalCode});
}
// override the value AFTER applying the mask
var valueToOverride = $postalCode.attr('override-value');
if (valueToOverride) {
$postalCode.val(valueToOverride);
}
} catch (e) {}
}
BRAPRINT.util.log('Masks applied!');
}
In my form where i use this mask function when I enter 6 digit postal code in box in submit form then city is automatically update If i providing incomplete pin code and clicking outside Postal Box in form data is cleared because in library use .bind("focus.mask") and .bind("blur.mask").
I read this tutorial:
http://view.jqueryui.com/mask/tests/visual/mask/mask.html
where say if .bind() convert to .unbind() then incomplete enter postal code in form not cleared after clicking out of the postal code input box.
after read this functionality I was try this in my js file where postal code :
$form.find('input:not([skip-masks])[name*=postalCode]').unbind("focus.mask");
$form.find('input:not([skip-masks])[name*=postalCode]').unbind("blur.mask");
and after this I was clearing all cache but this is not working.
I want data not cleared if i enter incomplete postal code. it is possible ?
I don't want to change in mask library file because this is not a right way.
Rather than unbind you could try e.preventDefault or return false as used in this article on CSS tricks which stops event propagation and bubbling.
http://css-tricks.com/return-false-and-prevent-default/
I have following JavaScript code :
this._incrementButtonProperties = {
"enabled": this.properties.incrementButtonConfig.enabled,
"enabledClass" : "SchedMainCtrlIncrementBtn_En",
"disabledClass" : "SchedMainCtrlIncrementBtn_Ds",
"appData" : this.properties.incrementButtonConfig.appData,
"text" : this.properties.incrementButtonConfig.text,
"incrementSelectCallback" : this._incrementButtonSelectHandler.bind(this),
};
and
this._incrementBtn = document.createElement('div');
this._incrementBtn .className = this._incrementButtonProperties.enabledClass;
this.divElt.appendChild(this._incrementBtn);
&
this._incrementBtn.addEventListener('click', this._incrementButtonProperties.incrementSelectCallback, false);
Also,
this._prototype._incrementButtonSelectHandler = function(ctrlRef, appData, params)
{
// + & -
alert("_incrementButtonSelectHandler called... ");
}
But event listener is not getting added :-( If I write document.addEventListener('click', this._incrementButtonProperties.incrementSelectCallback, false); - then listener is getting added but I need it only for "this._incrementBtn" div element.
Any idea whats going wrong?
Note : Please do not suggest jQuery etc. I do not want to use any framework.
Thanks
Sneha
Should it really read this._prototype._incrementButtonSelectHandler = ...?
Shouldn't it be this.prototype? Otherwise I don't see how this._incrementButtonSelectHandler could correspond to this._prototype._incrementButtonSelectHandler.
Also, you have a trailing comma in this._incrementButtonProperties {...}, which until Ecmascript 5 was actually invalid, even if most browsers will accept it without any complaining.