Ckeditor custom plugin- populate dialog data from ajax - ckeditor

I have created a custom plugin to tag a list of usernames in ckeditor. The methodology for implementing is to get the data from the ajax controller. The following is the ajax function to get the list of user names.
$org = new VA_Logic_Organization($orgid);
if ($groupid) {
$group = new VA_Logic_Group($groupid);
if ($group->assigntomanager == 1) {
$manager = new VA_Logic_Avatar($group->managerid);
$avatarlist[$group->managerid] = $manager->firstname . ' ' . $manager->lastname;
} else {
$avatarlist = $group->getAvatarListByName($name, $form->hideleveldifference);
}
} else if ($form->defaultassigngroup) {
$group = new VA_Logic_Group($form->defaultassigngroup);
if ($group->assigntomanager == 1) {
$manager = new VA_Logic_Avatar($group->managerid);
$avatarlist[$group->managerid] = $manager->firstname . ' ' . $manager->lastname;
} else {
$avatarlist = $group->getAvatarListByName($name, $form->hideleveldifference);
}
} else {
$avatarlist = $org->getAvatarListByName($name, $form->hideleveldifference);
}
$this->_helper->layout->disableLayout();
$this->_helper->viewRenderer->setNoRender(TRUE);
echo json_encode($avatarlist);
The following is the ckedior pluginname.js.
elements: [
{
type: 'select',
id: 'exam_ID',
label: 'Select Exam',
items :function(element)
{
$.ajax({
type: 'POST',
url: baseurl +"employee/ajax/assignedtoselect/groupid/" ,
contentType: 'application/json; charset=utf-8',
dataType: 'json',
async: false,
});
}
}
]
I need to populate the json data on click of the dialog text box.

Finally found the solution.
The onShow function was very helpful,
The working code for pluginname.js is here
CKEDITOR.dialog.add( 'abbrDialog', function( editor ) {
return {
// Basic properties of the dialog window: title, minimum size.
title: 'Tag Avatars',
minWidth: 250,
minHeight: 100,
// Dialog window contents definition.
contents: [
{
// Definition of the Basic Settings dialog tab (page).
id: 'tab-basic',
label: 'Avatars',
// The tab contents.
elements: [
{
// Text input field for the abbreviation text.
type: 'text',
id: 'avatarid',
label: 'Type an avatar name to tag'
},
]
},
{
// Definition of the Basic Settings dialog tab (page).
id: 'tab-advanced',
label: 'Items/Modules',
// The tab contents.
elements: [
{
// Text input field for the abbreviation text.
type: 'text',
id: 'instanceid',
label: 'Type an item to tag'
},
{
type: 'checkbox',
id: 'checkid',
label: 'check to add link'
}
]
}
// Definition of the Advanced Settings dialog tab (page).
],
onShow: function() {
var assigned_config = {
source: baseurl+"employee/ajax/assignedtoselect/",
select: function(event, ui){
$("#cke_79_textInput").val(ui.item.value);
$("#cke_79_textInput").val(ui.item.id);
window.abbr1 = ui.item.id;
},
change: function (ev, ui) {
if (!ui.item){
$("#cke_79_textInput").val("");
}
}
};
$("#cke_79_textInput").autocomplete(assigned_config);
var ac_config = {
source: baseurl+"employee/module/parentlist/",
select: function(event, ui){
$("#cke_84_textInput").val(ui.item.value);
$("#cke_84_textInput").val(ui.item.id);
window.instanceid = ui.item.id;
},
change: function (ev, ui) {
if (!ui.item){
$("#cke_84_textInput").val("");
}
}
};
$("#cke_84_textInput").autocomplete(ac_config);
},
// This method is invoked once a user clicks the OK button, confirming the dialog.
onOk: function() {
var dialog = this;
if(window.abbr1 === undefined){
var checkid = document.getElementById('cke_88_uiElement');
if (checkid.checked) {
var url = baseurl+ '/employee/module/view/instanceformid/'+instanceid;
abbr = dialog.getValueOf( 'tab-advanced', 'instanceid' );
var inst = '<a target="_blank" href='+url+'>'+abbr+'</a>';
editor.insertHtml(inst);
}
else{
var inst = '\$\[' +instanceid+ '\!\description]';
editor.insertHtml( inst );
}
}
else{
abbr = dialog.getValueOf( 'tab-basic', 'avatarid' );
var url = baseurl + '/employee/avatar/friendsprofilepopup/avatarid/' +abbr1;
var htmlavatar = '<a class="infopopup20" href= '+url+' >'+abbr+ '</a>';
editor.insertHtml( htmlavatar );
}
}
};
});

