tinymce table on textarea. Tab key doesnt move cursor to next cell - cursor

I am using TinyMCE plugin on textarea. As i insert table with particular rows and columns, it creates the table. But when the cursor is focused on one cell and on pressing TAB, the cursor wont move to the next cell until i start typing and the cursor is then visible.
this issue happens only on IE9 and works fine on FireFox.
Kindly throw some light upon this issue.
Below is my textarea.
<textarea id="${docAnnotationAttrId}" name="docAnnotation" title="${attribute.description}"
rows="22" cols="80" style="width: 100%; height: 360px"
class="tinymce" readonly=true><c:out value="${attrMap[attrKey].value}"/></textarea>
<script>
var options = {'elementName' : '${docAnnotationAttrId}', 'incidentId' : '${document_uniqueReference.incidentId}',
'contextPath' : '${sharedContextPath}','dictionaries':'${webProperties.tinymceDictionaries}'};
$('#${docAnnotationAttrId}').edit(options);
</script>

I have the same problem, See me code below which i use to solved it.
function handleMyTinyCMETabEventOnChromeIE(){
tinymce.activeEditor.execCommand('mceInsertContent', false, " ");
$('#tabcontrol').blur();
tinymce.activeEditor.execCommand('mceInsertContent', false, "");
return false;
}
...
<textarea id="elm1" name="elm1"></textarea>
<a id='tabcontrol' onfocus="javascript: handleMyTinyCMETabEventOnChromeIE()" tabindex='0' href="#"></a>

Related

How to add the placeholder in tinymce v4.0

