How to swap CSS in Sencha Touch - sencha-touch

I need to swap the css for my Mobile application done in Sencha Touch.
At the moment I=m not obtaining any result.
Could you tell me how to do it?
Thanks

I solved the issue using this code...
var accessibilityButton = {
xtype: 'button',
ui: 'custom-btn-confirm',
maxWidth: '360px',
centered: true,
flex: 1,
scope: this,
style: 'color: #ffffff',
text: 'Active Accesibility',
ui: 'custom-btn-confirm',
handler: function changeStyle() {
// Swap the CSS for Accessibility
var i, a, url, btn;
for(i=0; (a = document.getElementsByTagName("link")[i]); i++) {
if(a.getAttribute("rel").indexOf("style") != -1) {
url = a.href;
btn = document.getElementById("ext-element-114");
if(url.lastIndexOf('app.css') !== -1) {
a.href = 'resources/css/app-accesibility.css';
btn.textContent = "AAAA";
}
else {
a.href = 'resources/css/app.css';
btn.textContent = "BBBB";
}
}
}
}
};

Related

data is shown on chartjs-vue only after resizing browser or opening developer tools

im having hard time fixing this problem.
i get my data with a get request, after opening developer tools or resizing browser the data is shown.
i have tried some delay or timeout solutions but sadly could not make it work. i need the fastest solution, even if it is a "dirty hack" sort of solution.
im using vue 2.9.1 and chartjs-vue 2.7.1.
thank you!
this is my code:
import {Line} from 'vue-chartjs'
export default {
name: 'Events',
extends: Line,
created: function () {
this.getEvents();
},
data () {
return {
gradient: null,
gradient2: null,
datesList : [],
avgList: []
}
},
methods:{
graphClickEvent(event, array){
var points = this.getElementAtEvent(event)
},
getEvents () {
this.$http.get('http://localhost:8081/users/getAllEvents'
,{headers: {'Content-Type': 'application/json',
'Authorization': localStorage.getItem('token'),}
}).then((res) => {
// res.body = array of event object
var eventsArr = res.body;
var arrayLength = eventsArr.length;
for (var i = 0; i < arrayLength; i++) {
var date = new Date(parseInt(eventsArr[i].startTime))
var day = date.getDate()
var month = date.getMonth()
var year = date.getFullYear()
var hours = date.getHours()
hours = ("0" + hours).slice(-2);
var minutes = date.getMinutes()
minutes = ("0" + minutes).slice(-2);
var str = day;
var str = day + "." + (month + 1) + "." + year +" - " + hours + ":" + minutes
this.datesList.push(str);
}
for (var i = 0; i < arrayLength; i++) {
var evnt = eventsArr[i];
this.avgList.push({label: evnt.name,y: evnt.pulseAverage ,tag: evnt.tag, id: evnt.id });
}
})
}
},
mounted () {
this.gradient = this.$refs.canvas.getContext('2d').createLinearGradient(0, 0, 0, 450)
this.gradient2 = this.$refs.canvas.getContext('2d').createLinearGradient(0, 0, 0, 450)
this.gradient.addColorStop(0, 'rgba(255, 0,0, 0.5)')
this.gradient.addColorStop(0.5, 'rgba(255, 0, 0, 0.25)');
this.gradient.addColorStop(1, 'rgba(255, 0, 0, 0)');
this.gradient2.addColorStop(0, 'rgba(0, 231, 255, 0.9)')
this.gradient2.addColorStop(0.5, 'rgba(0, 231, 255, 0.35)');
this.gradient2.addColorStop(1, 'rgba(0, 231, 255, 0)');
this.renderChart({
labels: this.datesList,
datasets: [
{
label: 'Events',
borderColor: '#05CBE1',
pointBackgroundColor: 'white',
pointBorderColor: 'white',
borderWidth: 2,
backgroundColor: this.gradient2,
data: this.avgList
},
]
,
options: {
scales: {
xAxes: [{
ticks: {
beginAtZero:true
}
}]
}
}
}
//
,{ onClick: function(event){
var activePoints = this.getElementAtEvent(event)
var firstPoint = activePoints[0];
if(firstPoint !== undefined){
var label = this.data.labels[firstPoint._index];
var value = this.data.datasets[firstPoint._datasetIndex].data[firstPoint._index];
var location = "eventGraph?id=" + value.id;
window.location.href = location;
}
}
, responsive: true, maintainAspectRatio: false,fontColor: '#66226',
tooltips: {
enabled: true,
mode: 'single',
callbacks: {
title: function(tooltipItems, data) {
var evnt = data.datasets[0].data[tooltipItems[0].index].label;
return evnt
},
label: function(tooltipItems, data) {
var avg = 'Average heart: ' + [tooltipItems.yLabel];
var evnt = 'Type: ' + data.datasets[0].data[tooltipItems.index].tag;
return [avg,evnt];
}
}
}
})
}
}
It sounds like an initialization issue where the chart is initially rendered in an element that is not visible or it can't determine the size of the parent.
I see similar issues doing a Google:
ChartJS won't draw graph inside bootstrap tab until window resize #17
Charts rendered in hidden DIVs will not display until browser resize #29
Chart.js not rendering properly until window resize or toggling line in legend
One suggested doing a chart refresh when everything is visible:
setTimeout(function() { myChart.update(); },1000);
In think in vue this could be done in the mount function.
I'm sure there is a more elegant way to handle this with a watch function or something similar for instance.
Updated:
As mentioned in the comments, I've seen references to people firing a window resize event manually using:
window.dispatchEvent(new Event('resize'));
I think it would probably work in the mounted function of the vue component:
export default {
name: 'graphs-component',
mounted: function(){
window.dispatchEvent(new Event('resize'));
}
}
You might even wrap it in a setTimeout to ensure everything is loaded.

