change some tinymce behaviour (javascript) - javascript

Hi everybody
I am using the tinymce format dropdown to apply custom styles to html elements. This is for users without html knowledge
One annoying thing for me is that when a user klicks at different styles they all get added and something like this may happen
<div class="floatleft floatright positionup positiondown">
In order to prevent this I searched for the responsible code which is in editor_template.js (compressed) but visible in editor_template_src.js
Is there maybe a way to rewrite this piece of javascript so that each applied style replaces the former?
_createStyleSelect : function(n) {
var t = this, ed = t.editor, ctrlMan = ed.controlManager, ctrl;
// Setup style select box
ctrl = ctrlMan.createListBox('styleselect', {
title : 'advanced.style_select',
onselect : function(name) {
var matches, formatNames = [];
each(ctrl.items, function(item) {
formatNames.push(item.value);
});
ed.focus();
ed.undoManager.add();
// Toggle off the current format
matches = ed.formatter.matchAll(formatNames);
if (!name || matches[0] == name)
ed.formatter.remove(matches[0]);
else
ed.formatter.apply(name);
ed.undoManager.add();
ed.nodeChanged();
return false; // No auto select
}
});

How about:
if (!name || matches[0] == name)
ed.formatter.remove(matches[0]);
else
ed.formatter.remove(matches[0]);
ed.formatter.apply(name);
Just a wild guess, haven't tried it myself.

This a lot of work to do, but it can be done.
I solved this issue writing a custom plugin and using a custom FormatterClass.
I suggest you try developing with tiny_mce_dev.js - this way you are able to track down problems to js classes.
Then you should have a look at the js-class Formatter.js and try to modify this one in order to fullfill your wishes.
The next step will be to save the mofied Formatter.js and make it part of your plugin, so that you can reset the real Formatter.js, cause i suggest not to change the tinymce core files.

Related

Change thousands sign using JS

Here I would like to replace in the draggable slider the "," sign used for the thousands into this sign " ' " (a quote mark).
I am currently using a plugin to render the table (from a JSON file) so I cannot alter the HTML.
I am able to change the sign, in fact on page load the sign seems correct, but as soon I drag the slider the separator changes to a comma again.
I saw that the data is rendered from the Plugin with a comma in the aria-valuetext="" attribute: <div class="noUi-handle noUi-handle-upper" data-handle="1" tabindex="0" role="slider" aria-orientation="horizontal" aria-valuemin="0.0" aria-valuemax="100.0" aria-valuenow="100.0" aria-valuetext="2,290.00"><div class="noUi-tooltip">2,290.00</div></div>
I tried using this code without any results:
<script>
window.onload = function(){
var div = document.querySelectorAll('.noUi-tooltip');
div.forEach(function(r) {
var text = r.textContent;
var output = text.replace(/[,|]/g, "'");
r.innerHTML = output;
});
}
</script>
What am I writing wrong?
I am using WordPress and the wpdatatables plugin.
I'm not sure about the plugin you've used for your slider but perhaps you can try this for now:
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (mutation.type == "attributes") {
var parentEl = document.getElementsByClassName('noUi-handle-upper');
var childEl = parentEl.childNodes[0];
childEl.innerHTML = childEl.innerHTML.replace(',', '\'');
}
});
});
observer.observe(document.getElementsByClassName('noUi-handle-upper')[0], {
attributes: true,
});
It's using MutationObserver which is not supported by older browsers. You can read more about it at https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver.
This is because you modify the string just in the beginning (on load).
This is why the code works in the beginning but doesn't work later, because it runs once and then stops.
I don't know how to use WordPress or sliders, but I'd advise you to use an 'on value changed' command, so the text will change to whatever you want it to each time the slider's value is changed.
I will post this now but I'll review your code and will try to update this with more exact information later.

CKEditor: PasteFromWord ignores pasteFilter

