How can we add a custom dropdown in tiny mce using yii2 - yii2

I want to add a custom drop down in tiny mce editor, I am using yii framework and using a yii plugin to integrate the editor

You haven't added any details in your question but since you are a new
bee here and SO Code of Conduct
has been revised to be more nice and humble towards newcomers, so I am
adding the answer for you, do go through the How to Ask a
Question? before posting a
question next time.
You can add the dropdown in the TinyMCE using setup option which takes a callback function with a parameter editor which holds the editor instance, and then you need to call the editor.addButton(label, options) with the options to create the custom dropdown button.
As you have not added any details in the question like what are the options that you are going to display in the dropdown so, I will assume here as usernames from the database in the variable $users.
Steps to Implement
First, we will convert $users array to js array by using yii\helpers\Json::encode().
Iterate that array to create the drop-down options with onclick event to insert the content to the editor.
Use editor.addButton('users',options) to create a button of type dropdown with label users to be later used when initializing the editor toolbar buttons.
Add the following code on top of the view
$usersList = \yii\helpers\Json::encode($users);
$tinyMCECallback = <<< JS
function (editor) {
let usersList = $usersList;
let options = [];
//iterate the user array and create the options with text and
//onclick event to insert the content on click to the editor
$.each(usersList, function(label, mapping) {
options.push({
text: label,
onclick: function() { tinymce.activeEditor.insertContent(label); }
});
});
//add the dropdown button to the editor
editor.addButton('users', {
type: 'menubutton',
text: 'Users',
icon: false,
menu: options
});
}
JS;
Now all you need to do is to pass the $tinyMCECallback to the setup option of the tinyMCE widget, if you are using the active form you code should be like below.
Note: Don't forget to add the users label of the button to the toolbar options, or if you change it in the javascript code change it accordingly in the editor toolbar options otherwise it won't show up
<?php
echo $form->field(
$model, 'body'
)->widget(
TinyMce::class, [
'options' => ['rows' => 10],
'language' => 'en',
'clientOptions' => [
'menubar' => false,
'statusbar' => false,
'toolbar' => "undo redo | users",
'setup' => new \yii\web\JsExpression($tinyMCECallback),
],
]
);
?>

Related

How to get kendo grid dropdownchange event for MVC