Related

Summernote custom button with dialog

I want to add a custom button to the Summernote toolbar that opens up a dialog that has a textbox for a URL and several checkboxes for settings. I then want to use the info from the dialog to scrape web pages and do processing on the content. The ultimate goal is to place the scraped content into the editor starting where the cursor is. I've searched and found some code on creating a custom button, but not any solid examples of implementing a dialog. I went through the summernote.js code to see how the Insert Image dialog works and that left me really confused. The test code I've got so far is in the code block, below. Thanks in advance to anyone who can help get me sorted out.
var showModalDialog = function(){
alert("Not Implemented");
};
var AddWiki = function(context) {
var ui = $.summernote.ui;
var button = ui.button({
contents: '<i class="fa fa-plus"/> Add Wiki',
tooltip: "Set a New Wiki",
class: "btn-primary",
click: function() {
showModalDialog();
}
});
return button.render();
};
$(".tw-summernote-instance textarea").summernote({
airMode: false,
dialogsInBody: false,
toolbar: [["mybutton", ["customButton"]]],
buttons: {
customButton: AddWiki
},
callbacks: {
onInit: function(e) {
var o = e.toolbar[0];
jQuery(o)
.find("button:first")
.addClass("btn-primary");
}
}
});
I found a good, simple example of what I wanted to do. Here's the code:
(function(factory) {
/* global define */
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['jquery'], factory);
} else if (typeof module === 'object' && module.exports) {
// Node/CommonJS
module.exports = factory(require('jquery'));
} else {
// Browser globals
factory(window.jQuery);
}
}(function($) {
$.extend($.summernote.plugins, {
'synonym': function(context) {
var self = this;
var ui = $.summernote.ui;
var $editor = context.layoutInfo.editor;
var options = context.options;
context.memo('button.synonym', function() {
return ui.button({
contents: '<i class="fa fa-snowflake-o">',
tooltip: 'Create Synonym',
click: context.createInvokeHandler('synonym.showDialog')
}).render();
});
self.initialize = function() {
var $container = options.dialogsInBody ? $(document.body) : $editor;
var body = '<div class="form-group">' +
'<label>Add Synonyms (comma - , - seperated</label>' +
'<input id="input-synonym" class="form-control" type="text" placeholder="Insert your synonym" />'
'</div>'
var footer = '<button href="#" class="btn btn-primary ext-synonym-btn">OK</button>';
self.$dialog = ui.dialog({
title: 'Create Synonym',
fade: options.dialogsFade,
body: body,
footer: footer
}).render().appendTo($container);
};
// You should remove elements on `initialize`.
self.destroy = function() {
self.$dialog.remove();
self.$dialog = null;
};
self.showDialog = function() {
self
.openDialog()
.then(function(data) {
ui.hideDialog(self.$dialog);
context.invoke('editor.restoreRange');
self.insertToEditor(data);
console.log("dialog returned: ", data)
})
.fail(function() {
context.invoke('editor.restoreRange');
});
};
self.openDialog = function() {
return $.Deferred(function(deferred) {
var $dialogBtn = self.$dialog.find('.ext-synonym-btn');
var $synonymInput = self.$dialog.find('#input-synonym')[0];
ui.onDialogShown(self.$dialog, function() {
context.triggerEvent('dialog.shown');
$dialogBtn
.click(function(event) {
event.preventDefault();
deferred.resolve({
synonym: $synonymInput.value
});
});
});
ui.onDialogHidden(self.$dialog, function() {
$dialogBtn.off('click');
if (deferred.state() === 'pending') {
deferred.reject();
}
});
ui.showDialog(self.$dialog);
});
};
this.insertToEditor = function(data) {
console.log("synonym: " + data.synonym)
var dataArr = data.synonym.split(',');
var restArr = dataArr.slice(1);
var $elem = $('<span>', {
'data-function': "addSynonym",
'data-options': '[' + restArr.join(',').trim() + ']',
'html': $('<span>', {
'text': dataArr[0],
'css': {
backgroundColor: 'yellow'
}
})
});
context.invoke('editor.insertNode', $elem[0]);
};
}
});
}));

