How to prevent ckeditor from substituting single quotes - ckeditor

I have searched for a solution to this problem but can't find it. When I paste code with single quotes like this:
<script type="text/javascript">
(function(d, t) {
var s = d.createElement(t), options = {
'id': 'IVvPsA',
'container': 'c47',
'height': '1479px',
Then the quotes are replaced and therefore the code is no longer valid
<script type="text/javascript">
(function(d, t) {
var s = d.createElement(t), options = {
'id': 'IVvPsA',
'container': 'c47',
'height'
Any idea? Thanks. I try to add in config.js this code:
config.allowedContent = true;
config.extraAllowedContent = 'div(col-md-*,container-fluid,row)';
config.extraAllowedContent = 'ul(*)';
config.extraAllowedContent = 'table(*)';
config.htmlEncodeOutput = false;
config.entities = false;

Related

How to load XML from an external site server (using AJAX)?

Here I have an example I'm building (with help).
Currently, the XML is stored in a data island. But what if I wanted to make a request to an external server? Would I use an XMLHttpRequest?
How would I code that in this example, and avoid the Cross Origin XMLHttpRequest problem?
In this example, I've tried playing with function loadXMLDoc(statelabel) but without success.
Am I on the right track with this function?
function loadXMLDoc( statelabel ) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
myFunction(this);
}
};
xhttp.open("GET", "state_data.xml", true);
xhttp.send();
}
Fully functional code here:
<!DOCTYPE html>
<!--
SO
datalist / xml handling
Q 51200490 (https://stackoverflow.com/questions/51200490/how-to-find-the-node-position-of-a-value-in-an-xml-tree/51201494)
A
-->
<html>
<head>
<title>SO sample</title>
<script>
// Setup of keypress event handler, default selection of xml data.
function setupEH () {
var n = document.getElementById("myInputId");
n.addEventListener("keyup", function(event) {
event.preventDefault();
if (event.keyCode === 13) {
document.getElementById("myButton").click();
}
});
loadXMLDoc('Alabama'); // comment out this line if you want a vanilla UI after loading the html page.
}
// Load the xml document
function loadXMLDoc( statelabel ) {
// The xml document is retrieved with the following steps:
// 1. Obtain the (in-document) source as a DOM node.
// 2. Extract textual content.
// 3. Instantiate the xml parser (a browser built-in)
// 4. Parse textual content into an xml document
//
// When retrieving the xml document by means of ajax, these steps will be handled by the library for you - a parsed xml document will be available as a property or through calling a method.
//
let x_xmlisland = document.getElementById("template_xml");
let s_xmlsource = x_xmlisland.textContent;
let parser = new DOMParser();
let xmlDoc = parser.parseFromString(s_xmlsource, "application/xml");
myFunction(xmlDoc, statelabel); // Actual work ...
}
// Processing the xml document
function myFunction(xmlDoc, statelabel) {
// debugger; // uncomment to trace
//
// Every bit of information is processed as follows:
// - Get the relevant xml subtree ( `UNIT` element of the selected state incl.descendants )
// - Extract the textual value.
// - Feed the textual value to the Html elements prsenting the result.
//
var xpr_current_unit = xmlDoc.evaluate("/STATE_DATA/UNIT[./STATE[./text() = '"+statelabel+"']]",xmlDoc,null,XPathResult.ORDERED_NODE_ITERATOR_TYPE,null);
var node_current_unit = xpr_current_unit.iterateNext();
//
// The subsequent calls to xmlDoc.evaluate set the current UNIT element as their context node ('starting point'/'temporary root' for the xpath expression).
// The context node is referenced by '.' (dot)
//
var xpr_s = xmlDoc.evaluate("./STATE/text()",node_current_unit,null,XPathResult.ORDERED_ANY_TYPE,null);
var node_s = xpr_s.iterateNext();
var s = node_s.textContent
document.getElementById("state").innerHTML = s;
var xpr_g = xmlDoc.evaluate("./GDP/text()",node_current_unit,null,XPathResult.ORDERED_ANY_TYPE,null);
var node_g = xpr_g.iterateNext();
var g = "Unknown";
if ( node_g !== null ) {
g = node_g.textContent;
}
document.getElementById("gdp").innerHTML = g;
var xpr_p = xmlDoc.evaluate("./POPULATION/text()",node_current_unit,null,XPathResult.ORDERED_ANY_TYPE,null);
var node_p = xpr_p.iterateNext();
var p = "Unknown";
if ( node_p !== null ) {
p = node_p.textContent;
}
document.getElementById("population").innerHTML = p;
// cf. https://stackoverflow.com/a/3437009
var xpr_u = xmlDoc.evaluate("count(./preceding::UNIT)+1.",node_current_unit,null,XPathResult.ORDERED_ANY_TYPE,null);
var n_ucount = xpr_u.numberValue;
document.getElementById("inputValue").innerHTML = s;
document.getElementById("nodePosition").innerHTML = n_ucount;
}
// Setup the submit click handler
function ehClick ( ) {
let node_choice = document.getElementById('myInputId');
loadXMLDoc(node_choice.value);
}
</script>
<style>
</style>
</head>
<body onload="setupEH()">
<script id="template_xml" type="text/xml"><?xml version="1.0" encoding="UTF-8"?>
<STATE_DATA>
<UNIT>
<STATE>Wisconsin</STATE>
<GDP>232,300,000,000</GDP>
<POPULATION>5,800,000</POPULATION>
</UNIT>
<UNIT>
<STATE>Alabama</STATE>
<GDP>165,800,000,000</GDP>
<POPULATION>4,900,000</POPULATION>
</UNIT>
<UNIT>
<STATE>California</STATE>
<!-- Note: the GDP node for this unit is missing -->
<POPULATION>39,600,000</POPULATION>
</UNIT>
<UNIT>
<STATE>Texas</STATE>
<GDP>1,600,000,000,000</GDP>
<POPULATION>28,300,000</POPULATION>
</UNIT>
<UNIT>
<STATE>Michigan</STATE>
<GDP>382,000,000</GDP>
<POPULATION>10,000,000</POPULATION>
</UNIT>
</STATE_DATA>
</script>
<input list="myInput" id="myInputId" value="">
<button id="myButton" onClick="ehClick()">submit</button>
<p>input value: <span id="inputValue"></span></p>
<p>XML tree node position of input value: <span id="nodePosition"></span></p>
<p>State: <span id="state"></span></p>
<p>GDP: <span id="gdp"></span></p>
<p>Population: <span id="population"></span></p>
<datalist id="myInput">
<option id="AL">Alabama</option>
<option id="CA">California</option>
<option id="MI">Michigan</option>
<option id="TX">Texas</option>
<option id="WI">Wisconsin</option>
</datalist>
</body>
</html>
This gets a little bit involved using vanilla XMLHttpRequest to load XML. Here is a quick sample.
function loadXMLDoc() {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
myFunction(this);
}
};
xmlhttp.open("GET", "sample.xml" , true);
xmlhttp.send();
}
function myFunction(xml) {
var x, i, xmlDoc, table;
xmlDoc = xml.responseXML;
table = "<tr><th>Artist</th><th>Title</th></tr>";
x = xmlDoc.getElementsByTagName("CD")
for (i = 0; i < x.length; i++) {
table += "<tr><td>" +
x[i].getElementsByTagName("ARTIST")[0].childNodes[0].nodeValue +
"</td><td>" +
x[i].getElementsByTagName("TITLE")[0].childNodes[0].nodeValue +
"</td></tr>";
}
document.getElementById("demo").innerHTML = table;
}
However, it gets much more complicated esp. if you want to do a cross-domain request.
That's probably the right moment to pick up jQuery to make things easier:
$.ajax({
url: 'https://www.w3schools.com/xml/note.xml',
dataType: 'XML',
type: 'GET',
async: false,
crossDomain: true,
success: function () { },$.ajax({
url: 'https://www.w3schools.com/xml/note.xml',
dataType: 'XML',
type: 'GET',
async: false,
crossDomain: true,
success: function () { },
failure: function () { },
complete: function (xml) {
// Parse the xml file and get data
var xmlDoc = $.parseXML(xml);
$xml = $(xmlDoc);
$xml.find('body').each(function () {
console.log($(this).text());
});
}
});

Trying to add a plugin to CKEditor

I'm trying to add a plugin to set a default URL when adding a link.
I followed the instructions here:
https://apostrophecms.org/docs/tutorials/howtos/ckeditor.html
And I ended up with:
// lib/modules/apostrophe-areas/public/js/user.js
apos.define('apostrophe-areas', {
construct: function(self, options) {
var superEnableCkeditor = self.enableCkeditor;
self.enableCkeditor = function() {
superEnableCkeditor();
CKEDITOR.plugins.addExternal('defaulturl', '/modules/my-apostrophe-areas/js/ckeditorPlugins/defaulturl/', 'plugin.js');
};
}
});
and this is my apostrophe-areas/public/js/ckeditorPlugins/defaulturl/plugin.js
CKEDITOR.on( 'dialogDefinition', function( ev ) {
var dialogName = ev.data.name;
var dialogDefinition = ev.data.definition;
if ( dialogName == 'link' ) {
var infoTab = dialogDefinition.getContents( 'info' );
var urlField = infoTab.get( 'url' );
urlField[ 'default' ] = 'www.example.com';
}
});
However, this is not working for me, I tried to do what is suggested here:
Ckeditor plugin configuration not working
But it doesn't worked.
What I've tried and worked was to append the plugin.js file at the end of the plugin.js of the split plugin at the apostrophe-area folder, but I think this is not the correct way to go
Thanks!
I think you can solve the issue two ways:
1. If you want to keep the external plugin file:
Wrap your code according to the API, see e.g. https://sdk.ckeditor.com/samples/timestamp.html and the plugin it references https://sdk.ckeditor.com/samples/assets/plugins/timestamp/plugin.js for an example. You need to use CKEDITOR.plugins.add( 'defaulturl', { init: ... }) in your plugin.js. Not sure if there is anything special to do otherwise as you want to modify the behavior of a CKEDITOR core plugin. That's why it would go with the next option...
2. If you don't need the extra plugin.js:
You can also replace the CKEDITOR.plugins.addExternal() call with the contents of your plugin.js file. I did this to modify the default link target to be _blank:
// /lib/modules/apostrophe-areas/public/js/user.js
'use strict';
// See https://apostrophecms.org/docs/tutorials/howtos/ckeditor.html and
apos.define('apostrophe-areas', {
construct: function(self, options) {
var superEnableCkeditor = self.enableCkeditor;
self.enableCkeditor = function enableCkeditor() {
superEnableCkeditor();
// https://docs.ckeditor.com/ckeditor4/latest/guide/dev_howtos_dialog_windows.html
CKEDITOR.on('dialogDefinition', function redefineDialog(ev) {
var dialogName = ev.data.name;
var dialogDefinition = ev.data.definition;
if (dialogName === 'link') {
var targetTab = dialogDefinition.getContents('target');
var targetField = targetTab.get('linkTargetType');
targetField.default = '_blank';
}
});
};
}
});
Good luck!

mithril.js issues with CKEditor

I've written this code using mithril.js + CKEditor
<body>
<script>
var frm = {};
frm.vm = (function () {
var vm = {};
vm.afterLoad = function () {
CKEDITOR.replace( 'editor1' );
};
vm.btnClick = function () {
console.log(document.getElementById('editor1').value);
};
return vm;
})();
frm.controller = function () {
};
frm.view = function (controller) {
return m("div", {config: frm.vm.afterLoad}, [
m("textarea", {id: "editor1"}),
m("button", {onclick: frm.vm.btnClick}, "Click here to see the text you've typed")
])
;
};
m.mount(document.body, frm);
</script>
</body>
but when I click the button, I see this error:
Uncaught The editor instance "editor1" is already attached to the provided element.
and console.log() prints a blank line.
What am I doing wrong?
I found the problem. To get the value of the CKEditor, one needs to use
CKEditor.instance.nameoftextarea.getData()

Knockout predefined default with options binding to observable array

I am getting a list of options for a select from a server and populating an observableArray. Then I would like to set the selected item to a predefined value. I have a very simple jsFiddle that emulates pulling data from a server with a button click.
http://jsfiddle.net/JonathanN/hev1rqeu/
Here's the Javascript with the basic attempt:
(function() {
var vm = (function() {
var self = this;
self.array = ko.observableArray([]);
self.selectedValue = ko.observable();
self.useSetTimeout = ko.observable(false);
self.array.subscribe(function(newValue) {
self.selectedValue('b');
});
self.populate = function() {
self.array(['a','b','c']);
};
}());
ko.applyBindings(vm);
}());
And here's my workaround, which replaces "self.selectedValue('b');":
var waitForSelectToPopulate = function() {
self.selectedValue('b');
if(self.selectedValue() != 'b') {
setTimeout(waitForSelectToPopulate, 10);
}
};
waitForSelectToPopulate();
I am not very fond of this as a workaround. It seems like there should be a reasonable way to handle this, but just setting the value on subscribe trigger doesn't seem to work.
You need optionsAfterRender. Here's a fiddle:
http://jsfiddle.net/sifriday/hev1rqeu/4/
HTML -
<select data-bind="options: array, value: selectedValue, optionsAfterRender: setVal">
JS addition -
self.setVal = function() {
self.selectedValue('b');
}
Docs - http://knockoutjs.com/documentation/options-binding.html - and scroll down to Note 2
Once the populate event has gone and got the json and placed it into your array, why not just set the value right after? as soon as you set the data inside of self.array it will update.
(function() {
var vm = (function() {
var self = this;
self.array = ko.observableArray([]);
self.selectedValue = ko.observable();
self.populate = function() {
// magical assmagic goes and get's json, and converts it to ['a','b','c']
self.array(['a','b','c']); // dropdown is now populated
self.selectedValue('c'); // therefore we can set it to a valid value
};
}());
ko.applyBindings(vm);
}());
see the following:
http://jsfiddle.net/hev1rqeu/5/

MooTools - how to reload image?

Is there any way to reload the same image using mootools. I have a camera that gives me image, but I have to refresh it. I wrote this, but it doesn't work so well:
var url = "some valid url to some image.jpg";
var timer = 10;
var periodical;
var camera_container;
var refresh = (function() {
var loader = new Asset.image(url, {
onLoad : function() {
camera_container.empty();
camera_container.inject(loader);
}
});
});
window.addEvent('domready', function() {
// the periodical starts here, the * 1000 is because milliseconds required
refresh.periodical(timer * 1000, this);
camera_container = $('camera-image');
});
Any help appreciated. Thanks.
why not add a seeding bit to the url?
(function() {
var url = "some valid url to some image.jpg?";
this.timer = 10;
var counter = 0;
this.refresh = (function() {
var loader = new Asset.image(url + counter, {
onLoad: function() {
camera_container.empty();
camera_container.inject(loader);
counter++;
}
});
});
})();
window.addEvent('domready', function() {
// the periodical starts here, the * 1000 is because milliseconds required
refresh.periodical(timer * 1000, this);
this.camera_container = $('camera-image');
});
this way the url will always be path/image.jpg?n where n changes and will force the browser to re-fetch it.
I think something like this also can work:
<div id="image-holder">
<img src="http://www.image.com/image.jpg"/>
</div>
var srcImage = 'http://www.image.com/image.jpg';
var reloadTime = 4000;
var holder = document.id('image-holder');
var imageReload = function(){
holder.empty();
var newImage = new Element('img',{
id:'image',
src:srcImage ,
alt:'image new'
}).inject(holder);
}
var start = function() {
interval = imageReload.periodical(reloadTime);
};
start();

Resources