Hi is there a way to add a placeholder for tinymce v4.0 ? I need html 5 placeholder implementation in tinymce but it is not there by default.
<textarea id="Text" placeholder="Create your prompt here." ui-tinymce="$ctrl.tinymceOptions" ng-model="$ctrl.tmcModel"></textarea>
Assuming one is using tinyMCE 4, you could add a placeholder upon init, and then remove it on focus. Remember TinyMCE uses an iframe.
Needs to be polished for being more efficient, but here is a quick approach:
tinymce.init({
//here all the rest of the options
//xxxxx
//Add the placeholder
setup: function (editor) {
editor.on('init', function(){
if (tinymce.get('Text').getContent() == ''){
tinymce.get('Text').setContent("<p id='#imThePlaceholder'>Your nice text here!</p>");
}
},
//and remove it on focus
editor.on('focus',function(){
$('iframe').contents().find('#imThePlaceholder').remove();
}),
})
This worked for me.
var iframe = document.getElementsByTagName('iframe')[0];
iframe.style.resize = 'vertical';

how to toggle medium editor option on click using angularjs

I am trying to toggle the medium editor option (disableEditing) on button click. On the click the value for the medium editor option is changed but the medium editor does not use 'updated' value.
AngularJS Controller
angular.module('myApp').controller('MyCtrl',
function MyCtrl($scope) {
$scope.isDisableEdit = false;
});
Html Template
<div ng-app='myApp' ng-controller="MyCtrl">
<span class='position-left' medium-editor ng-model='editModel' bind-options="{'disableEditing': isDisableEdit, 'placeholder': {'text': 'type here'}}"></span>
<button class='position-right' ng-click='isDisableEdit = !isDisableEdit'>
Click to Toggle Editing
</button>
<span class='position-right'>
toggle value - {{isDisableEdit}}
</span>
</div>
I have created a jsfiddle demo.
I think initialising medium editor on 'click' could solve the issue, but i am not sure how to do that either.
using thijsw angular medium editor and yabwe medium editor
For this specific use case, you could try just disabling/enabling the editor when the button is clicked:
var editor = new MediumEditor(iElement);
function onClick(event) {
if (editor.isActive) {
editor.destroy();
} else {
editor.setup();
}
}
In the above example, the onClick function is a handler for that toggle button you defined.
If you're just trying to enable/disable the user's ability to edit, I think those helpers should work for you.
MediumEditor does not currently support changing configuration options on an already existing instance. So, if you were actually trying to change a value for a MediumEditor option (ie disableEditing) you would need to .destroy() the previous instance, and create a new instance of the editor:
var editor = new MediumEditor(iElement),
editingAllowed = true;
function onClick(event) {
editor.destroy();
if (editingAllowed) {
editor = new MediumEditor(iElement, { disableEditing: true });
} else {
editor = new MediumEditor(iElement);
}
editingAllowed = !editingAllowed;
}
Once instantiated, you can use .setup() and .destroy() helper methods to tear-down and re-initialize the editor respectively. However, you cannot pass new options unless you create a new instance of the editor itself.
One last note, you were calling the init() method above. This method is not officially supported or documented and it may be going away in future releases, so I would definitely avoid calling that method if you can.
Or you could just use this dirty hack : duplicate the medium-editor element (one with disableEditing enabled, the other with disableEditing disabled), and show only one at a time with ng-show / ng-hide :)
<span ng-show='isDisableEdit' class='position-left' medium-editor ng-model='editModel' bind-options="{'disableEditing': true ,'disableReturn': isDisableEdit, 'placeholder': {'text': 'type here'}}"></span>
<span ng-hide='isDisableEdit' class='position-left' medium-editor ng-model='editModel' bind-options="{'disableEditing':false ,'disableReturn': isDisableEdit, 'placeholder': {'text': 'type here'}}"></span>
You can see jsfiddle.

AngularJS : why after loading more data filter stop working?

there is one filter functionality in my demo I will explain my problem I have one table in which i use infinite scroll is implemented In other words when user moves to bottom it load more data.There is search input field in top .Using this I am able to filter item in table .but I don't know why it is not working
When you search "ubs" and "ing" first time .it works perfectly .But when you load more data other words when user scroll to bottom and load more data the again it try to filter "ubs" and "ing" it not give any result why ?
<label class="item item-input">
<img src="https://dl.dropboxusercontent.com/s/n2s5u9eifp3y2rz/search_icon.png?dl=0">
<input type="text" placeholder="Search" ng-model="query">
</label>
secondly Actually I am implementing infinite scroll so only 100 element display .can we search element from 2000 (which I am getting from service )and display data the search result ?
Update :
Here's a Plunker with everything working together. I have separated all of the pieces into individual JS files, as it was getting unruly:
Plunker
Search
The built in filter will only return results from the current view data that the ng-repeat is displaying. Because you're not loading all of the data into the view at once, you'll have to create your own search functionality.
In the demo, click the search icon to show the search box, then type your search value and press the ENTER key or click the search button to return the results.
Since you want to check whether the user pressed ENTER you have to pass both the event and the querystring to the function, so you can check for the enter keycode. The function should also run when someone clicks or taps the search button. I set ng-model="query" on the input, so query is the reference in the view. Therefore, you'll add ng-click="searchInvoices($event, query)" to your search button, and ng-keyup="searchInvoices($event, query)" to the input. And, finally, to make it easy to clear the input field, add a button that displays when the input is not empty with ng-show="query" and attach a click event with ng-click="query=null; resetGrid()".
Add the searchInvoices function to your controller. It will only run the search if either the query is empty (because you need to reset the view if the person uses the backspace key to empty the input) OR if the user pressed ENTER OR if the event was a click event in case the user clicks the search button. The inner if statement, prevents the search from running if the query is empty and just resets the view. If the query is not empty, against the total dataset and builds an array of matching results, which is used to update the view.
The last line sets the scroll position to the top of the scrollview container. This makes sure that the user sees the results without having to click somewhere in the scrollview container. Make sure you inject the $ionicScrollDelegate into your controller for this to work and set delegate-handle="invoicegrid" on your ion-scroll directive.
$scope.searchInvoices = function(evt, queryval) {
if (queryval.length === 0 || evt.keyCode === 13 || evt.type === 'click') {
if (queryval.length === 0) {
$scope.invoice_records = $scope.total_invoice_records;
} else {
var recordset = $scope.total_invoice_records;
results = [];
var recordsetLength = recordset.length;
var searchVal = queryval.toLowerCase();
var i, j;
for (i = 0; i < recordsetLength; i++) {
var record = recordset[i].columns;
for (j = 0; j < record.length; j++) {
var invoice = record[j].value.toLowerCase();
if (invoice.indexOf(searchVal) >= 0) {
results.push(recordset[i]);
}
}
}
$scope.invoice_records = results;
$ionicScrollDelegate.$getByHandle('invoicegrid').scrollTop();
}
}
};
Lastly, you need to modify the loadMore() function that is used by the infinite scroll directive, so that it doesn't try to load additional data when scrolling through the search results. To do this, you can just pass the query into loadMore on the directive like: on-infinite="loadMore(query)", then in your function, you can just run the broadcast event when the query exists. Also, removing the ngIf will ensure that the list remains dynamic.
$scope.loadMore = function(query) {
if (query || counter >= $scope.total_invoice_records.length) {
$scope.$broadcast('scroll.infiniteScrollComplete');
} else {
$scope.counter = $scope.counter + showitems;
$scope.$broadcast('scroll.infiniteScrollComplete');
}
};
You used filter in wrong way inside ng-repeat like ng-repeat="column in invoice_records | filter:query" instead of ng-repeat="column in invoice_records | query"
<div class="row" ng-repeat="column in invoice_records |filter:query">
<div class="col col-center brd collapse-sm" ng-repeat="field in column.columns" ng-show="data[$index].checked && data[$index].fieldNameOrPath===field.fieldNameOrPath">{{field.value}}</div>
<div class="col col-10 text-center brd collapse-sm"></div>
</div>
Demo Plunkr

Why is my click event called twice in jquery?

Why is my click event fired twice in jquery?
HTML
<ul class=submenu>
<li><label for=toggle><input id=toggle type=checkbox checked>Show</label></li>
</ul>
Javascript
$("ul.submenu li:contains('Show')").on("click", function(e) {
console.log("toggle");
if ($(this).find("[type=checkbox]").is(":checked")) console.log("Show");
else console.log("Hide");
});
This is what I get in console:
toggle menu.js:39
Show menu.js:40
toggle menu.js:39
Hide menu.js:41
> $("ul.submenu li:contains('Show')")
[<li>​ ]
<label for=​"toggle">​
<input id=​"toggle" type=​"checkbox" checked>​
"Show"
</label>​
</li>​
If I remember correctly, I've seen this behavior on at least some browsers, where clicking the label both triggers a click on the label and on the input.
So if you ignore the events where e.target.tagName is "LABEL", you'll just get the one event. At least, that's what I get in my tests:
Example with both events | Source
Example filtering out the e.target.tagName = "LABEL" ones | Source
I recommend you use the change event on the input[type="checkbox"] which will only be triggered once. So as a solution to the above problem you might do the following:
$("#toggle").on("change", function(e) {
if ($(this).is(":checked"))
console.log("toggle: Show");
else
console.log("toggle: Hide");
});
https://jsfiddle.net/ssrboq3w/
The vanilla JS version using querySelector which isn't compatible with older versions of IE:
document.querySelector('#toggle').addEventListener('change',function(){
if(this.checked)
console.log('toggle: Show');
else
console.log('toggle: Hide');
});
https://jsfiddle.net/rp6vsyh6/
This behavior occurs when the input tag is structured within the label tag:
<label for="toggle"><input id="toggle" type="checkbox" checked>Show</label>
If the input checkbox is placed outside label, with the use of the id and for attributes, the multiple firing of the click event will not occur:
<label for="toggle">Show</label>
<input id="toggle" type="checkbox" checked>
I found that when I had the click (or change) event defined in a location in the code that was called multiple times, this issue occurred. Move definition to click event to document ready and you should be all set.
Not sure why this wasn't mentioned. But if:
You don't want to move the input outside of the label (possibly because you don't want to alter the HTML).
Checking by e.target.tagName or even e.target doesn't work for
you because you have other elements inside the label
(in my case it had spans holding an SVG with a path so e.target.tagName sometimes showed SVG and other times it showed PATH).
You want the click handler to stay on the li (possibly because you have
other items in the li besides the checkbox).
Then this should do the trick nicely.
$('label').on('click', function(e) {
e.stopPropagation();
});
$('#toggle').on('click', function(e) {
e.stopPropagation();
$(this).closest('li').trigger('click');
});
Then you can write your own li click handler without worrying about events being triggered twice. Personally, I prefer to use a data-selected attribute that changes from false to true and vice versa each time the li is clicked instead of relying on the input's value:
$('ul.submenu li').on('click', function() {
let _li = $(this),
ticked = _li.attr('data-selected');
ticked = (ticked === 'false') ? true : false;
_li.attr('data-selected', ticked);
_li.find('#toggle').prop('checked', ticked);
});