Kendo Treeview expand and checkbox not working after new value was passed in from a dropdown list

new to stackoverflow and implementing treeview. I'm having an issue where whenever I select a different value from my dropdown list that would populate my treeview the expand and checkbox is not working anymore. But the first time works.
So I have ajax call that would grab a parameter from a dropdown list to return JSON data to populate my tree. Here's my code. I've been pounding my head for this error and I've also tried some solution in the kendo ui documentation but it just doesn't work. Really need some help. Thank you!
Here's my code:
dataB1 = #Html.Raw(Json.Encode(ViewData["branchList"]));
reloadNewBranch = #Html.Raw(Json.Encode(ViewData["reloadNewBranch"]));
$('#comboNewBranch').kendoAutoComplete({
dataSource: dataB2,
placeholder: "Enter branch name...",
value: reloadNewBranch
});
//Create TreeView
function onChange(e) {
$("body").css("cursor", "progress");
$('#hiddenPackageArray').val('');
document.getElementById("textTestpassId").innerHTML = 'At least one(1) template must be selected.';
$('#treeview').empty();
$.ajax({
url: '#Url.Action("LoadOldBranchTemplates", "Home")',
data: { oldBranchName: $("#comboOldBranch").data("kendoAutoComplete").value() },
dataType: "json"
}).done(function (result, textStatus, jqXHR) {
var viewModel = new kendo.data.HierarchicalDataSource({
data: result,
schema: {
model: {
id: "Id",
hasChildren: true,
children: "Templates"
}
}
});
$("#treeview").kendoTreeView({
loadOnDemand: false,
checkboxes: {
checkChildren: true
},
check: onCheck,
dataSource: viewModel,
dataTextField: ["TestPassName", "DisplayName"]
})
// gathers IDs of checked nodes
function checkedNodeIds(nodes, checkedNodes) {
for (let i = 0; i < nodes.length; i++) {
if (nodes[i].checked) {
checkedNodes.push(nodes[i].Id);
let filtered = checkedNodes.filter(function (listOfId) {
return listOfId != null;
});
$('#hiddenPackageArray').val(filtered);
}
if (nodes[i].hasChildren) {
checkedNodeIds(nodes[i].children.view(), checkedNodes);
}
}
}
// show checked node IDs on datasource change
function onCheck(e) {
console.log("I'm in onSelect function");
var checkedNodes = Array();
var treeView = $("#treeview").data("kendoTreeView");
var message = String();
checkedNodeIds(treeView.dataSource.view(), checkedNodes);
console.log("Checkbox changed :: " + this.text(e.node));
if (checkedNodes.length > 0) {
message = checkedNodes.join(" ");
} else {
message = "No package(s) are selected.";
$('#hiddenPackageArray').val('');
}
$("#result").html(message);
}
$("body").css("cursor", "default");
})
.fail(function (xmlHttpRequest, textStatus, errorThrown) {
$('#mainDiv').append('<p>Status: ' + textStatus + '</p>');
$('#mainDiv').append('<p>Error: ' + errorThrown + '</p>');
$('#mainDiv').append('<p>' + xmlHttpRequest + '</p>');
});
};

knockout validation for array of objects