In CKEditor 4.6.2 (currently bundled in Drupal 8) ACF is disabled by default, to make sure some of the special plugins work correctly. So for the record: I do not want to enable ACF and am not able to use allowedContent or disallowedContent. I'm trying to prevent some elements to be injected on paste from Word (like h1 and p[styles]).
To accomplish this, I'm trying to add these to pasteFilter which works perfectly on non-Word-pasted content, though when pasting from Word the pasteFilter seems to be ignored? Is this a bug?
So, how can I:
Keep ACF disabled - In favor of special Drupal elements
Keep pastefromword enabled - To detect special Word styling like indentation and lists.
Add additional filtering to all (including from Word) pastings - To remove some elements and attributes like h1, style="font-family: Verdana" etc...
Handling content pasted from Word requires some serious amount of markup processing to transform it into clean, semantic content. The paste from Word filter is very specific covering many edge cases (especially with nested lists). The reason why pasting from Word has its own filter and does not reuse ACF rules is the fact that it may cause some conflicts - it is described in this issue.
As for now there is now out-of-the-box approach to add additional filtering to content pasted from Word. However, you may utilise afterPasteFromWord event, to filter the pasted data like:
var editor = CKEDITOR.replace( 'editor1' );
editor.on( 'afterPasteFromWord', function( evt ) {
var filter = editor.activeFilter, // Use activeFilter so it reflects ACF settings.
// var filter = new CKEDITOR.filter( 'p b' ), // Use custom new filter.
fragment = CKEDITOR.htmlParser.fragment.fromHtml( evt.data.dataValue ),
writer = new CKEDITOR.htmlParser.basicWriter();
filter.applyTo( fragment );
fragment.writeHtml( writer );
evt.data.dataValue = writer.getHtml();
} );
Please see this codepen demo.
You may also refer to official docs on CKEDITOR.filter.applyTo and CKEDITOR.editor.activeProperty.
This is my current solution, as a plugin:
// Activate the ACF filter only when pasting from Word (the opposite of the default).
// Use config.pasteFilter='semantic-content' to filter non-Word pasted content.
// Tested with ckeditor 4.8.
CKEDITOR.plugins.add('filterOnlyOnPaste', {
init: function(editor) {
editor.on('setData', function(evt) {
editor.activeFilter.disabled = true;
});
editor.on('instanceReady', function(evt) {
editor.activeFilter.disabled = true;
});
editor.on('afterPasteFromWord', function(e) {
editor.activeFilter.disabled = false;
var filter = editor.activeFilter,
fragment = CKEDITOR.htmlParser.fragment.fromHtml(e.data.dataValue),
writer = new CKEDITOR.htmlParser.basicWriter();
filter.applyTo(fragment);
fragment.writeHtml(writer);
e.data.dataValue = writer.getHtml();
editor.activeFilter.disabled = true;
});
}
});

Set value of dropdown to variable in SugarCRM

I am fairly new to using SugarCRM and I am just trying to do some validation on a form page I have.
I am simply trying to get the value of my dropdown, and perform my error if it is equal to "None" but I am unsure how to get the value using SugarJS.
Here is an example of how i get just a basic input field, which is working correctly.
var first_name = $('input[name=first_name]').val();
var last_name = $('input[name=last_name]').val();
if (first_name == "") {
$('input[name=first_name]').css({'border':'2px solid red'});
proceed = false;
}
if (last_name == "") {
$('input[name=last_name]').css({'border':'2px solid red'});
proceed = false;
}
See how I make: https://github.com/ErasmoOliveira87/SugarCRM
I create one logic hook to load js files, and use a normal Jquery inside of scripts.js file (I never found other way to do this). This solution I use to professional versions, and works for community too. If you have access to FTP to manipulate the files you just need create the structure otherwise if you using professional version you need to create one package with manifest file(have example in git too).
fields with "_c" are custom fields, you can see the names in studio.
$(document).ready(function(){
$('#account_name').val("Some value");
$('#phone_number').val("Some value");
$('#YOUR_CUSTOM_FIELD_ID_c').val("Some value");
$('#YOUR_CUSTOM_FIELD_ID_c').val("Some value");
});
After create everything you need go to Admin > Repair > rebuild to clean all cache files.

Highlighting current selected textfield - best approach