DataTables image (or at least image title) export to PDF

Using DataTables and Buttons (NOT TableTools, which is retired) extension. Some cells have progressbars and small icons. Is there a way to export these images (or at least their titles) to PDF? Found some possible hacks on this page, but all of them were for retired TableTools.
Checked https://datatables.net/reference/button/pdf and https://datatables.net/reference/api/buttons.exportData%28%29 but couldn't find any method to achieve this goal. Tested by adding this code:
stripHtml: false
but whole HTML code (like img src=...) was included in PDF file instead of images.
If exporting images isn't possible, is there a way to export at least alt or title attribute of each image? That would be enough.
I assume you are using pdfHtml5. dataTables is using pdfmake in order to export pdf files. When pdfmake is used from within a browser it needs images to be defined as base64 encoded dataurls.
Example : You have rendered a <img src="myglyph.png"> in the first column of some of the rows - those glyphs should be included in the PDF. First create an Image reference to the glyph :
var myGlyph = new Image();
myGlyph.src = 'myglyph.png';
In your customize function you must now
1) build a dictionary with all images that should be included in the PDF
2) replace text nodes with image nodes to reference images
buttons : [
{
extend : 'pdfHtml5',
customize: function(doc) {
//ensure doc.images exists
doc.images = doc.images || {};
//build dictionary
doc.images['myGlyph'] = getBase64Image(myGlyph);
//..add more images[xyz]=anotherDataUrl here
//when the content is <img src="myglyph.png">
//remove the text node and insert an image node
for (var i=1;i<doc.content[1].table.body.length;i++) {
if (doc.content[1].table.body[i][0].text == '<img src="myglyph.png">') {
delete doc.content[1].table.body[i][0].text;
doc.content[1].table.body[i][0].image = 'myGlyph';
}
}
},
exportOptions : {
stripHtml: false
}
}
Here is a an example of a getBase64Image function
function getBase64Image(img) {
var canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
return canvas.toDataURL("image/png");
}
If you just want to show the title of images in the PDF - or in any other way want to manipulate the text content of the PDF - then it is a little bit easier. The content of each column in each row can be formatted through the exportOptions.format.body callback :
buttons : [
{
extend : 'pdfHtml5',
exportOptions : {
stripHtml: false
format: {
body: function(data, col, row) {
var isImg = ~data.toLowerCase().indexOf('img') ? $(data).is('img') : false;
if (isImg) {
return $(data).attr('title');
}
return data;
}
}
}
]
The reason format.body cannot be used along with images is that is only let us pass data back to the text node part of the PDF document.
See also
http://pdfmake.org/#/gettingstarted (look for Images section)
https://github.com/bpampuch/pdfmake/blob/master/examples/images.js
Since no suggestions received, I had to make a hack in order to get PDF file formatted the way I want.
In case someone has the same issue, you can use hidden span to display image alt/title near image itself. I'm sure it's not the best practice, but it will do the trick. So the code will look like:
<img src='image.png' alt='some_title'/><span class='hidden'>some_title</span>
This way datatables will show only the image, while PDF file will contain text you need.
This is my CODE!
HTML
<div class="dt-btn"></div>
<table>
<thead><tr><th>No</th><th>IMAGE</th><th>NOTE</th></tr></thead>
<tbody>
<tr>
<td>{{$NO}}</td>
<td>{{$imgSRC}}</td>
<td>{{$NAME}}<br />
{{$GRADE}}<br />
{{$PROFILE}}<br />
{{$CODE}}<br />
</td>
</tr>
</tbody>
</table>
JAVASCRIPT
$.extend( true, $.fn.dataTable.defaults, {
buttons: [{
text: '<i class="bx bx-download font-medium-1"></i><span class="align-middle ml-25">Download PDF</span>',
className: 'btn btn-light-secondary mb-1 mx-1 dnPDF',
extend: 'pdfHtml5',
pageSize: 'A4',
styles: {
fullWidth: { fontSize: 11, bold: true, alignment: 'left', margin: [0,0,0,0] }
},
action: function ( e, dt, node, config ) {
var that = this;
setTimeout( function () {
$.fn.dataTable.ext.buttons.pdfHtml5.action.call(that, e, dt, node, config);
$( ".donePDF" ).remove();
$( ".dnPDF" ).prop("disabled", false);
}, 50);
},
customize: function(doc) {
doc.defaultStyle.fontSize = 11;
doc.defaultStyle.alignment = 'left';
doc.content[1].table.dontBreakRows = true;
if (doc) {
for (var i = 1; i < doc.content[1].table.body.length; i++) {
// 1st Column - display IMAGE
var imgtext = doc.content[1].table.body[i][0].text;
delete doc.content[1].table.body[i][0].text;
jQuery.ajax({
type: "GET",
dataType: "json",
url: "{{route('base64')}}",
data: { src: imgtext },
async: false,
success: function(resp) {
//console.log(resp.data);
doc.content[1].table.body[i][0] = {
margin: [0, 0, 0, 3],
alignment: 'center',
image: resp.data,
width: 80,
height: 136
};
}
});
// 2nd Column - display NOTE(4 line)
var bodyhtml = doc.content[1].table.body[i][1].text;
var bodytext = bodyhtml.split("\n");
var bodystyle = []
for (var j = 0; j < bodytext.length; j++) {
switch(j) {
case 0:
// NAME
var _text = { margin:[0, 0, 0, 3], color:"#000000", fillColor:'#ffffff', bold:true, fontSize:13, alignment:'center', text:bodytext[j] };
break;
case 1:
// GRADE
var _text = { margin:[0, 0, 0, 3], color:"blue", fillColor:'#ffffff', bold:false, fontSize:11, alignment:'left', text:bodytext[j] };
break;
case 3:
// CODE
var _text = { margin:[0, 0, 0, 3], color:"#000000", fillColor:'#ffffff', bold:true, fontSize:11, alignment:'left', text:bodytext[j] };
break;
default:
// OTHERS
var _text = { margin:[0, 0, 0, 3], color:"#000000", fillColor:'#ffffff', bold:false, fontSize:11, alignment:'left', text:bodytext[j] };
break;
}
bodystyle[j] = _text;
};
doc.content[1].table.body[i][1] = bodystyle;
}
}
},
exportOptions: {
columns: [ 1, 2 ],
stripNewlines: false,
stripHtml: true,
modifier: {
page: 'all' // 'all', 'current'
},
}
}],
columns: [
{ className: 'iNo', orderable: true, visible: true},
{ className: 'iIMG', orderable: false, visible: false },
{ className: 'iPDF', orderable: false, visible: false, responsivePriority: 10001 } ]
});
var table = $('#table').DataTable();
table.buttons().container().appendTo('.dt-btn');
$('.dnPDF').on('click', function(){
$(this).append('<span class="spinner-border spinner-border-sm donePDF" role="status" aria-hidden="true"></span>').closest('button').attr('disabled','disabled');
});
$.fn.dataTable.Buttons.defaults.dom.container.className = '';
$.fn.dataTable.Buttons.defaults.dom.button.className = 'btn';
PHP
public function base64(Request $request)
{
$request->validate([
'src' => 'required|string'
]);
$fTYPE = pathinfo($request->src, PATHINFO_EXTENSION);
$fDATA = #file_get_contents($request->src);
$imgDATA = base64_encode($fDATA);
$imgSRC = 'data:image/' . $fTYPE . ';base64,'.$imgDATA;
$error = ($imgDATA!='') ? 0 : 1;
$msg = ($error) ? 'Error' : 'Success';
return response()->json([ 'msg' => $msg, 'error'=> $error, 'data' => $imgSRC]);
}
[Sample][1]: https://i.stack.imgur.com/35Wlm.jpg
In addition to davidkonrad's answer. I created dynamically all base64 images and used them in Datatables pdfmake like this:
for (var i = 1; i < doc.content[2].table.body.length; i++) {
if (doc.content[2].table.body[i][1].text.indexOf('<img src=') !== -1) {
html = doc.content[2].table.body[i][1].text;
var regex = /<img.*?src=['"](.*?)['"]/;
var src = regex.exec(html)[1];
var tempImage = new Image();
tempImage.src = src;
doc.images[src] = getBase64Image(tempImage)
delete doc.content[2].table.body[i][1].text;
doc.content[2].table.body[i][1].image = src;
doc.content[2].table.body[i][1].fit = [50, 50];
}
//here i am removing the html links so that i can use stripHtml: true,
if (doc.content[2].table.body[i][2].text.indexOf('<a href="details.php?') !== -1) {
html = $.parseHTML(doc.content[2].table.body[i][2].text);
delete doc.content[2].table.body[i][1].text;
doc.content[2].table.body[i][2].text = html[0].innerHTML;
}
}

ST2.1 vs ST2.2 chart sprite style renderer

With ST2.1, I had a scatter graph with a renderer function changing all sprite rotation and color based on values in the store. It was working well.
I upgraded to ST2.2.0 and now I'm having trouble rebuilding the same function.
code for ST2.1 - was working.
series: [
{
type: 'scatter',
xField: 'local_date_time',
yField: 'wind_spd_kt',
marker: { ...
},
style: {
renderer: function (target, sprite, index, storeItem) {
var sweather = Ext.getStore('Sun');
if (index < sweather.getCount() ){
target.rotationRads = storeItem.data.sun_dir;
if (storeItem.data.sun_spd_kt < 10) {
target.fill = '#ff0000'; //red
//console.log ( index + ' : <10 :' + storeItem.data.sun_spd_kt )
}
else { target.fill = '#00EE00'; } //green
}
}
},
COde in ST2.2.0 that I tried:
style: {
renderer: function (sprite, config, rendererData, index) {
sprite.rotationRads = rendererData.store.data.all[index].raw.sun_dir
sprite.attr.fillStyle = '#ff0000'
}
}
Has Anyone used "renderer" successfully in ST2.2.0?
I made up a solution to your problem. Could you try the following ?
renderer: function (sprite, config, rendererData, index) {
if (index % 2 == 0) {
return { strokeStyle: 'red' };
}
}

Sencha Touch 2 Carousel: Lock Swiping of Start/End Page

I want Carousel to stop swiping at start and end of the pages.
I mean to prevent the end page to swipe to the right and the start page to swipe to the left:
Is there any config or some other way to implement it?
Thank you in Advance.
By default, ST2's carousel component has this configuration. So, you need not put in any extra effort to achieve this.
Look at this example from Sencha's website. When you reach the last item, it will prevent swiping to the right and when you are on first item, it will prevent swiping to the left.
Ext.create('Ext.Carousel', {
fullscreen: true,
defaults: {
styleHtmlContent: true
},
items: [
{
html : 'Item 1',
style: 'background-color: #5E99CC'
},
{
html : 'Item 2',
style: 'background-color: #759E60'
},
{
html : 'Item 3'
}
]
});
You can create your own carousel and then override the onDrag event following is the code form Ext.carousel.Carousel
Ext.define('Ext.carousel.Custom', {
extend: 'Ext.carousel.Carousel',
onDrag: function(e) {
if (!this.isDragging) {
return;
}
var startOffset = this.dragStartOffset,
direction = this.getDirection(),
delta = direction === 'horizontal' ? e.deltaX : e.deltaY,
lastOffset = this.offset,
flickStartTime = this.flickStartTime,
dragDirection = this.dragDirection,
now = Ext.Date.now(),
currentActiveIndex = this.getActiveIndex(),
maxIndex = this.getMaxItemIndex(),
lastDragDirection = dragDirection,
offset;
if ((currentActiveIndex === 0 && delta > 0) || (currentActiveIndex === maxIndex && delta < 0)) {
delta *= 0.5;
}
offset = startOffset + delta;
if (offset > lastOffset) {
dragDirection = 1;
}
else if (offset < lastOffset) {
dragDirection = -1;
}
if (dragDirection !== lastDragDirection || (now - flickStartTime) > 300) {
this.flickStartOffset = lastOffset;
this.flickStartTime = now;
}
this.dragDirection = dragDirection;
// now that we have the dragDirection, we should use that to check if there
// is an item to drag to
if ((dragDirection == 1 && currentActiveIndex == 0) || (dragDirection == -1 && currentActiveIndex == maxIndex)) {
return;
}
this.setOffset(offset);
}
});
reference :=Link

Tabpanel in Extjs4 has memory leak?

every one!
I use tablpanel in extjs4,found the memory in IE8 didn't reduce when remove the panel in tabpanel,and also raised when add the panel again.so I write a test as below:
Ext.onReady(function() {
var currentItem;
var tabs = Ext.createWidget('tabpanel', {
renderTo: 'tabs',
resizeTabs: true,
enableTabScroll: true,
width: 600,
height: 250,
defaults: {
autoScroll:true,
bodyPadding: 10
}
});
var __my_task = '';
var i = 0;
try{
__my_task = {
run: function(){
if (i % 2 == 0){
for(var j = 0; j < 10; j++){
addTab(true);
}
}else{
var items = [];
tabs.items.each(function(item){
if(item.closable){
if(!false || item != this.item){
items.push(item);
}
}
}, this);
Ext.each(items, function(item){
tabs.remove(item);
item.destroy();
}, this);
} // else
i ++;
},
interval: 300
}
Ext.TaskManager.start(__my_task);
}catch(e){}
// tab generation code
var index = 0;
function addTab (closable) {
++index;
tabs.add(Ext.create('Ext.tree.Panel',{
title: 'New Tab ' + index,
iconCls: 'tabs',
closable: !!closable
}));
}
});
run it in IE8,the memory will raised so quickly,my code is wrong ? any question for me, thanks!
IMO it's hardly to evaluate if there is memory leak in Javascript (Extjs written in JS as you know). The object may be deleted with delete() (destroy() will use it) but cannot sure when the memory will be actually released.
You can find more about Javascript garbage collector in Deleting or setting to null and Javascript garbage collection