I have used MVC kendo grid and I have bind the dropdown to grid. Now I have to get the dropdownchange event to populate other grid items by using dropdown selection.
columns.ForeignKey(c => c.CountryID, (SelectList)ViewBag.Countries).Title("Select Country");
$("#ddlTables").change(function () {
//You will get change event here
//Add debugger here and see
//Do your code here
});
columns.ForeignKey(c => c.CountryID, (SelectList)ViewBag.Countries,new {#id = "ddlCountry"}).Title("Select Country");
Here is the code replace this with your code and try to do your stuff and if still facing issue let me know
You can do it using an editor template as follows.
change the column as follows
columns.Bound(c => c.CountryID).Title("Country").EditorTemplateName("Countries").Width(300);
after that create a partial view inside views/shared/EditorTemplates with name Countries as follows
#using System.Collections
#(Html.Kendo().DropDownList()
.DataValueField("COUNTRYNAME")
.DataTextField("COUNTRYNAME")
.Name("CountryID")
.BindTo((IEnumerable)ViewBag.Countries)
.OptionLabel("Select Country")
.Filter(FilterType.Contains)
.Events(e =>
{
e.Change("CountryChange");
})
)
After this you can write jquery as follows
<script>
function CountryChange()
{
//You will get change event here
}

Wordpress: programmatically create sub menu for frontend

I'd like to write a wordpress-plugin, where you can add a page.
If you submit the page it should also create a submenu under the menu "Teams".
Until now I can create a page through my code, but not the submenu.
I tried different functions I found on google, but nothing will work.
Does anyone know a function or a script that will help?
Yes sure, use the following as a sample to get you going. The clause to check if you are in the right menu may need altering or deleting if you don't have multiple menu objects defined.
menu_item_parent is vital and that is the parent item uid. find that by viewing your front end source code. You should find that each menu item inserted via WP menu creating functions inserts the unique items id.
// add a sub menu dynamically via code!
function aj_add_menu_item( $items, $args ) {
// check we are in the right menu
if( $args -> theme_location =="primary" ) {
$new_links = array();
// Create a nav_menu_item object
$newItem = array(
'title' => "Offers",
'menu_item_parent' => 71,
'ID' => 'loginout',
'db_id' => '12312332', // something random
'url' => "offers",
'classes' => array( 'menu-item' )
);
$items[] = (object) $newItem; // add to end of existing object.
menu_item_parent value will ensure it goes in right place
return $items;
}else{
return $items;
}
}
add_filter( 'wp_nav_menu_objects', 'aj_add_menu_item', 10, 2 );

How to add a link in MediaWiki VisualEditor Toolbar?

I`m trying to insert a custom link to a special page in VisualEditor toolbar. See the image below.
See Image
I googled a lot but without success. Someone please give a path...
My answer is based on the following resources:
MediaWiki core JS doc (ooui-js)
VisualEditor JS doc (+ reading code of both repositories used for VE, mediawiki/extension/VisualEditor and VisualEditor)
Also, I'm pretty sure, that there is no documented way of adding a tool to the toolbar in VE, as far as I know. Although it's possible to add a tool to a group, which is already added, mostly used for the "Insert" tool group, like in Syntaxhighlight_GeSHi). There is, probably, a much easier or "better" way of doing this :)
First, VisualEditor provides a way to load additional modules (called plugins) when the main part of VE loads (mostly, when you click the "Edit" button). The modules needs to be registered via the global variable $wgVisualEditorPluginModules (or the equivalent in extension.json, if you're using the new extension registration). In your extension registration file, you should initialize a module (with your required script files to add the tool) and add it as a VE plugin.
Example PHP (old extension registration via PHP files):
// other setup...
$wgResourceModules['ext.extName.visualeditor'] = array(
'localBasePath' => __DIR__,
'remoteExtPath' => 'extName'
'dependencies' => array(
'ext.visualEditor.mwcore',
),
'scripts' => array(
'javascripts/ve.ui.ExtNameTool.js',
),
'messages' => array(
'extname-ve-toolname',
),
);
$wgVisualEditorPluginModules[] = 'ext.extName.visualeditor';
// other setup...
extension.json (new JSON-based extension registration):
// other setup...
"ResourceModules": {
"ext.geshi.visualEditor": {
"scripts": [
"javascripts/ve.ui.ExtNameTool.js"
],
"dependencies": [
"ext.visualEditor.mwcore"
],
"messages": [
"extname-ve-toolname"
]
}
},
"VisualEditorPluginModules": [
"ext.extName.visualeditor"
],
// other setup...
Now, if VE starts, it will load your module, named ext.extName.visualeditor in this example, with the script ve.ui.ExtNameTool.js. In this script, you can now do, what ever you want. As an example, this is a way to add a new module to the end of the toolgroup list in the toolbar:
Example of ve.ui.ExtNameTool.js:
( function () {
// create a new class, which will inherit ve.ui.Tool,
// which represents one tool
ve.ui.extNameTool = function extNameTool( toolGroup, config ) {
// parent constructor
ve.ui.extNameTool.super.apply( this, arguments );
// the tool should be enabled by default, enable it
this.setDisabled( false );
}
// inherit ve.ui.Tool
OO.inheritClass( ve.ui.extNameTool, ve.ui.Tool );
// every tool needs at least a name, or an icon
// (with the static property icon)
ve.ui.extNameTool.static.name = 'extname';
// don't add the tool to a named group automatically
ve.ui.extNameTool.static.autoAddToGroup = false;
// prevent this tool to be added to a catch-all group (*),
although this tool isn't added to a group
ve.ui.extNameTool.static.autoAddToCatchall = false;
// the title of the group (it's a message key,
// which should be added to the extensions i18n
// en.json file to be translateable)
// can be a string, too
ve.ui.extNameTool.static.title =
OO.ui.deferMsg( 'extname-ve-toolname' );
// onSelect is the handler for a click on the tool
ve.ui.extNameTool.prototype.onSelect = function () {
// show an alert box only, but you can do anything
alert( 'Hello' );
this.setActive( false );
}
// needs to be overwritten, but does nothing so far
ve.ui.extNameTool.prototype.onUpdateState = function () {
ve.ui.extNameTool.super.prototype.onUpdateState.apply( this, arguments );
}
// the tool needs to be registered to the toolFactory
// of the toolbar to be reachable with the given name
ve.ui.toolFactory.register( ve.ui.extNameTool );
// add this tool to the toolbar
ve.init.mw.Target.static.toolbarGroups.push( {
// this will create a new toolgroup with the tools
// named in this include directive. The naem is the name given
// in the static property of the tool
include: [ 'extname' ]
} );
} )();
After installing the extension in your LocalSettings.php and starting VE, you should see a new tool in the toolbar with the given name. Clicking it will show an alert box with content "Hello". Like written in the inline comments: In the click handler (onSelect) you can do whatever you want, e.g. open a link in a new tab, e.g. to a Special page. To get the link to a special page I would suggest to use mw.Title to get a localized namespace. For example:
var relativeUrl = mw.Title.newFromText( 'RecentChanges', -1 ).getUrl();
The first parameter of mw.Title.newFromText() is the name of the page, the second parameter is the ID of the namespace (-1 is the default for special pages and should always work).
I hope that helps!
I am not sure I understand your question entirely. It is as simple as selecting some text, clicking the chain icon, then clicking the External Link tab and pasting your link there.

Handling events from a Kendo MVC Grid's PopUp editor window

I have a Kendo MVC grid that I am creating with the Html.Kendo().Grid helper. When the PopUp editor window opens, I want to catch the event and run a bit of javascript. When I configure a normal kendo window with .Events, the events fire properly and my function runs. However, when I code the .Events property on the .Editable.Window of the grid, the events do not fire.
#(Html.Kendo().Grid<FooRecord>()
.Name("cFooGrid")
.Columns(c =>
{
c.Bound(f => f.Foo);
c.Bound(f => f.Bar);
c.Bound(f => f.Bas);
c.Command(a => a.Edit());
})
.Editable(e => e
.Mode(GridEditMode.PopUp)
.Window(w => w.Events(v => v.Open("OnEditStart").Activate(#<text>function () {console.log("EditWindow.Activate")}</text>)))
)
.ToolBar(t =>
{
t.Create();
})
.DataSource(ds => ds
.Ajax()
.Create(r => r.Action("UpdateIndex", "Home"))
.Read(r => r.Action("IndexList", "Home"))
.Update(u => u.Action("UpdateIndex", "Home"))
.Model( m => {
m.Id(f => f.Foo);
})
)
)
When I review the generated code in Chrome's developer tools, the window is generated without the Activate or Open features:
jQuery(function(){jQuery("#cFooGrid").kendoGrid({"columns":[{"title":"Foo Key","field":"Foo","encoded":true,"editor":null},{"title":"Bar Field","field":"Bar","encoded":true,"editor":null},{"title":"Bas Value","field":"Bas","encoded":true,"editor":null},{"command":[{"name":"edit","buttonType":"ImageAndText","text":"Edit"}]}],"scrollable":false,"editable":{"confirmation":"Are you sure you want to delete this record?","confirmDelete":"Delete","cancelDelete":"Cancel","mode":"popup","template":"\u003cdiv class=\"editor-label\"\u003e\u003clabel for=\"Foo\"\u003eFoo Key\u003c/label\u003e\u003c/div\u003e\u003cdiv class=\"editor-field\"\u003e\u003cinput class=\"k-textbox\" id=\"Foo\" name=\"Foo\" /\u003e\u003cspan class=\"field-validation-valid\" data-valmsg-for=\"Foo\" data-valmsg-replace=\"true\"\u003e\u003c/span\u003e\u003c/div\u003e\u003cdiv class=\"editor-label\"\u003e\u003clabel for=\"Bar\"\u003eBar Field\u003c/label\u003e\u003c/div\u003e\u003cdiv class=\"editor-field\"\u003e\u003cinput class=\"k-textbox\" data-val=\"true\" data-val-maxlength=\"The field Bar Field must be a string or array type with a maximum length of \u0026\\#39;20\u0026\\#39;.\" data-val-maxlength-max=\"20\" id=\"Bar\" name=\"Bar\" /\u003e\u003cspan class=\"field-validation-valid\" data-valmsg-for=\"Bar\" data-valmsg-replace=\"true\"\u003e\u003c/span\u003e\u003c/div\u003e\u003cdiv class=\"editor-label\"\u003e\u003clabel for=\"Bas\"\u003eBas Value\u003c/label\u003e\u003c/div\u003e\u003cdiv class=\"editor-field\"\u003e\u003cinput class=\"k-textbox\" data-val=\"true\" data-val-required=\"The Bas Value field is required.\" id=\"Bas\" name=\"Bas\" /\u003e\u003cspan class=\"field-validation-valid\" data-valmsg-for=\"Bas\" data-valmsg-replace=\"true\"\u003e\u003c/span\u003e\u003c/div\u003e","window":{"title":"Edit","modal":true,"draggable":true,"resizable":false},"create":true,"update":true,"destroy":true},"toolbar":{"command":[{"name":null,"buttonType":"ImageAndText","text":"Add new record"}]},"dataSource":{"type":(function(){if(kendo.data.transports['aspnetmvc-ajax']){return 'aspnetmvc-ajax';} else{throw new Error('The kendo.aspnetmvc.min.js script is not included.');}})(),"transport":{"read":{"url":"/Home/IndexList"},"prefix":"","update":{"url":"/Home/UpdateIndex"},"create":{"url":"/Home/UpdateIndex"}},"serverPaging":true,"serverSorting":true,"serverFiltering":true,"serverGrouping":true,"serverAggregates":true,"filter":[],"schema":{"data":"Data","total":"Total","errors":"Errors","model":{"id":"Foo","fields":{"Foo":{"type":"string"},"Bar":{"type":"string"},"Bas":{"type":"string"}}}}}});});
Or, more specifically:
"window":{"title":"Edit","modal":true,"draggable":true,"resizable":false}
I would expect that the window would be generated with Activate: and Open: parameters, but they don't show up. Can anyone give me a pointer as to whether this just isn't supported or I am doing something wrong?
Edit:
So in order to capture the events as above, there are two steps:
Add this to the grid definition (remove the Window .Events)
.Events(e => e.Edit("OnEditStart"))
Then add a javascript function like this to the page.
function OnEditStart(pEvent) {
var editWindow = pEvent.container.data('kendoWindow');
editWindow.bind('activate', function () {
console.log('Edit start event fired');
});
}
NOTE: There does not appear to be any way to capture the open event since this event is fired on the window before the edit event on the grid.
The "events" of the kendo grid popup are not honoured/serialized (at least not the last time I tested this back in 2014) and so you should use the grid's Edit event to control the "Pop Up" window events
So within your grid add this:
.Events(event => event.Edit("onEdit"))
.//other grid settings here.
Then add a javascript function like this:
function onEdit(e) {
//get window object
var kendoWindow = e.container.data("kendoWindow");
kendoWindow.setOptions({
title: "I have a custom Title"
//do stuff in here
});
}
Then you can apply what ever functions you want to the window via javascript.
I do something similar to this to resize the pop up editor so it takes up 80% of the screen size regardless of the display/device.
If you have something more specific you are after then I will update my answer accordingly.
edit: If you want you can refer to this post from Telerik's own forums which is what I used when I first encountered this issue back in mid 2014.
Kendo Pop Up Editor not firing off applied events

Kendo MVC - Persist and load grid buttons

I am trying to persist my grid data and following this example.
This works very well for me but the problem is I am having Excel Import button in my grid and after loading the persisted state of the grid, the Excel Export button is disappeared.
This is my code for the grid (data persisting code is not here, it is same as the above example).
#(Html.Kendo().Grid<DtoTaskExtended>()
.Name("AdraKendoGrid")
.TableHtmlAttributes(CodeTaskKendoGrid.GetTableHtmlAttributes())
.RowAction(CodeTaskKendoGrid.GridPerRowAction)
.CellAction(CodeTaskKendoGrid.GridCellsConfigurator)
.Columns(CodeTaskKendoGrid.ColumnsConfigurator)
.ToolBar(tools => tools.Excel())
.Pageable(pager => pager.PageSizes(new int[] { 15, 50, 100, 500 })
.Info(true)
.Messages(message => message.Display("{0} - {1} " + Strings.of + "{2} " + Strings.items))
.Messages(message => message.ItemsPerPage(Strings.itemsPerPage))
.Messages(message => message.Empty(Strings.noItemsToDisplay)))
.Sortable()
.Groupable(gr => gr.Messages(message => message.Empty(Strings.kendoGroupMsg)))
.Excel(excel => excel
.AllPages(true)
.FileName("Task Grid Export.xlsx")
.Filterable(true)
.ProxyURL(Url.Action("Excel_Export_Save", "Task")) //.ForceProxy(true)
)
.Filterable()
.Reorderable(reorder => reorder.Columns(true))
.Resizable(r => r.Columns(true))
.ColumnMenu()
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(10)
.Read(read => read.Action("GetTaskResult", "Task")))
.ClientDetailTemplateId("client-template")
)
Data is saved and loaded correctly, but the grid buttons (Export to Excel) button is disappeared after loading data.
How do I persist the button of the gird?
Thank you.
Hi I have a same issue like you and i solve my problem like this
function load() {
var grid = $('#gr').data("kendoGrid");
var toolBar = $("#grid .k-grid-toolbar").html();
var options = localStorage["kendo-grid-options-log"];
if (options) {
grid.setOptions(JSON.parse(options));
$("#grid .k-grid-toolbar").html(toolBar);
$("#grid .k-grid-toolbar").addClass("k-grid-top");
}
}
There is a limitation for making the toolbar persistent. A note about it from the kendo docs:
An important limitation when using the setOptions method in combination with the MVC wrappers is that any toolbar or header server templates (razor syntax #) will be lost and the layout will become incorrect once the method is invoked. Those options cannot be persisted because there is no JavaScript equivalent option for them since they contain server side logic. Consider using JavaScript initialization (instead of the MVC wrapper). An alternative is to specify the same option with the JavaScript equivalent.
Here's a possible solution:
Persist state issues
I'm not a developer, but ran across the same problem with using javascript. I had to put the entire template code in the grid options, instead of pointing to an HTML template.
I hope that points you in the right direction.
After a long research I was able to find a real and workable solution:
https://github.com/telerik/ui-for-aspnet-mvc-examples/blob/master/grid/grid-preserve-server-toolbar-template-after-set-options/GridPerserveToolbarServerTemplate/Views/Home/Index.cshtml
You need to add the following code to your View:
Razor:
#helper ToolbarTemplate() {
<a class="k-button k-button-icontext k-grid-save-changes" href="javascript:void(0)"><span class="k-icon k-update"></span>Save changes</a>
<a class="k-button k-button-icontext k-grid-cancel-changes" href="javascript:void(0)"><span class="k-icon k-cancel"></span>Cancel changes</a>
}
<script type="text/x-kendo-template" id="toolbarTemplate">
#Html.Raw(#ToolbarTemplate().ToHtmlString().Replace("#", "\\#").Replace("</scr", "<\\/scr"))
</script>
JavaScript:
<script>
//Here you define the ID of your grid
var grid = $("#grid").data("kendoGrid");
//Here you get the local settings for your case
var options = localStorage["settings"];
//To verify if there is anything stored
if (options) {
//To parse the result
var parsedOptions = JSON.parse(options);
//To display the toolbar
parsedOptions.toolbar = [
{ template: $("#toolbarTemplate").html() }
];
//To set the stored changes
grid.setOptions(parsedOptions);
}
</script>
What is the trick?
You need to get code generated the first time before saving the state (you can get it with inspect element).
And add it to the ToolbarTemplate(), after that the toolbar is going to be stored too.
Also, in the above link you can read more about headers if you want to stored them too, it will be a similar code.
The code that I showed it's fully tested and it's working 100% of cases.
If you a doubt of why this is happening, as far as I know it's related to the fact that the Toolbar is created on the server side while the states are done on the client side.