Blessed ListTable - Top row locked, cant select or scroll - javascript

I'm new to blessed, and have a listTable that doesn't seem to scroll its top line.
Any suggestions?
var blessed = require('blessed');
var screen = new blessed.Screen
// Function to create a bunch of sample data
function getData(start, count) {
var result = [];
for (var i=start; i < count; i++) {
var row = [ '', i+'', 'test' + i];
result.push(row);
}
return result;
}
// quit when q or Ctrl-q is pressed
screen.key(['q','C-q'], function() {
return process.exit(0);
});
// Create a table
var table = blessed.listtable({
parent: screen,
left: 0,
data: getData(0,100),
border: 'line',
align: 'center',
keys: true,
width: '90%',
height: '90%',
vi: false,
name:'table'
});
// Focus table, and render results to screen
table.focus();
screen.render();

The reason is that the first row acts as the header for the table and it stays in a fixed position for convenience.
You will probably need to make your own custom ListTable class if you do not want the header since it is currently not optional. It's fairly easy to do though, just remove the relevant bits from the existing class that reference the fixed header (see the commented out bits here).

Related

How to position divs on top ads on Amazon.com

I want to position some divs on top of all ads on Amazon.com like this:
This is for a project of mine. The above picture was achieved through getting the coordinates of the ads using getBoundingClientRect and creating divs, setting top and left based on these coordinates, and appending the divs to document.body. However, since they have absolute position and are children of document.body, they do not move with the ads. For example, if I resize the window, this happens
Also, in product pages, this happens without doing anything.
I have also tried appending the divs to the parents of the iframes/ads, but I can never seem to make them appear outside of their parent. I have tried suggestions from various links, such as making position:absolute, setting bottom or top, making the parents position:relative but nothing has worked. There has been one instance of the div appearing outside of the parent but it was in some random position above it like this.
I seriously don't know how to accomplish this. Ideally, the div would be a sibling of the iframe or something like that, so I don't have to deal with the divs not moving when the window resizes. I just can't seem to get anything work, though.
// Here is the code for appending to parent of iframes.
// The divs just end up overlaying the ad.
function setStyle(element, styleProperties) {
for (var property in styleProperties) {
element.style[property] = styleProperties[property];
}
}
// Regex for getting all the parents of all the iframes
var placements = document.querySelectorAll('div[id^=\'ape_\'][id$=\'placement\']');
for (var i = 0; i < placements.length; ++i) {
var placement = placements[i];
var iframe = placement.getElementsByTagName('iframe')[0];
var debugDiv = document.createElement('div');
debugDiv.id = iframe.id + '_debug_div';
setStyle(debugDiv, {
'backgroundColor': '#ff0000',
'height': '30px',
'display': 'block',
'position': 'absolute',
'top': '-30px',
'zIndex': '16777270',
});
alert(placement.id)
placement.style.position = 'relative'
placement.appendChild(debugDiv);
}
edit:
Here's the getBoundingClientRect code:
function setStyle(element, styleProperties) {
for (var property in styleProperties) {
element.style[property] = styleProperties[property];
}
}
function createDiv(iframeId, top, left, width) {
var div = document.createElement('div');
div.id = iframeId + '_debug_div';
setStyle(div, {
'backgroundColor': '#ccffff',
'backgroundColor': '#ff0000',
'height': '30px',
'width': width.toString() + 'px',
'display': 'block',
'position': 'absolute',
'top': (top - 30).toString() + 'px',
'left': left.toString() + 'px',
'zIndex': '16777270'
});
return div;
}
var placements = document.querySelectorAll('div[id^=\'ape_\'][id$=\'placement\']');
for (var i = 0; i < placements.length; ++i) {
var placement = placements[i];
var iframe = placement.getElementsByTagName('iframe')[0];
var iframeRect = iframe.getBoundingClientRect();
iframeWidth = iframeRect.right - iframeRect.left;
var debugDiv = createDiv(iframe.id, iframeRect.top, iframeRect.left, iframeWidth);
document.body.appendChild(debugDiv);
};
This doesn't work properly when the window is resized. It also does not work properly on product pages for some ads.
Try using the resize eventlistener, with a DOM MutationObserver:
var observeDOM = (function(){
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
return function( obj, callback ){
if( !obj || !obj.nodeType === 1 ) return; // validation
if( MutationObserver ){
// define a new observer
var obs = new MutationObserver(function(mutations, observer){
callback(mutations);
})
// have the observer observe foo for changes in children
obs.observe( obj, { childList:true, subtree:true });
}
else if( window.addEventListener ){
obj.addEventListener('DOMNodeInserted', callback, false);
obj.addEventListener('DOMNodeRemoved', callback, false);
}
}
})();
window.onchange = function(){
observeDOM(document.body, () => {
window.addEventListener('resize', () => {
var placements = document.querySelectorAll('div[id^=\'ape_\'] [id$=\'placement\']');
for (var i = 0; i < placements.length; ++i) {
var placement = placements[i];
var iframe = placement.getElementsByTagName('iframe')[0];
var iframeRect = iframe.getBoundingClientRect();
iframeWidth = iframeRect.right - iframeRect.left;
var debugDiv = createDiv(iframe.id, iframeRect.top, iframeRect.left, iframeWidth);
document.body.appendChild(debugDiv);
}
});
});
}
It's a start. I think the issue with the misplaced bars on the product pages may be fixed by using the onload listener too, although I can't reproduce those issues for whatever reason. If it's not matching some ads altogether, that's likely due to your query selector, but I can't help fix that unfortunately.
The code for the DOM observer is from here - it should detect changes more accurately than onchange, especially for things like flex, where elements can get reordered in the DOM on mobile view. You may also want to wrap this in document.addEventListener("DOMContentLoaded", ... to wait until everything's loaded (at the sacrifice of IE8), or just use jQuery's $(document).ready() (which is compatible with IE8) - however, if you're not already using jQuery, don't import it just for this one function!
Also, you may want to do something about the padding on the body, which may be the cause of the misalignment in some cases. You should probably get it using window.getComputedStyles, and compensate for it. Once again, however, I can't reproduce these errors.
I think, that you want to select the image of the ad.
const adImages = document.querySelectorAll('your ad images');
for (var i = 0; i < adImages.length; ++i) {
adImages[i].parent.insertAdjacentHTML('afterbegin', 'your html');
}
You basicaly set the first child of that parent element on the top.

Get last viewed index with Scrollify

I'm using scrollify to swap out fixed position components, and adding/removing classes to animate the transition. I have everything working as I'd like as you progress forward through the scroll, but when you scroll up to see a previous section, its not removing the previous class, and the previous section now animates in behind it.
I don't think the prev method will be of use, because it doesn't call the previous section your were at, only the previous section assuming you are always moving forward.
Here is my code below, you can move forward just fine, but trying to go backwards presents a problem as the new current section will load behind the previous one, and the previous one will still be visible.
jsfilddle here
var wrapper = $('.wrapper');
var currentPosition = 0;
$(wrapper).each(function(index) {
if (currentPosition != index) {
$(this).css('opacity', 0);
} else if (currentPosition == index) {
$(this).css('opacity', 1);
}
});
$(function() {
$.scrollify({
section: ".wrapper",
scrollSpeed: 700,
setHeights: false,
after: function(index, sections) {
var prevWrapper = $.scrollify.current().prev();
var currentWrapper = $.scrollify.current();
var nextWrapper = $.scrollify.current().next();
$(prevWrapper).removeClass('wrapper-enter').addClass('wrapper-leave');
$(currentWrapper).removeClass('wrapper-leave').addClass('wrapper-enter');
},
});
});
The issue is depending on scrolling up or down your "next" or "prev" may not actually be what you think so you are hiding classes incorrectly.
What you could do as scrollify doesn't have an option to detect scroll direction is to create a super quick variable that will detect if you are scrolling up or down. Then simply update your classes then in the after function.
$.scrollify({
section: ".wrapper",
scrollSpeed: 700,
setHeights: false,
after: function(index, sections) {
var prevWrapper = $.scrollify.current().prev();
var currentWrapper = $.scrollify.current();
var nextWrapper = $.scrollify.current().next();
let elem = null;
// Add wrapper-enter to current element.
$(currentWrapper).removeClass('wrapper-leave').addClass('wrapper-enter');
if(lastIndex < index) {
// Scolled down if lastIndex < index
elem = prevWrapper;
} else {
// Scrolled up if last index > index
elem = nextWrapper;
}
$(elem).removeClass('wrapper-enter').addClass('wrapper-leave');
lastIndex = index;
},
In the above I simply created a variable to track the last index.
Here is a working fiddle: https://jsfiddle.net/k1e6x79f/

How to set the auto width for combo box in Kendo UI?

I want to set the combo box width automatically based on the lengthiest text which is bound to the Combo box, so I tried like below, but I am able to see the auto size (width) only for drop down (drop down when clicking the combo) of the combo box, still the length is greater than expected, the overall length should be reduced to hold only 3 characters, am I missing something here?
<input id="combobox" />
$("#combobox").kendoComboBox({
index: 0,
dataSource: {
data: ["One", "Two"]
}
});
var comboBox = $("#combobox").data("kendoComboBox");
comboBox.list.width("auto");
$("#combobox").width(parseInt($("#combobox").css("width")));
http://jsfiddle.net/KendoDev/Z4rwQ/
I guess you could determine the length in the datasource itself, and then resize the combobox. This works for a demo project, but i guess depending on styles and padding that you might need to to some more refining to the sizing technique.
This determines the size of the elements (again, in case you are using objects instead of strings inside the array, you might need to refine it a bit (you could pass the displayMember if you'd like)
function determineWidth(ds) {
var l = ds.length, selement = document.createElement('span'), maxwidth = 0, curwidth = 0;
selement.style = 'position: fixed; left: -500px; top: -500px;';
document.body.appendChild(selement);
for (var i = 0; i < l; i++) {
$(selement).html(ds[i]);
curwidth = $(selement).width();
if (curwidth < maxwidth) {
continue;
}
maxwidth = curwidth;
}
document.body.removeChild(selement);
return curwidth + 24;
}
inside the combobox, you can bind to the dataBound event, determine the size of the elements, and update the container and parent to match the actual size
$("#combobox").kendoComboBox({
index: 0,
dataSource: {
data: ["One", "Two", "Hundred"]
},
dataBound: function() {
var width = determineWidth(this.dataSource.data());
$('#combobox-container').find('span>.k-dropdown-wrap').width(width).parent().width(width);
}
});
var comboBox = $("#combobox").data("kendoComboBox");
fiddle you can find here: http://jsfiddle.net/Icepickle/gLbLtjhf/
I will like to add, if you want to have a fixed width of comboBox irrespective of the data item length then define the "HtmlAttributes" property while defining the combo box:
#(Html.Kendo().ComboBox().Name("myCombo")
.DataTextField("Text")
.DataValueField("Value")
.Placeholder("--- Select ---")
.DataSource(src => src.Read(read => read.Action("ActionMethod", "Controller")))
.HtmlAttributes(new { style = "width: 200px;"})
)
Or from javascript:
var combobox = $("#combobox").data("kendoComboBox");
combobox.list.width(200);
Reference Link
Try adding this css.
.k-combobox
{
display: inline !important;
}
and register open event
open: function(e) {
var width = $(".k-combobox").width();
$(".k-animation-container").width(width);
$(".k-list-container").width(width - 4);
}
DEMO
update
Perhaps you need to wrap the combobox and wrap it with div.
<div id="combobox-container">
<input id="combobox" />
</div>
then change the jquery into
open: function(e) {
var width = $("#combobox-container").width();
$("#combobox-container").parent().find(".k-animation-container").width(width);
$("#combobox-container").parent().find(".k-list-container").width(width - 4);
}
UPDATED DEMO

Extjs Grid Width Calculated Wrong

I am trying to create a Extjs Grid with no vertical and horizontal scroll bars. it means that the grid should expand to infinity in both direction.
here is my code:
Ext.require([
'Ext.grid.*',
'Ext.data.*',
'Ext.util.*',
'Ext.state.*'
]);
Ext.onReady(function() {
Ext.QuickTips.init();
// setup the state provider, all state information will be saved to a cookie
//Ext.state.Manager.setProvider(Ext.create('Ext.state.CookieProvider'));
var cols = 50;
var colsData = [];
var fields = [];
for(var i=1;i<cols;i++){
colsData.push(
{
text : 'COLUMN - ' + i,
//flex : 1,
width : 120,
sortable : true,
dataIndex: 'COL'+i
});
fields.push(
{name: 'COL'+i, type: 'int'}
);
}
var myData = [];
//create data
for(var i=1;i<500; i++){
var subData = [];
for(var j=1;j<cols; j++){
subData.push(Math.floor((Math.random()*10000)+1));
}
myData.push(subData);
}
function change(val) {
return val;
}
// create the data store
var store = Ext.create('Ext.data.ArrayStore', {
fields: fields,
data: myData
});
// create the Grid
var grid = Ext.create('Ext.grid.Panel', {
store: store,
stateful: true,
//stateId: 'stateGrid',
autoHeight: true,
autoWidth: true,
autoScroll: false,
//containerScroll: false,
columns: colsData,
//height: 100,
//width: 600,
title: 'Array Grid',
renderTo: 'grid-example',
viewConfig: {
//stripeRows: false,
//forceFit: false
}
});
});
i'm rendering my grid to a div element so practically i don't use any layout or etc.
<div id="grid-example" class="myDiv"></div>
and the styles:
<style type="text/css">
body{
overflow: visible;
}
.myDiv{
display: block;
/*float: left;*/
overflow: visible;
}
</style>
Here is my browser's screen shot that shows the vertical scroll bar [just like I expected].
THE PROBLEM IS
There is NO horizontal scroll bar and part of columns just cut off from page and there is no way to see the data they are presenting.
i can see that extjs tries to calculate the height and the width for the grids. in case of height it's correct but for width it's not, the calculated width is equals to my browser's width, not to the sum of columns which are in the grid.
I appreciate any suggestion or words from your side, thank you.
any one can help me with that?
I solved this problem by registering a numbers of listeners on viewConfig.viewready, grid.columnresize and etc. So we calculate the total width of columns each time we render a grid or resize/change a visibility of a column. consequently, I expand the grid to the calculated size. something like:
var grid = Ext.create('Ext.grid.Panel', {
store: store,
stateful: true,
autoHeight: true,
columns: colsData,
title: 'Array Grid',
renderTo: 'grid-example',
viewConfig: {
listeners: {
viewready:function(){
var totalWidth = 0;
Ext.each(grid.columns, function(column, index) {
if (column.isHidden() == false)
totalWidth += column.width;
});
//console.log("Width: " + totalWidth);
grid.setWidth(totalWidth);
}
}
}
,listeners: {
columnresize: function(){
grid.viewConfig.listeners.viewready();
},
columnhide: function(){
grid.viewConfig.listeners.viewready();
},
columnshow: function(){
grid.viewConfig.listeners.viewready();
}
}
});
});
Perhaps you are loking for autoScroll? Don't know what kind of behaviour you want from the question.
The question remains, do you want the grid to have scrollbars, or do you want the div to have scrollbars, or do you want the browser to have scrollbars?
The div is a block level element in HTML. It will automatically fill the browser's width, no more, no less in your example. ExtJS will then fill that div with the grid, making the grid as large as the browser's window, no more. Since you do not allow the grid to have scrollbars, the excess columns are cut off.
If you want the grid to have scrollbars, use autoScroll set to true.
If you want the div to scroll instead, set overflow: auto instead of visible on .myDiv. You would have to specify width on the grid itself too, and make it as wide as the width of the columns.
I recommend letting ExtJS handle the scrollbar as ExtJS can use more efficient rendering if you let it (only render columns and rows that are actually visible).

Multiple rows with jcarousel

I'm trying to use jcarousel to build a container with multiple rows, I've tried a few things but have had no luck. Can anyone make any suggestions on how to create it?
This is .js code substitutions according to #Sike and a little additional of me, the height was not set dynamically, now it is.
var defaults = {
vertical: false,
rtl: false,
start: 1,
offset: 1,
size: null,
scroll: 3,
visible: null,
animation: 'normal',
easing: 'swing',
auto: 0,
wrap: null,
initCallback: null,
setupCallback: null,
reloadCallback: null,
itemLoadCallback: null,
itemFirstInCallback: null,
itemFirstOutCallback: null,
itemLastInCallback: null,
itemLastOutCallback: null,
itemVisibleInCallback: null,
itemVisibleOutCallback: null,
animationStepCallback: null,
buttonNextHTML: '<div></div>',
buttonPrevHTML: '<div></div>',
buttonNextEvent: 'click',
buttonPrevEvent: 'click',
buttonNextCallback: null,
buttonPrevCallback: null,
moduleWidth: null,
rows: null,
itemFallbackDimension: null
}, windowLoaded = false;
this.clip.addClass(this.className('jcarousel-clip')).css({
position: 'relative',
height: this.options.rows * this.options.moduleWidth
});
this.container.addClass(this.className('jcarousel-container')).css({
position: 'relative',
height: this.options.rows * this.options.moduleWidth
});
if (li.size() > 0) {
var moduleCount = li.size();
var wh = 0, j = this.options.offset;
wh = this.options.moduleWidth * Math.ceil(moduleCount / this.options.rows);
wh = wh + this.options.moduleWidth;
li.each(function() {
self.format(this, j++);
//wh += self.dimension(this, di);
});
this.list.css(this.wh, wh + 'px');
// Only set if not explicitly passed as option
if (!o || o.size === undefined) {
this.options.size = Math.ceil(li.size() / this.options.rows);
}
}
This is the call in using the static_sample.html of the code bundle in the download of jscarousel:
<script type="text/javascript">
jQuery(document).ready(function() {
jQuery('#mycarousel').jcarousel( {
scroll: 1,
moduleWidth: 75,
rows:2,
animation: 'slow'
});
});
</script>
In case you need to change the content of the carousel and reload the carousel you need to do this:
// Destroy contents of wrapper
$('.wrapper *').remove();
// Create UL list
$('.wrapper').append('<ul id="carousellist"></ul>')
// Load your items into the carousellist
for (var i = 0; i < 10; i++)
{
$('#carouselist').append('<li>Item ' + i + '</li>');
}
// Now apply carousel to list
jQuery('#carousellist').jcarousel({ // your config });
The carousel html definition needs to be like this:
<div class="wrapper">
<ul id="mycarousel0" class="jcarousel-skin-tango">
...<li></li>
</ul>
</div>
Thanks to Webcidentes
We have had to make a similar modifiaction. We do this by extending the default options, to include a rows value, and the width of each item (we call them modules) then divide the width by the number of rows.
Code added to jCarousel function...
Add to default options:
moduleWidth: null,
rows:null,
Then set when creating jCarousel:
$('.columns2.rows2 .mycarousel').jcarousel( {
scroll: 1,
moduleWidth: 290,
rows:2,
itemLoadCallback: tonyTest,
animation: 'slow'
});
The find and edit the lines in:
$.jcarousel = function(e, o) {
if (li.size() > 0) {
...
moduleCount = li.size();
wh = this.options.moduleWidth * Math.ceil( moduleCount / this.options.rows );
wh = wh + this.options.moduleWidth;
this.list.css(this.wh, wh + 'px');
// Only set if not explicitly passed as option
if (!o || o.size === undefined)
this.options.size = Math.ceil( li.size() / this.options.rows );
Hope this helps,
Tony Dillon
you might want to look at serialScroll or localScroll instead of jcarousel.
I found this post on Google Groups that has a working version for multiple rows. I have used this and it works great. http://groups.google.com/group/jquery-en/browse_thread/thread/2c7c4a86d19cadf9
I tried the above solutions and found changing the original jCarousel code to be troublesome - it introduced buggy behaviour for me because it didn't play nice with some of the features of jCarousel such as the continous looping etc.
I used another approach which works great and I thought others may benefit from it as well. It is the JS code I use to create the li items to support a jCarousel with multiple rows with elegant flow of items, i.e. fill horizontally, then vertically, then scrollpages:
123 | 789
456 | 0AB
It will add (value of var carouselRows) items to a single li and as such allows jCarousel to support multiple rows without modifying the original jCarousel code.
// Populate Album photos with support for multiple rows filling first columns, then rows, then pages
var carouselRows=3; // number of rows in the carousel
var carouselColumns=5 // number of columns per carousel page
var numItems=25; // the total number of items to display in jcarousel
for (var indexpage=0; indexpage<Math.ceil(numItems/(carouselRows*carouselColumns)); indexpage++) // for each carousel page
{
for (var indexcolumn = 0; indexcolumn<carouselColumns; indexcolumn++) // for each column on that carousel page
{
// handle cases with less columns than value of carouselColumns
if (indexcolumn<numItems-(indexpage*carouselRows*carouselColumns))
{
var li = document.createElement('li');
for (var indexrow = 0; indexrow < carouselRows; indexrow++) // for each row in that column
{
var indexitem = (indexpage*carouselRows*carouselColumns)+(indexrow*carouselColumns)+indexcolumn;
// handle cases where there is no item for the row below
if (indexitem<numItems)
{
var div = document.createElement('div'), img = document.createElement('img');
img.src = imagesArray[indexitem]; // replace this by your images source
div.appendChild(img);
li.appendChild(div);
}
}
$ul.append(li); // append to ul in the DOM
}
}
}
After this code has filled the ul with the li items jCarousel should be invoked.
Hope this helps someone.
Jonathan
If you need a quick solution for a fixed or one-off requirement that definitely doesn't involve changing core library code which may be updated from time to time, the following may suit. To turn the following six items into two rows on the carousel:
<div class="item">contents</div>
<div class="item">contents</div>
<div class="item">contents</div>
<div class="item">contents</div>
<div class="item">contents</div>
<div class="item">contents</div>
you can use a little JS to wrap the divs into LI groups of two then initialise the carousel. your scenario may allow you to do the grouping on the server isn't always possible. obviously you can extend this to however many rows you need.
var $pArr = $('div.item');
var pArrLen = $pArr.length;
for (var i = 0;i < pArrLen;i+=2){
$pArr.filter(':eq('+i+'),:eq('+(i+1)+')').wrapAll('<li />');
};

Categories

Resources