MediaWiki Extension question / suggestion - mediawiki

Complete beginner here. I want to create a new tab on each page that has a custom action. When clicked, it takes you to a new page which has custom HTML on it along with the text or the original article.
So far I could create a new Tab and could give a custom action mycustomaction to it. I am pasting what I did so far here. Please let me know if I am using the correct hooks etc. and what is a better way to achieve this basic functionality.
So far with their docs I have done this:
#Hook for Tab
$wgHooks['SkinTemplateContentActions'][] = 'myTab';
#Callback
function myTab( $content_actions) {
global $wgTitle;
$content_actions['0'] = array(
'text' => 'my custom label',
'href' => $wgTitle->getFullURL( 'action=mycustomaction' ),
);
return true;
}
#new action hook
$wgHooks['UnknownAction'][] = 'mycustomaction';
#callback
function mycustomaction($action, $article) {
echo $action;
return true;
}
This gives me error:
No such action
The action specified by the URL is invalid. You might have mistyped the URL, or followed an incorrect link. This might also indicate a bug in the software used by yourplugin

What I was doing wrong:
$content_actions[‘0’] should simply be $content_actions[] (minor nitpick)
$content_actions is passed-by-reference, it should be function myTab( &$content_actions ) {}
mycustomaction() should do something along the lines of
if ( $action == ‘mycustomaction’ ) {
do stuff; return false;
}
else {
return true;
}
It should use $wgOut->addHTML() instead of echo
Thanks a lot everyone for your help!

Related

Lightswitch html client override default save button

