Tinymce 5 dialog urlinput disable/enable broken - tinymce

Heads up to anyone who is self hosting who also runs across this bug....
In version 5.6.0 silver theme, the dialog urlinput enable/disable works for the input field but not the browse button of the control. The problem is that the enable/disable events are intercepted by the typeaheadBehaviours portion of the internal object so they never make it to the event handlers for the overall field. The fix is to add the onDisabled and onEnabled handlers to the Disabling.config for typeaheadBehaviours and remove the line of code from each handler that addresses the input field.
Original typeaheadBehaviours Disabling.config....
Disabling.config({
disabled: function () {
return spec.disabled || providersBackstage.isDisabled();
}
})
Amended code....
Disabling.config({
disabled: function () {
return spec.disabled || providersBackstage.isDisabled();
},
onDisabled: function (comp) {
memUrlPickerButton.getOpt(comp).each(Disabling.disable);
},
onEnabled: function (comp) {
memUrlPickerButton.getOpt(comp).each(Disabling.enable);
}
})
Haven't been able to figure out how to get those events to bubble up to the the overall control handlers but this seems to make things work as expected.

Related

Understanding binding and selection in Word Add-in

I'm trying to build an add-in with similar behaviour like the comment system.
I select a part of text.
Press a button in my add-in. A card is created that links to that text.
I do something else, like write text on a different position.
When I press the card in my add-in, I'd like to jump back to the selected text (in point 1).
I studied the API, documentation. And learned that I could do something like that with Bindings. A contentcontrol might also be an option, although I noticed that you can't connect and eventhandler (it's in beta). I might need an eventhandler to track changes later.
Create binding (step 2)
Office.context.document.bindings.addFromSelectionAsync(Office.BindingType.Text, { id: 'MyBinding' }, (asyncResult) => {
if (asyncResult.status == Office.AsyncResultStatus.Failed) {
console.log('Action failed. Error: ' + asyncResult.error.message);
} else {
console.log('Added new binding with id: ' + asyncResult.value.id);
}
});
Works. Then I click somewhere else in my document, to continue with step 4.
View binding (step 4).
So I click the card and what to jump back to that text binding, with the binding selected.
I figured there are multiple ways.
Method #1
Use the Office.select function below logs the text contents of the binding. However, it doesn't select that text in the document.
Office.select("bindings#MyBinding").getDataAsync(function (asyncResult) {
if (asyncResult.status == Office.AsyncResultStatus.Failed) {
}
else {
console.log(asyncResult.value);
}
});
Method #2
Use the GoToById function to jump to the binding.
Office.context.document.goToByIdAsync("MyBinding", Office.GoToType.Binding, function (asyncResult) {
let val = asyncResult.value;
console.log(val);
});
This shows like a blue like frame around the text that was previously selected and puts the cursor at the start.
I'd prefer that I don't see that frame (no idea if that's possible) and I would like to the text selected.
There is the Office.GoToByIdOptions interface that mentions:
In Word: Office.SelectionMode.Selected selects all content in the binding.
I don't understand how pass that option in the function call though and I can't find an example. Can I use this interface to get the selection?
https://learn.microsoft.com/en-us/javascript/api/office/office.document?view=common-js-preview#office-office-document-gotobyidasync-member(1)
goToByIdAsync(id, goToType, options, callback)
If there are other ways to do this, I'd like to know that as well.
With some help I could figure it out. I learned that an Interface is just an object.
So in this case:
const options = {
selectionMode: Office.SelectionMode.Selected
};
Office.context.document.goToByIdAsync("MyBinding", Office.GoToType.Binding, options, function (asyncResult) {
console.log(asyncResult);
});
This gives the selected result.
Sure someone can provide a better answer than this, as it's unfamiliar territory for me, but...
When you create a Binding from the Selection in Word, you're going to get a Content Control anyway. So to avoid having something that looks like a content control with the blue box, you either have to modify the control's display or you have to find some other way to reference a region of your document. In the traditional Word Object model, you could use a bookmark, for example. But the office-js APIs do not seem very interested in them.
However, when you create a Binding, which is an Office object, you don't get immediate access to the Content Control's properties (since that's a Word object). So instead of creating the Binding then trying to modify the Content Control, you may be better off creating the Content Control then Binding to it.
Something like this:
async function markTarget() {
Word.run(async (context) => {
const cc = context.document.getSelection().insertContentControl();
// "Hidden" means you don't get the "Bounding Box"
// (blue box with Title), or the Start/End tag view
cc.appearance = "Hidden";
// Provide a Title so we have a Name to bind to
cc.title = "myCC";
// If you don't want users changing the content, you
// could uncomment the following line
//cc.cannotDelete = true;
return context.sync()
.then(
() => {
console.log("Content control inserted");
// Now create a binding using the named item
Office.context.document.bindings.addFromNamedItemAsync("myCC",
Office.BindingType.Text,
{ id: 'MyBinding' });
},
() => console.log("Content control insertion failed")
).then(
() => console.log("Added new binding"),
() => console.log("Binding creation failed")
)
});
}
So why not just create the ContentControl, name it, and then you should be able to select it later using its Title, right? Well, getting the "data" from a control is one thing. Actually selecting it doesn't seem straightforward in the API, whereas Selecting a Binding seems to be.
So this code is pretty similar to your approach, but adds the parameter to select the whole text. The syntax for that is really the same syntax as { id: 'MyBinding' } in the code you already have.
function selectTarget() {
Office.context.document.goToByIdAsync(
"MyBinding",
Office.GoToType.Binding,
{ selectionMode: Office.SelectionMode.Selected },
function(asyncResult) {
let val = asyncResult.value;
console.log(val);
}
);
}
Both the Binding and the ContentControl (and its Title) are persisted when you save/reopen the document. In this case, the Binding is persisted as a piece of XML that stores the type ("text"), name ("MyBinding") and a reference to the internal ID of the content control, which is a 32-bit number, although that is not immediately obvious when you look at the XML - in an example here, the Id Word stores for the ContentControl is -122165626, but "Office" stores the ID for the Binding as 4172801670, but that's because they are using the two different two's complement representations of the same number.

Change content before preview in TinyMCE 4

In TinyMCE 4, I want to change displayed contents before they are showed on preview popup windows. This change must not affect current contents in editor. Can we do that?
If it can't, I want to catch close event of preview windows. How to do that?
TinyMCE allows us to register callbacks via the property init_instance_callback
By using the BeforeExecCommand event, oddly not in current documentation, you can make changes prior to a command being executed. We can similarly use the ExecCommand event to make changes after the command is executed. The Preview Plugin triggers the mcePreview command. You can view the Editor command Identifiers here.
Putting that together you can add the following when initializing your TinyMCE. This will show "changed content" in the preview without making visible changes to the content within TinyMCE.
var preProssesInnerHtml;
tinymce.init({
//other things...
init_instance_callback: function (editor) {
editor.on('BeforeExecCommand', function (e) {
if (e.command == "mcePreview") {
//store content prior to changing.
preProssesInnerHtml = editor.getContent();
editor.setContent("changed content");
}
});
editor.on("ExecCommand", function (e) {
if (e.command == "mcePreview") {
//Restore initial content.
editor.setContent(preProssesInnerHtml);
}
});
}
}

Customize or change default message boxes issued by workflow dialogs on errors in Alfresco

Presently, a messagebox appears with the failing class name:
Is it possible to override the default behavior in Alfresco? Could we use forms service to present a different message ?
Additional to zladuric answer,
you can use failureCallback method to show message what you want.
But it is difficult to search failureCallback method of workflow forms for a new one because workflow forms such as "Start Workflow", "Task Edit", "Task Detail" are used form engine.
For example, in "Start Workflow" form, you can add our own successCallBack and failureCallBack by writing onBeforeFormRuntimeInit event handler in start-workflow.js like this.
onBeforeFormRuntimeInit: function StartWorkflow_onBeforeFormRuntimeInit(layer, args)
{
var startWorkflowForm = Dom.get(this.generateId + "-form");
Event.addListener(startWorkflowForm, "submit", this._submitInvoked, this);
args[1].runtime.setAJAXSubmit(true,
{
successCallback:
{
fn: this.onFormSubmitSuccess,
scope: this
},
failureCallback:
{
fn: this.onFormSubmitFailure,
scope: this
}
});
}
onFormSubmitSuccess: function StartWorkflow_onFormSubmitSuccess(response)
{
this.navigateForward(true);
// Show your success message or do something.
}
onFormSubmitFailure: function StartWorkflow_onFormSubmitFailure(response)
{
var msgTitle = this.msg(this.options.failureMessageKey);
var msgBody = this.msg(this.options.failureMessageKey);
// example of showing processing response message
// you can write your own logic
if (response.json && response.json.message)
{
if(response.json.message.indexOf("ConcurrencyFailureException") != -1)
{
msgTitle = this.msg("message.concurrencyFailure");
msgBody = this.msg("message.startedAgain");
}
else
msgBody = response.json.message;
}
Alfresco.util.PopupManager.displayPrompt(
{
title: msgTitle,
text: msgBody
});
}
Since Alfresco.component.StartWorkflow(in start-workflow.js) extends Alfresco.component.ShareFormManager(in alfresco.js). You can override onBeforeFormRuntimeInit event in start-workflow.js. I hope this your help you.
I'm not looking at the code right now, but this looks like a regular YUI dialog. So it's fired by YUI. So this YUI is client side, probably in My-tasks dashlet or my tasks page.
Furthermore, the error message looks like it is a status.message from the failed backend message/service.
You could probably locate that client-side javascript file, find the method that starts the task and see what its' failureCallback handler is. Then edit that failureCallback method and make it show something different then the response.status.message or whatever it is. Perhaps something like this.msg("message.my-custom-error-message"); which you then customize on your own.
Modifying YUI dialog scripts will might affect the other functionalities as well.
If we customize start-workflow. js, its only going to be achieved in start workflow form.
So as generic solution, below is the suggestion.
When alfresco is rendering the workflow form , it is rendering the transition button using the activiti-transition.js file.Basically this buttons are doing nothing more but submitting the workflow form.
So the best way would be , customizing this activiti-transition.ftl and activiti-transition.js file , to make an ajax call and handle the response as we want.
I just had a look on full flow of how this front end error is shown.
activiti-transition is submiting the workflow form.
Using a function named as submitForm which resides inside alfresco.js, it is invoking an submit event of form
Inside the forms-runtime.js file there is one function named as _submitInvoked(handles the submit event of form), which is responsible for making an ajax call and submitting the workflow form.If there is error while submitting , it will display the error which is from backend.

Ignore multiple button taps after first one on iPhone webapp using jQuery Mobile?

Assume button A in an HTML5 webapp built with jQuery Mobile.
If someone taps button A, we call foo(). Foo() should get called once even if the user double taps button A.
We tried using event.preventDefault(), but that didn't stop the second tap from invoking foo(). event.stopImmediatePropagation() might work, but it also stops other methods further up the stack and may not lead to clean code maintenance.
Other suggestions? Maintaining a tracking variable seems like an awfully ugly solution and is undesirable.
You can set a flag and check if it's OK to run the foo() function or unbind the event for the time you don't want the user to be able to use it and then re-bind the event handler after a delay (just a couple options).
Here's what I would do. I would use a timeout to exclude the subsequent events:
$(document).delegate('#my-page-id', 'pageinit', function () {
//setup a flag to determine if it's OK to run the event handler
var okFlag = true;
//bind event handler to the element in question for the `click` event
$('#my-button-id').bind('click', function () {
//check to see if the flag is set to `true`, do nothing if it's not
if (okFlag) {
//set the flag to `false` so the event handler will be disabled until the timeout resolves
okFlag = false;
//set a timeout to set the flag back to `true` which enables the event handler once again
//you can change the delay for the timeout to whatever you may need, note that units are in milliseconds
setTimeout(function () {
okFlag = true;
}, 300);
//and now, finally, run your original event handler
foo();
}
});
});
I've created a sample here http://jsfiddle.net/kiliman/kH924/
If you're using <a data-role="button"> type buttons, there is no 'disabled' status, but you can add the appropriate class to give it the disabled look.
In your event handler, check to see if the button has the ui-disabled class, and if so, you can return right away. If it doesn't, add the ui-disabled class, then call foo()
If you want to re-enable the button, simply remove the class.
$(function() {
$('#page').bind('pageinit', function(e, data) {
// initialize page
$('#dofoo').click(function() {
var $btn = $(this),
isDisabled = $btn.hasClass('ui-disabled');
if (isDisabled) {
e.preventDefault();
return;
}
$btn.addClass('ui-disabled');
foo();
});
});
function foo() {
alert('I did foo');
}
});

jQuery live with the ready or load event

I'm using the jQuery Tools tooltip plugin, which is initialized with $('selector').tooltip(). I'd like to call this on any current or future .tooltipper element. I figured that the following would work:
$('.tooltipper').live('ready', function(){
$(this).tooltip()
}
But it was unsuccessful---the ready event did not fire. The same for load. I've read that livequery can produce the result of I'm looking for, but surely there is a way to use jQuery .live() to pull it off, considering the documentation says that it works for all jQuery events, of which I believe ready is one.
Quoted from the jQ API (http://api.jquery.com/live/):
In jQuery 1.3.x only the following JavaScript events (in addition to custom events) could be bound with .live(): click, dblclick, keydown, keypress, keyup, mousedown, mousemove, mouseout, mouseover, and mouseup.
As of jQuery 1.4 the .live() method supports custom events as well as all JavaScript events.
As of jQuery 1.4.1 even focus and blur work with live (mapping to the more appropriate, bubbling, events focusin and focusout).
As of jQuery 1.4.1 the hover event can be specified (mapping to "mouseenter mouseleave").
.live() does not appear to support the ready event.
To add to HurnsMobile's excellent answer; Looking at bindReady(), which is the internal call that jQuery makes to bind to the document load event every time you call $(some_function) or $(document).ready(some_function) we see why we cannot bind to "ready":
bindReady: function() {
if ( readyBound ) {
return;
}
readyBound = true;
// Catch cases where $(document).ready() is called after the
// browser event has already occurred.
if ( document.readyState === "complete" ) {
return jQuery.ready();
}
// Mozilla, Opera and webkit nightlies currently support this event
if ( document.addEventListener ) {
// Use the handy event callback
document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
// A fallback to window.onload, that will always work
window.addEventListener( "load", jQuery.ready, false );
// If IE event model is used
} else if ( document.attachEvent ) {
// ensure firing before onload,
// maybe late but safe also for iframes
document.attachEvent("onreadystatechange", DOMContentLoaded);
// A fallback to window.onload, that will always work
window.attachEvent( "onload", jQuery.ready );
// If IE and not a frame
// continually check to see if the document is ready
var toplevel = false;
try {
toplevel = window.frameElement == null;
} catch(e) { //and silently drop any errors
}
// If the document supports the scroll check and we're not in a frame:
if ( document.documentElement.doScroll && toplevel ) {
doScrollCheck();
}
}
}
To sum it up, $(some_function) calls a function which binds to:
DOMContentLoaded
onreadystatechange (DOMContentLoaded)
window.load / onload
Your best bet would be to bind to those actions that might create new .tooltipper elements, rather than trying to listen for the ready event (which happens only once).
HurnsMobile is right. JQuery live does not support the ready-event.
This is why I created a plugin that combines the two. You register your callback once, and then you will need to call the plugin once for content you add manually.
$.liveReady('.tooltipper', function(){
this.tooltip()
});
Then when creating new content:
element.html(somehtml);
element.liveReady();
or
$('<div class="tooltipper">...').appendTo($('body')).liveReady();
A demo is available here: http://cdn.bitbucket.org/larscorneliussen/jquery.liveready/downloads/demo.html
Check out the introductory post here: http://startbigthinksmall.wordpress.com/2011/04/20/announcing-jquery-live-ready-1-0-release/
Also have a look at http://docs.jquery.com/Plugins/livequery, which listenes for changes on the dom.