I want to add a checkbox to the link modal menu. I can’t understand how I should save the changes. If I use the onOk method, it will overwrite the main method. Tried through decorator, but this._. SelectedElement element is not defined yet at this moment.
CKEDITOR.on( 'dialogDefinition', function( ev ) {
var dialogName = ev.data.name;
var dialogDefinition = ev.data.definition;
var link = ev.editor.getSelectedHtml().getHtml();
if ( dialogName === 'link' ) {
var infoTab = dialogDefinition.getContents( 'info' );
var checkbox = {
type: 'checkbox',
id: 'custom',
label: 'Add data attr',
setup: function (data) {
this.allowOnChange = false;
if (data.custom)
this.setValue(data.custom);
this.allowOnChange = true;
},
commit: function (data) {
data.custom = this.getValue()
this.allowOnChange = false;
}
}
infoTab.add(checkbox);
}
function decorator(func) {
return function() {
var attributes = {}
var data = {}
var editor = this.getParentEditor();
this.commitContent(data);
if (data.custom)
attributes["custom-attribute"] = "button";
else
attributes["custom-attribute"] = "";
var element = this._.selectedElement // not init
element.setAttributes(attributes);
func.apply(this, arguments);
};
}
dialogDefinition.onOk = decorator(dialogDefinition.onOk)
});
function decorator(func) {
return function() {
func.apply(this, arguments);
var data = {}
this.commitContent(data);
var editor = this.getParentEditor();
var anchor = editor.getSelection().getSelectedElement()
if (!anchor) {
anchor = document.querySelector('.cke_wysiwyg_frame').contentWindow.getSelection().focusNode
}
if (data.testId) {
anchor.setAttribute('data-test','true')
} else {
anchor.removeAttribute('data-test')
}
};
}
CKEDITOR.on( 'dialogDefinition', function( ev ) {
var dialogName = ev.data.name;
var dialogDefinition = ev.data.definition;
if ( dialogName === 'link' ) {
var infoTab = dialogDefinition.getContents( 'info' );
var checkbox = {
type: 'checkbox',
id: 'testId',
label: 'Test',
setup: function (data) {
this.allowOnChange = false;
var el = ev.editor.getSelectedHtml();
let a = el.$.childNodes[0]
if (a.getAttribute('data-test')){
this.setValue('checked')
}
this.allowOnChange = true;
},
commit: function (data) {
data.testId = this.getValue()
this.allowOnChange = false;
}
}
infoTab.add(checkbox);
dialogDefinition.onOk = decorator(dialogDefinition.onOk)
}
Also allow added attribute in CKeditor config
Related
I am using CKFinder 3 in a Web project as described on the CKFinder Website my problem is that I can't return multiple selected Images. The problem is that when I select multiple Images just the first one is returned.
Is there a way to return multiple files?
var button1 = document.getElementById( 'ckfinder-popup-1' );
var button2 = document.getElementById( 'ckfinder-popup-2' );
button1.onclick = function() {
selectFileWithCKFinder( 'ckfinder-input-1' );
};
button2.onclick = function() {
selectFileWithCKFinder( 'ckfinder-input-2' );
};
function selectFileWithCKFinder( elementId ) {
CKFinder.modal( {
chooseFiles: true,
width: 800,
height: 600,
onInit: function( finder ) {
finder.on( 'files:choose', function( evt ) {
var file = evt.data.files.first();
var output = document.getElementById( elementId );
output.value = file.getUrl();
} );
finder.on( 'file:choose:resizedImage', function( evt ) {
var output = document.getElementById( elementId );
output.value = evt.data.resizedUrl;
} );
}
} );
I have found a way how to do it.
The only bummer is that you can’t resize images.
var button1 = document.getElementById( 'ckfinder-popup-1' );
button1.onclick = function() {
selectFileWithCKFinder( 'ckfinder-input-1' );
};
function selectFileWithCKFinder( elementId ) {
CKFinder.modal( {
chooseFiles: true,
width: 800,
height: 600,
onInit: function( finder ) {
finder.on( 'files:choose', function( evt ) {
var url='';
for(i = 0; i < evt.data.files.models.length ; i++){
var file = evt.data.files.models[i];
var tempurl = file.getUrl();
url +=','+tempurl;
}
var output = document.getElementById( elementId );
output.value = url;
} );
finder.on( 'file:choose:resizedImage', function( evt ) {
var url='';
for(i = 0; i < evt.data.files.models.length ; i++){
var file = evt.data.files.models[i];
var tempurl = file.getUrl();
url +=','+tempurl;
}
var output = document.getElementById( elementId );
output.value = url;
} );
}
} );
}
</script> ```
I found a new problem where when i manipulate the dom using jquery. The dom is not updated.
Here we go.
var PostCard = function($root) {
this.$root = $root;
this.stuff_id = this.$root.data('stuff_id');
this.id = this.$root.data('id');
this.is_owner = this.$root.data('is_owner');
this.$propose_button = null;
this.$favorite_button = null;
this.init();
this.initEvents();
};
PostCard.prototype.init = function () {
this.$propose_button = this.$root.find("." + PostCard.prototype.CSS_CLASSES.PROPOSE_BUTTON);
this.$proposal_box_modal = this.$root.find("." + PostCard.prototype.CSS_CLASSES.PROPOSAL_MODAL);
this.$proposal_box = this.$root.find("." + PostCard.prototype.CSS_CLASSES.PROPOSAL_BOX);
this.$favorite_button = this.$root.find(".post-card-button-favorite");
this.$total_favorite = this.$root.find('.post-card-total-favorite');
this.$image_view_editor = this.$root.find("#" + this.id + "-image-view");
this.image_view_editor = new ImageViewEditor(this.$image_view_editor);
this.proposal_box = new HomeProposalBox(this.$proposal_box);
};
PostCard.prototype.initEvents = function() {
var self =this;
$(document).on("click", "#" + this.id,function(e) {
if(e.target && $(e.target).hasClass('post-card-button-propose') ){
if(self.is_owner ) {
return false;
}
if(CommonLibrary.isGuest()) {
return false;
}
self.$proposal_box_modal.modal("show").load($(this).attr("value"));
} else if(e.target && $(e.target).hasClass('post-card-button-favorite')) {
self.clickFavoriteButton_();
}
});
PostCard.prototype.clickFavoriteButton_ = function() {
this.markFavorite();
};
PostCard.prototype.markFavorite = function() {
this.$favorite_button.addClass('post-card-button-red');
};
When Favorite button is clicked, the clickFavoriteButton() will be trigerred, and markfavorite method will be fired next.
The problem is although this.$favorite_button is updated (the class is added to the variable), the dom in the page is not updated
this only happens to dynamically loaded element, and does not happen to element that has been around since the page is loaded.
The PostCard is created in PostList class
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
var PostList = function($root) {
this.$root = $root;
this.stuff_ids = '';
this.id = $root.data('id');
this.location = $root.data('location');
this.query = '';
this.post_cards = [];
this.$post_list_area = null;
this.permit_retrieve_post = true;
this.init();
this.initEvents();
};
PostList.prototype.SCROLL_VALUE = 95;
PostList.prototype.init = function() {
$.each($(".post-card"), function(index, value) {
this.post_cards.push(new PostCard($(value)));
if(this.stuff_ids === '' ) {
this.stuff_ids += $(value).data('stuff_id');
} else {
this.stuff_ids += "," + $(value).data('stuff_id');
}
}.bind(this));
this.$post_list_area = this.$root.find('.post-list-area');
};
PostList.prototype.initEvents = function() {
$(window).scroll({self:this}, this.retrievePostWhenScroll_);
};
PostList.prototype.retrievePostWhenScroll_ = function(e) {
var self = e.data.self;
var scrollPercentage =
((document.documentElement.scrollTop + document.body.scrollTop) /
(document.documentElement.scrollHeight - document.documentElement.clientHeight) * 100);
if(scrollPercentage > PostList.prototype.SCROLL_VALUE) {
if(self.permit_retrieve_post) {
self.permit_retrieve_post = false;
$.ajax({
url: $("#base-url").val() + "/site/get-more-posts",
type: 'post',
data: {'ids' : self.stuff_ids, query: self.query, location: self.location},
success: function(data) {
var parsedData = JSON.parse(data);
if(parsedData['status'] === 1) {
self.$post_list_area.append(parsedData['view']);
$(parsedData['view']).filter('.post-card').each(function(index, value) {
self.post_cards.push(new PostCard($(value)));
self.stuff_ids += "," + $(value).data('stuff_id');
});
}
self.permit_retrieve_post = true;
},
error : function(data) {
self.permit_retrieve_post = true;
}
});
}
}
};
When you scroll the page, the retrieveWhenScroll method will be fired and PostCard will be dynamically added
So here is my autocomplete functionality:
var selected;
var itemAdded = false;
$('.js-main-search').autocomplete({
minLength: 3,
source: function(request, response) {
$.getJSON('/dashboard/searchDocumentsAndCompanies.do',
{ q: request.term},
function(data) {
if(data.length == 0){
data = [
{name: 'No matches found', resultType: 'COMPANY', noResults: true},
{name: 'No matches found', resultType: 'BRANCHES', noResults: true},
];
}
data.unshift({name: 'Search from documents »', reqQuery: request.term, docSearch:true});
response(data);
});
},
select: function( event, ui ) {
event.preventDefault();
selected = true;
if(ui.item.docSearch && !itemAdded){
$(".textbox.ui-front li:eq(1)").before('<li class="search-category ui-menu-item">Documents</li>');
itemAdded = true;
}
}
});
$('.js-main-search').data("uiAutocomplete").close = function(event) {
if (!selected){
$('.js-main-search').data("uiAutocomplete").close.apply( this, arguments );
}
selected = false;
};
$('.js-main-search').data('uiAutocomplete')._renderItem = function( ul, item ) {
itemAdded = false;
item.value = item.name;
var $el = $( "<li>" ).append(item.value);
if(item.docSearch){
$el.addClass( "search-documents-btn" );
$el.one('click', function (e) {
e.preventDefault();
console.log(ul.children());
});
}
if(!item.noResults && !item.docSearch){
$el.append('<div class="meta">Documents | Company page</div>');
}
$el.appendTo( ul );
return $el;
};
$('.js-main-search').data('uiAutocomplete')._renderMenu = function(ul, items) {
var companiesResults = true;
var branchesResults = true;
var that = this,currentCategory = '';
$.each(items, function(index, item) {
var li;
if (item.resultType != currentCategory && !item.docSearch) {
var categoryTitle = '';
if(item.resultType == 'COMPANY'){
categoryTitle = 'Companies';
companiesResults = false;
} else{
categoryTitle = 'Branches'
branchesResults = false;
}
ul.append('<li class="search-category">'+categoryTitle+'</li>');
currentCategory = item.resultType;
}
li = that._renderItemData(ul, item);
if (item.resultType) {
item.value = item.name;
li.attr('aria-label', item.resultType + ' : '+ item.value);
}
});
if(companiesResults && branchesResults){
ul.append('<li class="search-show-more-btn">Show more</li>');
}
};
When I am starting to enter search keyword sometimes it gives me the following error in console: "Too much recursion", but I don't understand why.
Any suggestions are welcome.
Usually when you get a stack overflow error, it is because you have a recursion for which no exit condition exist or is triggered. Looking at your code, here's the function that causes the problem.
$('.js-main-search').data("uiAutocomplete").close = function (event) {
if (!selected) {
$('.js-main-search').data("uiAutocomplete").close.apply(this, arguments);
}
selected = false;
};
I guess the selected = false; should be inside the if statement before the recursive call like so:
$('.js-main-search').data("uiAutocomplete").close = function (event) {
if (!selected) {
selected = false;
$('.js-main-search').data("uiAutocomplete").close.apply(this, arguments);
}
};
I am using infinite scroll to load posts and tried to integrate a custom like button for every single posts that needs a small jquery script to work. My problem is I added this Jquery directly after the sucess in ajax load posts. But when I load eg the 3. page my jquery script executes twice and on the posts of the 2nd page the lke buttons are not working correctly. How can I handle this? If I dont execute the code after the ajax request and only call this jquery code globally the like buttons do not work in the new loaded posts of the ajax infinite scroll. Maybe I need to stop the sript of before when eg loadin 3. page through the ajax infinite scroll but how? This is my code:
function load_more_posts(selector){
var url = $(selector).attr('href');
var data;
loading = true;
$.ajax({
url: url,
data: data,
success: function( data ) {
var $items = $( '.loading-content .item', data );
$new_anchor = $( selector, data );
$items.addClass('hidden');
if ( $('#cooked-plugin-page .result-section.masonry-layout .loading-content').length ){
$( '.loading-content').isotope( 'insert', $items );
} else {
$( '.loading-content').append($items);
setTimeout(function() {
$items.removeClass('hidden');
}, 200);
}
if($new_anchor.length) {
$(selector).attr('href', $new_anchor.attr('href'));
} else {
$(selector).remove();
}
loading = false;
$('.like-btn').each(function() {
var $button = $(this),
$icon = $button.find('> i'),
likedRecipes = $.cookie('cpLikedRecipes'),
recipeID = $button.attr('data-recipe-id');
cookied = $button.attr('data-cookied');
userLiked = $button.attr('data-userliked');
if ( cookied == 1 && typeof likedRecipes !== 'undefined' && likedRecipes.split(',').indexOf(recipeID) > -1 || userLiked == 1 ) {
$icon.removeClass('fa-heart-o').addClass('fa-heart');
}
});
$('#cooked-plugin-page .like-btn').on('click', function() {
var $button = $(this),
$icon = $button.find('> i'),
$count = $button.find('.like-count'),
count = parseInt($count.text()),
likedRecipes = $.cookie('cpLikedRecipes'),
recipeID = $button.attr('data-recipe-id'),
cookied = $button.attr('data-cookied'),
likeURL = $button.attr('href'),
likeAction;
if ( $icon.hasClass('fa-heart-o') ) {
$icon.removeClass('fa-heart-o').addClass('fa-heart');
count++;
if (cookied == 1){
if ( typeof likedRecipes === 'undefined' ) {
likedRecipes = recipeID;
} else {
likedRecipes = likedRecipes + ',' + recipeID;
}
$.cookie('cpLikedRecipes', likedRecipes, { expires: 365 } );
}
likeAction = 'like';
} else {
$icon.removeClass('fa-heart').addClass('fa-heart-o');
count--;
if (cookied == 1){
if ( typeof likedRecipes === 'undefied' ) {
return false;
}
}
if (cookied == 1){
var likedSplit = likedRecipes.split(','),
recipeIdx = likedSplit.indexOf(recipeID);
if ( recipeIdx > -1 ) {
likedSplit.splice( recipeIdx, 1 );
likedRecipes = likedSplit.join(',');
$.cookie('cpLikedRecipes', likedRecipes, { expires: 365 } );
likeAction = 'dislike';
}
} else {
likeAction = 'dislike';
}
}
$.ajax({
'url' : likeURL,
'data': {
'action' : 'cp_like',
'likeAction': likeAction
},
success: function(data) {
$count.text(data);
}
});
return false;
});
$('#cooked-plugin-page .tab-links a').on('click', function() {
var tab = $(this).attr('href');
if ( !$(this).is('.current') ){
$(this).addClass('current').siblings('.current').removeClass('current');
$('#cooked-plugin-page.fullscreen .tab').removeClass('current');
$(tab).addClass('current');
$win.scrollTop(0);
}
return false;
});
if($('.rating-holder').length) {
$('.rating-holder .rate')
.on('mouseenter', function() {
var $me = $(this);
var $parent = $me.parents('.rating-holder');
var my_index = $me.index();
var rated = $parent.attr('data-rated');
$parent.removeClass(function(index, css) {
return (css.match (/(^|\s)rate-\S+/g) || []).join(' ');
});
$parent.addClass('rate-' + (my_index + 1));
})
.on('mouseleave', function() {
var $me = $(this);
var $parent = $me.parents('.rating-holder');
var my_index = $me.index();
var rated = $parent.attr('data-rated');
$parent.removeClass(function(index, css) {
return (css.match (/(^|\s)rate-\S+/g) || []).join(' ');
});
if(rated !== undefined) {
$parent.addClass('rate-' + rated);
}
})
.on('click', function() {
var $me = $(this);
var $parent = $me.parents('.rating-holder');
var my_index = $me.index();
$('.rating-real-value').val(my_index + 1);
$parent.attr('data-rated', my_index + 1);
$parent.addClass('rate-' + (my_index + 1));
});
}
setTimeout(function() {
masonry();
}, 500);
}
});
}
There's a great plugin for scrolling. He has methods such as bund, unbind, destroy and e.t.c.:
https://github.com/infinite-scroll/infinite-scroll#methods
Using the google chrome Api extension, I have the following code that show notification from JSON. Once notification is show, and when I clicked on it opened multiple tabs url (It's an error). I need to solve that problem because this should open only one tab url, this is the only problem. look the code below:
var timeChange = 1000, jsons = ['JSON_URL'];
updateValue = function() {
var colorStatus = 0;
chrome.storage.local.get(function (dataStorage) {
$.getJSON(jsons+'?'+$.now(), function (data) {
var jLastPost = {'LastNotification':''}, sizePost = (data.results.length - 1), dataLastPost = data.results[0];
totalEntradas = data.totalEntradas ? data.totalEntradas : '';
$.each(data.results, function (k,v) {
if (($.inArray('post-'+v.id, dataStorage.IDs) !== -1) && (v.date_status > 0)) {
colorStatus = 1;
}
});
chrome.browserAction.setBadgeText({'text': totalEntradas.toString()});
if (dataStorage.LastNotification !== dataLastPost.id)
{
jLastPost.LastNotification = dataLastPost.id;
chrome.storage.local.set(jLastPost);
chrome.notifications.create(dataLastPost.id,{
type: 'basic',
title: dataLastPost.titulo,
message: 'Now for you!',
iconUrl: dataLastPost.image
}, function (id) {});
chrome.notifications.onClicked.addListener(function () {
chrome.tabs.create({url: dataLastPost.uri});
});
chrome.notifications.clear(dataLastPost.id, function() {});
return false;
}
});
});
setTimeout(updateValue, timeChange);
}
updateValue();
You are attaching a chrome.notifications.onClicked listener every second when you run updateValue. At a minimum you should move the listener outside of the method.
Something along these lines should work.
var timeChange = 1000, jsons = ['JSON_URL'];
var lastPostUri;
chrome.notifications.onClicked.addListener(function () {
if (lastPostUri) {
chrome.tabs.create({url: lastPostUri});
}
});
updateValue = function() {
var colorStatus = 0;
chrome.storage.local.get(function (dataStorage) {
$.getJSON(jsons+'?'+$.now(), function (data) {
var jLastPost = {'LastNotification':''}, sizePost = (data.results.length - 1), dataLastPost = data.results[0];
totalEntradas = data.totalEntradas ? data.totalEntradas : '';
$.each(data.results, function (k,v) {
if (($.inArray('post-'+v.id, dataStorage.IDs) !== -1) && (v.date_status > 0)) {
colorStatus = 1;
}
});
chrome.browserAction.setBadgeText({'text': totalEntradas.toString()});
if (dataStorage.LastNotification !== dataLastPost.id)
{
jLastPost.LastNotification = dataLastPost.id;
chrome.storage.local.set(jLastPost);
lastPostUri = dataLastPost.uri
chrome.notifications.create(dataLastPost.id,{
type: 'basic',
title: dataLastPost.titulo,
message: 'Now for you!',
iconUrl: dataLastPost.image
}, function (id) {});
chrome.notifications.clear(dataLastPost.id, function() {});
return false;
}
});
});
setTimeout(updateValue, timeChange);
}
updateValue();