I have an array of dynamically added objects and I want to validate this array for required fields and numeric values.
I have 3 buttons, one for adding note, another for removing note and one for saving
How to validate every object ?
.. the code:
$(function () {
var initialData = [{
Title: "",
NoteText: "",
Suggestion: "",
MediaTime: ""
}];
var CreateNewNoteModel = function (Notes) {
var self = this;
self.Notes = ko.observableArray(ko.utils.arrayMap(Notes, function (Note) {
return { Title: Note.Title, NoteText: Note.NoteText, Suggestion: Note.Suggestion, MediaTime: Note.MediaTime };};
}));
var i = 1;
self.addNote = function () {
self.Notes.push({
Title: "", NoteText: "", Suggestion: "", MediaTime: ""
});
$('#editor' + i).wysihtml5();
$('#editorB' + i).wysihtml5();
i++;
};
self.removeNote = function (Note) {
self.Notes.remove(Note);
};
self.save = function () {
self.lastSavedJson(JSON.stringify(ko.toJS(self.Notes), null, 2));
var jsondata = self.lastSavedJson();
$.ajax({
url: "/api/Notes/?mid=" + m + "&p=" + p,
cache: false,
type: 'Post',
dataType: 'json',
contentType: 'application/json; charset=utf-8',
data: jsondata,
success: function () {
alert("Success");
document.location.reload(true);
}
});
};
self.lastSavedJson = ko.observable("")
};
ko.applyBindings(new CreateNewNoteModel(initialData));
});
I am using jQuery validate plugin to add validation to knockout-js by using jQuery's validation methods: "$.validator.addMethod" and "$.validator.addClassRules".
Example:
First define your validation methods and css classes. Later on, we add the css classes to your inputs to validate your fields.
function DefineValidationRules() {
$.validator.addMethod("validateNumber", ValidateInteger, "This field is not a number");
$.validator.addMethod("validateRequired", $.validator.methods.required, "This field is required");
$.validator.addMethod("validateMin", $.validator.methods.min, $.format("This number be greater than or equal to {0}"));
$.validator.addMethod("validateMax", $.validator.methods.min, $.format("This number must be less than or equal to {0}"));
$.validator.addMethod("validateMinlength", $.validator.methods.minlength, $.format("This field must contain at least {0} characters"));
$.validator.addMethod("validateRangelength", $.validator.methods.rangelength, $.format("This field must contain between {0} and {1} characters"));
$.validator.addClassRules("validate-number", { validateNumber: true });
$.validator.addClassRules("validate-number-min", { validateNumber: true, validateMin: 1 });
$.validator.addClassRules("validate-required-number-min", { validateRequired: true, validateNumber: true, validateMin: 1 });
$.validator.addClassRules("validate-required", { validateRequired: true });
$.validator.addClassRules("validate-rangelengthmax6", { validateRangelength: [0,6] });
}
DefineValidationRules();
You can also add your own custom validation method:
function ValidateInteger(value) {
//do whatever you want to check
}
Having an input in knockout:
<input class="validate-required validate-number" type="text" data-bind="value: examplefield, valueUpdate: 'afterkeydown', attr: { attrname: 'itsvalue'}" />
Checking on submit:
$("#yoursubmitbutton").on("click", function () {
var formtosubmit = $("#idofyourform");
//check for validation errors
if (isValid(formtosubmit)) {
formtosubmit.submit();
//
// code to proceed to next step
}
});
function isValid(el) {
var $thisform = el;
$thisform.validate({
errorElement: "label",
errorPlacement: function (error, element) {
//eventual different error placing
if (element.attr("name") == "fname" || element.attr("name") == "lname") {
element.css("border", "2px solid red");
error.insertAfter("#lastname");
} else {
error.insertAfter(element);
}
}
});
return $thisform.valid();
}

keep the Ids of selected results of Kendo UI Autocomplete in a hidden input

I wrote this code to use kendo UI autocomplete. I need to show the title of the selected result in the textbox and keep the if in some hidden input, how can I get the id. it seems the select doesn't work.
$("[data-autocomplete]").each(function () {
var luurl = $(this).attr('data-lookupurl');
var thisElemt = $(this);
$(this).kendoAutoComplete({
minLength: 3,
separator: ", ",
dataTextField: "title",
select: function (e) {
var selectedOne = this.dataItem(e.item.Index());
console.log(kendo.stringify(selectedOne));
},
dataSource: new kendo.data.DataSource({
serverFiltering: true,
serverPaging: true,
pageSize: 20,
transport: {
read: luurl,
dataType: "json",
parameterMap: function (data) {
return { title: thisElemt.val() };
},
schema: {
model: {
id: "id",
fields: {
id: { type: "id" },
title: { type: "string" }
}
}
}
}
})
});
});
There is a typo error, you should use: e.item.index() instead of e.item.Index() (index is lowercase).
So the select function would be:
select : function (e) {
var selectedOne = this.dataItem(e.item.index());
console.log(kendo.stringify(selectedOne));
},
and easier way is :
var autocomplete = $("#autoCompleteId").data("kendoAutoComplete");
console.log(autocomplete.listView._dataItems[0]);
you can access to select data item in autocomplete.listView._dataItems[0] object
you can use script
<script>
$(document).ready(function () {
$("#categories").change(function () {
var url = '#Url.Content("~/")' + "Limitations/ThanaByDistrict_SelectedState";
var ddlsource = "#categories";
var ddltarget = "#target";
$.getJSON(url, { Sel_StateName: $(ddlsource).val() }, function (data) {
$(ddltarget).empty();
$(ddltarget).val(data);
});
});
});
</script>
in controller like
// Get selected combox value
public JsonResult ThanaByDistrict_SelectedState ( Guid Sel_StateName )
{
JsonResult result = new JsonResult ( );
objects temp=db . objects . Single ( m => m . ob_guid == Sel_StateName );
result . Data = temp.ob_code;
result . JsonRequestBehavior = JsonRequestBehavior . AllowGet;
return result;
}
For details you can see this LINK