I am trying to achieve an effect like this on mobile (ios + android):
http://i.imgur.com/6zaTdRd.png
Where the currently selected textfield has a blue tinted icon + underlining
So my framework lacks any support for grey scaling a bitmap image of any sort so I need to swap between two images to achieve this effect.
My current implementation looks like this:
Please note this for the Titanium Alloy MVC framework but I'm guessing the basic logic should be similar.
I listen for blur/focus events to toggle current image
$.firstNameField.addEventListener('focus', function(e){
swapImages($.firstNameField.getParent());
});
$.lastNameField.addEventListener('focus', function(e){
swapImages($.lastNameField.getParent());
});
and then I swap images like so:
/**
* Swaps between the images (..._0 and ..._1) of an ImageView nested in a
TableRow
* ..._0 Greyscale image
* ..._0 Colour image
* #param e current TableViewRow
*/
function swapImages(e){
var imagePathSplit = (e.children[0].image).split('_');
var newImagePath = null;
if(imagePathSplit[1] == "0.png")
newImagePath = imagePathSplit[0] + "_1.png";
else
newImagePath = imagePathSplit[0] + "_0.png";
e.children[0].image = newImagePath;
return;
}
This doesn't look that great especially since I need a lot more fields with this functionality, I also want to implement tabbing (using Return key = NEXT) between the fields which will further balloon to increase 1 more event listener per field.
How would something like this be done ideally? I can think of one way of just creating the fields in code in array form which should help simplify matters (no more looking too far for Parent/Children, but that would still end up using quite a bit of listeners for switching right?
EDIT: Forgot to add how I have the textFields setup:
<TableView id="paypalTable">
<TableViewSection>
<TableViewRow id="firstNameView" class="tableRow">
<ImageView id="firstNameIcon" class="textFieldIcon"/>
<TextField id="firstNameField" class="textField"/>
</TableViewRow>
I tried something similar in one of my projects. Although I had an Alloy project I had to use a classic approach to get my desired behaviour.
In my controller:
var textFields = [];
var yourTextFieldsArray = [];
for (var i = 0; i < yourTextFieldsArray; i++) {
//Set the selected state to false initially. Maybe you need another command for it.
textFieldIsSelected[i] = false;
//create your new view
textFields[i] = Ti.UI.createView({
top : topValues[i],
width : Titanium.UI.FILL,
height : height,
id : i + 1,
touchEnabled : true
});
textFields[i].addEventListener('click', function(e) {
//Check the source id
if (e.source.id - 1 > -1) {
//use your function swapImages(e.source.id). Notice the slightly different parameter since you do not need the complete event.
swapImages(e.source.id);
}
}
function swapImages(id){
//Check the the path variable as you did
var imagePathSplit = (textFields[i-1].image).split('_');
var newImagePath = null;
if(imagePathSplit[1] == "0.png")
newImagePath = imagePathSplit[0] + "_1.png";
else
newImagePath = imagePathSplit[0] + "_0.png";
textFields[i-1].image = newImagePath;
}
This approach lets you use the same event listener for every property.
Please notice that my ids start at 1 and not at 0. This is because I had to implement such a behaviour for images and ImageViews do not accept id=0. My guess is that TextViews don't do it either so you should stick with it. Further notice that you need to decrement the id to get the corresponding object in the textFields Array. Otherwise you would get an out of bounds error.
You should create one more event listener for your NEXT event. Implement it in the same way as the first eventListener. Maybe the code is not perfect because I wrote it from my memory. If there are any questions left feel free to ask in the comments.

Setting JQueryUI's autocomplete to render items in a custom way the first time only

I'm using JQuery UI's Autocomplete to load a list of users into a custom control and display them in the regular suggestion list. On page load, I'm calling this field's search() method to populate the form with some initial data.
The problem is that the on page load event displays the suggestion list, as well as populating the custom control. How can I disable the suggestion list for the first query only?
I've tried monkey-patching various methods, and they either break or do nothing.
Of course, the alternative is setting a timeout on a function call to close it, but this will create an ugly flicker I'd like to avoid.
In the end, I overwrote Autocomplete's _suggest method like so:
suggest = function(items) {
ul = this.menu.element.empty().zIndex( this.element.zIndex() + 1 );
this._renderMenu(ul, items);
this.menu.deactivate();
this.menu.refresh();
/* these four lines are the difference between regular autocomplete and this autocomplete */
if (!this.first)
ul.show();
else
this.first = false;
this._resizeMenu();
args = {
of: this.element
}
ul.position($.extend(args, this.options.position));
if (this.options.autoFocus)
this.menu.next(new $.Event("mouseover"));
/* initialisation*/
field.autocomplete().data('autocomplete').first = true;
field.autocomplete().data('autocomplete')._renderItem = renderItem;
field.autocomplete().data('autocomplete')._suggest = suggest;
It's not the most elegant solution, but it works.

Categories