I want to be able to override the default save button on the html client however i cant seem to find the control to do so. I want to write some validation behind it and allow the user to select an option but I just cant seem to find it.
I know the silverlight client you can override it but just cant seem to override it in the html client.
thanks
It's achieved using beforeApplyChanges.
example: (Please excuse any typos/syntax errors, you get the rough idea!)
myapp.AddEditScreen.beforeApplyChanges = function (screen) {
switch (screen.Property_SavingStatus) {
case 'Not Saving':
setTimeout(function () {
// Override Save -> toggle SavingStatus -> Call Save again
SaveMyChangesMyWay();
screen.Property_SavingStatus = 'Commit';
myapp.commitChanges(); // Or Discard or Apply.
}, 500);
return false; // Cancel save changes request
break;
case 'Apply':
return true;
break;
default:
};

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.

trigger active form validation manually before submit

is it possible to call the active form validation programmatically via javascript? I need to call the validation procedure before doing some ajax operations.
Guess I'm a bit late with a reply here but I just had the same question and the solution by soju did not work for me either.
So I looked a bit deeper into the JS-code of ActiveForm and found that it appears to monitor the status of each field in a variable and if the field is "untouched" the validation isn't triggered, unless submitting the actual form. So I changed my call to this:
var $form = $("#my-form"),
data = $form.data("yiiActiveForm");
$.each(data.attributes, function() {
this.status = 3;
});
$form.yiiActiveForm("validate");
This now appears to be working as I expect.
We can achieve that by merging #BlueZed and #S Rana's answer.
You can write below script, so we can check that if form has any error in it then form will not submit (Even It will work for tabular (wizards) like form ).
var $form = $("#form"),
data = $form.data("yiiActiveForm");
$.each(data.attributes, function() {
this.status = 3;
});
$form.yiiActiveForm("validate");
if ($("#form").find(".has-error").length) {
return false;
}
Thanks blue zed,
but before this -
to append form field, u need to do this stuff...
// your input
$inputData = $form->field($model,"prductName");
// this remove next line & convert double quotes to single quotes
$newInputData= trim(preg_replace('/\s+/', ' ',str_replace('"',"'", $inputData)));
// then append like this
$("#table").append("'.$newInputData.'");
// this worked for me along with blue zend solution like this below
$this->registerJs('
$(document).on("click","input[type=text]",function(){
var $form = $("#w0"),
data = $form.data("yiiActiveForm");
$.each(data.attributes, function() {
this.status = 3;
});
$form.yiiActiveForm("validate");
});
');
Yes it is possible, you should try this :
$('#form-id').yiiActiveForm('validate');
this is worked for me
$this->registerJs( "
$('body').on('beforeSubmit', 'form#product-form', function () {
var form = $(this);
// return false if form still have some validation errors
if (form.find('.has-error').length) {
return false;
}
// submit form
$.ajax({
url: form.attr('action'),
type: 'post',
data: form.serialize(),
success: function (response) {
}
});
return false;
}); ");
The validation is activated when submitting the form. Thus, this will work:
$form.data('yiiActiveForm').submitting = true;
$form.yiiActiveForm('validate', false);
The second argument to validate is called forceValidate.
To validate manually from javascript, you should place following code to end of form submit event.
return $('#your-form-id').yiiActiveForm('validate');
For novice users,
$('#your-form-id').submit(function () {
return $('#your-form-id').yiiActiveForm('validate');
});
Also note that you should specify form id on ActiveForm like below
<?php $form = ActiveForm::begin(['id' => 'd4d-hub-form']); ?>
I had the same issue. And the are no clearly solution in official documentation and I don't know why any solution on Stackoverflow does not work for me. May be in the different versions of yii2 there is different ways to do that. I have spent a lot of time to find solution. In my case I have triggered validation for individual input on the form:
$('#form-id').data('yiiActiveForm').submitting = false;
$('#form-id').yiiActiveForm('validateAttribute', 'input-id'); //this will triger validation for input with id 'input-id'
$('#form-id').yiiActiveForm('validateAttribute', 'other-input-id'); //this will triger validation for input with id 'other-input-id'
please notice second parameter of function yiiActiveForm() it is not selector and it is not name of attribute it is id of input of attribute!!!
Try this
$("#form-id").data('yiiActiveForm').submitting = true;
$("#form-id").yiiActiveForm('validate');
it will show validation error if any field is not valid.
Also if all fields are validate then it will submit the request

MvxTabsFragmentActivity - Remove tabs

Is there any way to remove tabs from an MvxTabsFragmentActivity-inherited class? I mean, currently there's only AddTab<T>() method for adding tabs. But, what if I want to remove tabs?
TIA,
Pap
No - MvxTabsFragmentActivity doesn't provide any RemoveTab functionality currently.
The source for this activity is https://github.com/MvvmCross/MvvmCross/blob/v3.1/Cirrious/Cirrious.MvvmCross.Droid.Fragging/MvxTabsFragmentActivity.cs - you should be able to use this as a starting point for your own needs.
UPDATE:
After following #Stuart's advice and-as I mentioned in my comment below-I added the source code for the MvxTabsFragmentActivity class to my project and added the following method-to remove all tabs-which was all I wanted:
public void RemoveAllTabs()
{
// First, detach the curent tab using SupportFragmentManager object.
if (_currentTab != null)
{
var tag = _currentTab.CachedFragment.Tag;
_currentTab.CachedFragment = SupportFragmentManager.FindFragmentByTag( tag );
if (_currentTab.CachedFragment != null && !_currentTab.CachedFragment.IsDetached)
{
var ft = SupportFragmentManager.BeginTransaction();
ft.Detach( _currentTab.CachedFragment );
ft.Commit();
SupportFragmentManager.ExecutePendingTransactions();
}
}
// Second remove all tabs from TabHost object
if (_tabHost != null)
_tabHost.ClearAllTabs();
// And lastly, empty our _lookup table(actually a Dictionary).
_lookup.Clear();
_currentTab = null; // Clear the current tab
}
I guess if someone wanted to have a specific tab removed he could use the SupportFragmentManager object and have something like this:
public void RemoveTab( string tag )
{
var fragment = SupportFragmentManager.FindFragmentByTag( tag );
if (fragment != null && ! fragment.IsDetached)
{
var ft = SupportFragmentManager.BeginTransaction();
ft.Detach( fragment );
ft.Commit();
SupportFragmentManager.ExecutePendingTransactions();
//_tabHost.TabWidget.RemoveView( fragment.View ); // Neither this..
//_tabHost.RemoveView( fragment.View ); // .. or this removed the tab from the Tabhost.
}
}
However, although the above code was successful at removing the fragment/view inside the tab, the tab itself remained-showing a blank/empty tab. I couldn't find a TabHost.RemoveTab() or TabHost.TabWidget.RemoveTab() methods and the TabHost.RemoveView()/TabHost.TabWidget.RemoveView() did not work.
Notes: I renamed the MvxTabsFragmentActivity to something else and included all copyright notices at the top of the class in my project. Thanks again to #Stuart.

CKeditor returning 403 when submitting certain html tags

I've created a page where I have two input textareas and I add CKeditor (ver. 4) to both of them.
The first editor works fine, I've set config.allowedContent = true; in the config.js to stop stripping tags like <script> and everything works as expected.
I have another editor right below it, same settings, same setup, I just changed the ID of the textarea field. It works when I submit normal text, but as soon as I add a <script> tag, for example, and press the submit button of the form in which the editors are in it seems to reload the page, doesn't submit any data and firebug tells me that the server returns 403.
I tried isolating the editor, adding personal configuration. Nothing. The first textarea works like a charm, second one returns 403 if the text has unsafe tags in it.
My setup is as follows, I'm using this ckeditor helper to insert the editors where I need. Page is created with CodeIgniter as you guessed.
I got a config.js file in ckeditor folder.
I'm using a regular form, nothing fancy about it. It looks like this
<form action="http://domain.com/admin/articles/edit/47" method="post">
<div id="cke_ckeditor_en_container">
<textarea cols="75" rows="7" id="ckeditor_en" name="text_en" class="input-text is-col-text"><?php echo set_value('text_en', isset($text_en) ? htmlspecialchars_decode($text_en) : ''); ?></textarea>
<?php echo display_ckeditor($ckeditor_en); ?>
</div>
<input type="submit" value="submit" />
</form>
The form has another part of html for the other editor which is the same, with changed id and other attributes, and a checkbox, nothing relevant.
And got this in my controller
public function edit(){
$this->load->helper('ckeditor');
$id = (int)$this->uri->segment(4);
if (empty($id)){
$this->session->set_flashdata('error', 'Empty ID!');
redirect('admin/articles');
}
$data = $this->articles_model->fetch_article($id);
$data['page_title'] = "Edit `" . $data['title'] . "`";
$data['form_url'] = "admin/articles/edit/" . $id;
$data['ckeditor'] = array(
'id' => 'ckeditor',
'path' => 'js/ckeditor');
$data['ckeditor_en'] = array(
'id' => 'ckeditor_en',
'path' => 'js/ckeditor');
$data['edit'] = true;
if($this->input->post('submit')){
$this->save_article("update",$id);
}
$this->load->view("admin/articles",$data);
}
private function save_article($type='insert', $id=0){
$this->load->library('form_validation');
$this->form_validation->set_rules('title','Title','trim|xss_clean|max_length[150]|min_length[1]');
$this->form_validation->set_rules('text','Text','trim');
$this->form_validation->set_rules('title_en','Title EN','trim|xss_clean|max_length[150]|min_length[1]');
$this->form_validation->set_rules('text_en','Text EN','trim');
$this->form_validation->set_rules('top_menu','Show in top menu','trim|xss_clean|max_length[1]');
if ($this->form_validation->run() === FALSE)
{
return FALSE;
}
// make sure we only pass in the fields we want
$data = array();
$data['title'] = $this->input->post('title');
$data['text'] = htmlspecialchars($this->input->post('text'));
$data['title_en'] = $this->input->post('title_en');
$data['text_en'] = htmlspecialchars($this->input->post('text_en'));
$data['url'] = $this->toAscii($this->input->post('title'));
$data['url_en'] = $this->toAscii($this->input->post('title_en'));
$data['top_menu'] = $this->input->post('top_menu');
if($type == "insert"){
$data['time'] = date("YmdHis");
}
if ($type == 'insert'){
if($this->articles_model->insert($data)){
$this->session->set_flashdata('success', 'Article added successfully!');
}else{
$this->session->set_flashdata('error', 'An error occured!');
}
}else if ($type == 'update'){
if($this->articles_model->update($id, $data)){
$this->session->set_flashdata('success', 'Article `' . $data['title'] . '` edited successfully!');
}else{
$this->session->set_flashdata('error', 'An error ecc!');
}
}
redirect("admin/articles");
}
Safety, or unsafeness, to be exact, of my code is not relevant
edit
Adding config.js for ckeditor.
CKEDITOR.editorConfig = function( config ) {
config.filebrowserBrowseUrl = '/js/kcfinder/browse.php?type=files';
config.filebrowserImageBrowseUrl = '/js/kcfinder/browse.php?type=images';
config.filebrowserFlashBrowseUrl = '/js/kcfinder/browse.php?type=flash';
config.filebrowserUploadUrl = '/js/kcfinder/upload.php?type=files';
config.filebrowserImageUploadUrl = '/js/kcfinder/upload.php?type=images';
config.filebrowserFlashUploadUrl = '/js/kcfinder/upload.php?type=flash';
config.removeButtons = 'Underline,Subscript,Superscript';
config.allowedContent = true;
// Se the most common block elements.
config.format_tags = 'p;h1;h2;h3;pre';
// Make dialogs simpler.
config.removeDialogTabs = 'image:advanced;link:advanced';
};
I'm stumped and stupified, I've got no ideas on what to do. It seems that the one input has been cursed.
Any help appreciated, thank you.
This would be the result of your mod_security rules. Depending on how strict they are they help better protect scripts from being hacked through vulnerabilities, generally those exploited via POST's.
As I understand you are trying to add something to your second textarea. And CKEditor removing some "unsafe" tags. I won't be very secure, but this can help you:
config.extraAllowedContent = '*{*}';
You will add this to your config.js. This code provides you to add anything you want. And CKEditor won't delete "unsafe" tags.
Documenation for this method
https://www.bilisimkitabi.com/403-error-on-submit-of-ckeditor
You can add to following code in your .htaccess file
#ckeditor Post 403 problem
<IfModule mod_security.c>
SecFilterEngine Off
SecFilterScanPOST Off
</IfModule>
#ckeditor Post 403 problem