How to dynamically change event sources?

I am using the jQuery FullCalendar plug-in. I want to load initially the calendar with events as an array. I am doing this like:
events: <%= Model.Events %>
or
eventSources: [{
events: <%= Model.Events %>
}]
Both ways work fine. I am using MVC 3.0 and <%= Model.Events %> returns an array of events in JSON format.
I want to use the events array ONLY for the initial loading of the calendar. Later, every times events are needed to be fetched, I want my events to be loaded using the url '/Calendar/Events'.
How can be this implemented?
I tried difference scenarios with addEventSource/removeEventSource in the viewDisplay callback, but nothing worked fine for me.
.fullCalendar( {
eventSources : [ {
url : '/Calendar/Events',
type : 'GET'
} ],
viewDisplay : function( event ) {
// assuming this will point to the full calendar,
// might have to do something silly like
// $( '#myCal' ).fullCalendar( 'refetchEvents' );
this.refetchEvents();
}
} );
I know it's a very old question but I needed this right now. The answer wasn't here but I found it in another question.
Here what is solution.
My primary source of events is this(this is the events source from the default examples of Fullcalendar):
events: function(start, end, callback) {
$.ajax({
type: 'POST',
url: 'myurl',
dataType:'xml',
crossDomain: true,
data: {
// our hypothetical feed requires UNIX timestamps
start: Math.round(start.getTime() / 1000),
end: Math.round(end.getTime() / 1000),
'acc':'2',
},
success: function(doc) {
var events = [];
var allday = null; //Workaround
var Editable = null; //Workaround
$(doc).find('event').each(function()
{
if($(this).attr('allDay') == "false") //Workaround
allday = false; //Workaround
if($(this).attr('allDay') == "true") //Workaround
allday = true; //Workaround
if($(this).attr('editable') == "false") //Workaround
Editable = false; //Workaround
if($(this).attr('editable') == "true") //Workaround
Editable = true; //Workaround
events.push({
id: $(this).attr('id'),
title: $(this).attr('title'),
start: $(this).attr('start'),
end: $(this).attr('end'),
allDay: allday,
editable: Editable
});
});
//calendar.fullCalendar( 'addEventSource', othersources.folgas );
//calendar.fullCalendar( 'addEventSource', othersources.ferias );
//calendar.fullCalendar('refetchEvents');
callback(events);
}
});
}
Now i needed it to add more sources and to do this ouside the calendar (next to the date variables from fullcalendar examples) i made a variable like the code above, but with ajax calls similar to my primary: )
var othersources = {
anothersource: {
events: function(start, end, callback) {
$.ajax({
type: 'POST',
url: 'myurl',
data: {
// our hypothetical feed requires UNIX timestamps
start: Math.round(start.getTime() / 1000),
end: Math.round(end.getTime() / 1000),
'acc':'7',
},
success: function(doc) {
var events = [];
var allday = null; //Workaround
var Editable = null; //Workaround
$(doc).find('event').each(function()
{
if($(this).attr('allDay') == "false") //Workaround
allday = false; //Workaround
if($(this).attr('allDay') == "true") //Workaround
allday = true; //Workaround
if($(this).attr('editable') == "false") //Workaround
Editable = false; //Workaround
if($(this).attr('editable') == "true") //Workaround
Editable = true; //Workaround
events.push({
id: $(this).attr('id'),
title: $(this).attr('title'),
start: $(this).attr('start'),
end: $(this).attr('end'),
allDay: allday,
editable: Editable
});
});
callback(events); //notice this
}
});
},
cache: true,
//error: function() { alert('something broke with courses...'); },
color: 'green', //events color and stuff
textColor: 'white',
//className: 'course'
}
}
Now, he build diffrent sources and use like this both...
eventSources: [ othersources.anothersource ],
viewDisplay: function(view) {
if (view.name == 'month'){
calendar.fullCalendar( 'addEventSource', othersources.anothersource );
//calendar.fullCalendar('refetchEvents');
//Notice i'm not doing the refetch events. And its working for me. but i'm calling thi elsewhere, every time i make an action. So you must figure it out ;)
}
Link to above solution
And another way i found on github.
Basically the problem was that I can't change data parameters after calendar initialization. For events this worked:
events: {
url : '',
type: 'POST',
data: function () {
return {
action: 'view',
search_text: search_text
};
},
error: function() {
alert('there was an error while fetching events!');
},
color: '#31b0d5', // a non-ajax option
textColor: '#fff;', // a non-ajax option
},
for resources it didnt so I had to make like that:
resources: function(callback) {
var view = $("#calendar").fullCalendar("getView");
$.ajax({
url: "",
type: 'POST',
dataType: "json",
cache: false,
data: {
start : view.start.format(),
end : view.end.format(),
timezone : view.options.timezone,
action : 'projects_employees',
search_text: search_text
}
}).then(function(resources) {
callback(resources);
})
},
Simple ways like that do not work cuz are static and couldn't be changed after init:
events: {
url: '',
type: 'POST',
data: {
action: 'view',
search_text: search_text
}
},
resources: {
url: '',
type: 'POST',
data: {
action: 'projects_employees',
search_text: search_text
}
}
Here is the github link. Replied by peon501.
After to many try, i did solve my problem with use first part (stackoverflow) codes. The key for me defiying eventSource with "var" key and use it like this
//...
eventSources: [ othersources.anothersource ] ,
//...
I have collected all the data in a php file the way I want it. And the output of this page was a javascript with this
header('Content-Type: text/javascript');
$fromDB ="";
$sources = "sources = [";
foreach ($events as $value) { // value is source name
$fromDB .= "var $value = {
url: path + 'fetchEvents.php',
method: 'GET',
extraParams: {
value: $value,
code: new URLSearchParams(window.location.search).get('code'),
},
failure: function(error) {
console.log(error);
Swal.fire('Error!', '', 'error');
},
};
";
$sources .= $value. " ";
}
$sources .= " ];";
// this $sources give me
// sources = [anothersource ,othersource ,anothersource2 ];
This make like this
var anothersource = {
url: path + 'fetchEvents.php',
method: 'GET',
extraParams: {
value: $value,
code: new URLSearchParams(window.location.search).get('code'),
},
failure: function(error) {
console.log(error);
Swal.fire('Error!', '', 'error');
},
};
var othersource = {
url: path + 'fetchEvents.php',
method: 'GET',
extraParams: {
value: $value,
code: new URLSearchParams(window.location.search).get('code'),
},
failure: function(error) {
console.log(error);
Swal.fire('Error!', '', 'error');
},
};
var anothersource2 = {
url: path + 'fetchEvents.php',
method: 'GET',
extraParams: {
value: $value,
code: new URLSearchParams(window.location.search).get('code'),
},
failure: function(error) {
console.log(error);
Swal.fire('Error!', '', 'error');
},
};
sources = [anothersource ,othersource ,anothersource2 ];
.fullCalendar( {
eventSources : sources , // here, we use dynamic eventsources
viewDisplay : function( event ) {
// assuming this will point to the full calendar,
// might have to do something silly like
// $( '#myCal' ).fullCalendar( 'refetchEvents' );
this.refetchEvents();
}
} );
I added the main javascript file, which will do all the operations, at the bottom of this php file.
//...
$file = "my/fullcalender/initjavascript/file.js"
file_get_contents($file) . PHP_EOL;
//...
This code opens the javascript file in the $file path and takes whatever is in it and adds it to this file.
I hope that will be useful.

Resources