how to handle combo boxes of ExtJS in selenium webdriver

Hi i have a ExtJS based UI. I have come to know that in ExtJS the combo box is not a real combo box but a combination of input text field, image of drop down box and a list. Now i am able to identify the control but i am stuck at selecting the value from the list. In the HTML source i see that the list is appearing as a seperate div and gets attached at the end of the source when we click on the drop down. find below the HTML source of the drop down control.
{
<div id="ext-gen678" class="x-form-field-wrap x-form-btn-plugin-wrap" style="width: 556px;">
<div id="ext-gen676" class="x-form-field-wrap x-form-field-trigger-wrap x-trigger-wrap-focus" style="width: 521px;">
<input id="ext-gen677" type="hidden" name="GHVOg:#concat#~inputFld~ISGP_UNIV:ft_t_isgp.prnt_iss_grp_oid:0" value="">
<input id="GHVOg:Mixh8:0" class="x-form-text x-form-field gs_dropDown_input gs_req x-form-invalid x-form-focus" type="text" autocomplete="off" size="24" style="width: 504px;">
<img id="trigger-GHVOg:Mixh8:0" class="x-form-trigger x-form-arrow-trigger" alt="" src="../../ext/resources/images/default/s.gif">
}
find below the HTML source of the drop down list:
<div id="ext-gen726" class="x-layer x-combo-list x-resizable-pinned" style="position: absolute; z-index: 12007; visibility: visible; left: 294px; top: 370px; width: 554px; height: 123px; font-size: 11px;">
<div id="ext-gen727" class="x-combo-list-inner" style="width: 554px; margin-bottom: 8px; height: 114px;">
<div class="x-combo-list-item"></div>
<div class="x-combo-list-item">12h Universe</div>
<div class="x-combo-list-item">1h Universe</div>
<div class="x-combo-list-item">24h Universe</div>
<div class="x-combo-list-item">2h Universe</div>
<div class="x-combo-list-item x-combo-selected">4h Universe</div>
Now i have problem selecting the value from the list as the div element of the list is not attached to the control.
Also please refer the screen shot, where i have multiple similar controls [Named "Add Security to Universe"]
In the screen shot you can see multiple drop downs [Add security to Universe] highlighted and all the drop downs have same value appearing in the list. so how can i identify these values from the drop down list.
I was wondering how ExtJS maintains mapping of the drop down div elements with the combo Box widget so that i could use the same logic for identifying the list. Can anyone tell me how can i go about doing this thing in selenium webdriver?
Did you notice that there will be only one visible x-combo-list on the page? (Let me know if you can open up two combo lists at the same time)
Therefore you only need to care about the visible one x-combo-list.
Css selector: .x-combo-list[style*='visibility: visible;'] .x-combo-list-item
Xpath: //*[contains(#class, 'x-combo-list') and contains(#style, 'visibility: visible;')]//*[contains(#class, 'x-combo-list-item')]
// untested java code, just for the logic
public void clickComboItem(WebElement input, String target) {
input.click(); // click input to pop up the combo list
List<WebElement> comboItems = driver.findElements(By.cssSelector(".x-combo-list[style*='visibility: visible;'] .x-combo-list-item"));
for (int i = 0; i <= comboItems.size(); i++) {
WebElement item = comboItems.get(i);
if (item.getText().eqauls(target)) {
item.click();
break;
}
}
}
// compilable C# version
public void ClickComboItem(IWebElement input, string target) {
input.Click();
IList<IWebElement> comboItems = driver.findElements(By.CssSelector(".x-combo-list[style*='visibility: visible;'] .x-combo-list-item"));
comboItems.First(item => item.Text.Trim() == target).Click();
}
What i can suggest is :
you catch all your inputs like :
List<WebElement> inputList = driver.findElements(By.cssSelector("input cssSelector")); // you must complete this cssSelector
WebElement input = inputList.get(0); // get the 1st input
input.click(); //click on the first input and the option list appears.
you catch all "options" like :
List<WebElement> optionList = driver.findElements(By.cssSelector(".x-combo-list-item")); // get all options
WebElement option = optionList.get(1);
option.click();
input.sendKeys(option.getText()); //getText() get the html inner value
This is just an example in Java and you can actually use a loop foreach if you want to automat this populate for all your inputs.
I use JavaScriptExecutor, my SelectRandomOption looks like this:
public void SelectRandomOption()
{
String randomOptionIndex = "Math.floor(Math.random()*Ext.getCmp('" + ExtJSIdOfComboBox + "').getStore().getCount()-1)";
String randomOptionValue = "Ext.getCmp('" + ExtJSIdOfComboBox + "').getStore().getAt(" + randomOptionIndex + ").getData()['model']";
String jsScript = "Ext.getCmp('" + ExtJSIdOfComboBox + "').setValue(" + randomOptionValue + ");";
js.ExecuteScript(jsScript);
}
I basically used the marked answer above however it needed a bit of adapting for Ext Js 4.1.
It's essentially the same approach but you need to look for a visible div marked with class "x-boundlist"
I used xpath and used queries that looked something like this:
.//div[#class[contains(.,'x-boundlist')]]
and then retrieve and click on an li matching your desired entry:
.//li[normalize-space(text())='combobox entry text']
I've put normalize-space in there as xpath seems to have real problems if you dont trim strings. That methods does a left + right trim and also removes duplicate spaces eg
' blah blah ' would change to 'blah blah'.

Resources