I am developing an Adobe CEP panel for Adobe software, and when this "fetch" files from a computer (synchrony), it shows them as list of divs.
The idea is to create a List View that represents the files as a header (h2) in every file of the computer. However, when there are 400 files and more, it becomes very lagging, and after maybe 30 seconds, the whole divs are loaded.
The CEP panel is an HTML file that runs on chromium browser.
Is there any way to make it faster? maybe the idea of creating element in a loop over the files is not efficient?
Just to enlighten those who doesn't familiar with Adobe CEP, the cool idea of the CEP that it actually runs on a different thread of the Adobe software, thus this does not stuck the user from continuing using the software tools...
Any ideas will be useful for me.
here is my code of creating the elements:
filesArray.forEach( element => {
var fileName = element.slice(0,element.length-4)
var fileID = makeFileid();
var div = document.createElement("div");
div.setAttribute("style", "border-bottom: 1px solid #9B9B9B")
div.setAttribute("class", "fonts");
div.classList.add("row");
var div2 = document.createElement("div");
div2.classList.add("column");
var h3 = document.createElement("h3")
h3.setAttribute("class" , "h3");
var h2 = document.createElement("h2");
h2.setAttribute("style" , "margin-right: 10px; font-size: 20px");
h2.setAttribute('id', element)
h2.setAttribute("onclick", "sayWho(this)")
div.appendChild(div2);
div2.appendChild(h3)
div2.appendChild(h2);
fontDiv.appendChild(div);
h3.innerText = fileName;
h2.innerText = 'The files of the computer';
var newStyle = document.createElement('style');
newStyle.appendChild(document.createTextNode('\
#font-face {\
font-family:"Ariel";\
));
document.head.appendChild(newStyle);
});
Thanks,
In my experience, this should be faster than manually creating every single element:
especially if the markup gets to a significant size.
fontDiv.innerHTML = `<style>
#font-face {
font-family: "Ariel";
}
</style>
${filesArray.map(element => {
var fileName = element.slice(0, element.length - 4);
var fileID = makeFileid();
return `<div class="fonts row"
style="border-bottom: 1px solid #9B9B9B">
<div class="column">
<h3 class="h3">${fileName}</h3>
<h2 id="${element}"
style="margin-right: 10px; font-size: 20px"
onclick="sayWho(this)">
The files of the computer
</h2>
</div>
</div>`
}).join("\n")}`
If this doesn't help, you can
a) break the list down into smaller chunks and add them with a small delay in between.
b) check out list virtualization
You can try by using map and that will create an array of html elements. Once the array is formed then use join with comma delimiter.
At the end append all the child once in the head , so you will not access dom multiple time , since accessing dom is a costly process
Related
Last year, I wrote a bookmarklet that allowed to reorder Jitsi video tiles in alphabetic order.
Unfortunately, the script does not seem to work with the recent Jitsi versions anymore.
I have already adjusted the access to the required elements, this is working fine again.
However, the order: n attribute of the elements is ignored know, even when I set the parent to display:flex, remove the position: absolute and the left|top:n px.
I played around with the CSS and looked into documentation, but given I am no frontender, I am currently stuck.
How can I change the CSS, so that the tiles are reordered?
As a clarification, I am only looking for where I need which changes in the CSS, no scripted solution. I can take care of the scripting. Achieving a swap of two video tiles while not breaking the look would be sufficient probably.
The below information are not necessary, but might be helpful to answer the question.
Below is a screenshot showing the position in the DOM tree:
DOM tree leading to the video tiles (seems I need more reputation to embed the image)
And here is the the javascript that allows to directly access the elements:
var numberOfVideos;
function getNumberOfParticipants(){
// works
}
function getNameOfParticipant(i){
var container = $('#remoteVideos')[0];
var jChildren = $(container).children();
var jChildren2 = jChildren[1].firstChild.children;
return [jChildren2[i].getElementsByClassName("displayname")[0].innerHTML, jChildren2[i] ];
}
function sortParticipants(){
numberOfVideos = getNumberOfParticipants();
var names = new Array();
//only applicable in tiles mode!
for(i=0; i<numberOfVideos; i++) {
names[i] = new Array (2);
names[i] = getNameOfParticipant(i);
}
//sort Array
names.sort((a, b) => a[0].localeCompare(b[0]));
//reorder the tiles
for(i = 0; i < numberOfVideos; i++){
$(names[i][1]).css('order', i); //this is the line that worked in 2021, but the `order` attribute is now being ignored
}
}
https://github.com/kaiyazeera/jitsi-bookmarklets/blob/master/alphabeticSort-auto0.js
The problem could be solved by modfying the global CSS:
var css = document.createElement("style");
css.type = "text/css";
css.innerHTML = ".videocontainer { position:relative !important; top: unset !important; left: unset !important; text-align:center;overflow:hidden; }"
var css2 = document.createElement("style");
css2.type = "text/css";
css2.innerHTML = ".tile-view .remote-videos > div {flex-wrap:wrap;}"
document.body.appendChild(css)
document.body.appendChild(css2)
First of all, sorry for my bad English, isn't the best ;)
So I'm new to working with JavaScript, Ajax and, jQuery. Since a young age I've been interested in coding. A friend of mine wants an update on their website I made for them a little while ago. They have a small podcast/radio station.
What I'm trying to do is make an automatic link between the podcasts they post on MixCloud and their website. I followed some tutorials and grave throw the forms on this website, but I can't get the script to work properly and get the information out of the JSON file that MixCloud makes with their API.
This is what I've got so far. I can't figure out what I'm doing wrong since I'm very very new to this. I tried different methods, but this is the closest I've got.
const Http = new XMLHttpRequest();
const url = 'https://api.mixcloud.com/itmotr-radio/cloudcasts/';
Http.open("GET", url);
Http.send();
Http.onreadystatechange = (e) => {
console.log(Http.responseText)
}
function append_json(XMLHttpRequest) {
//Set Up the template
var s = $("#postTemplate")[0].innerHTML.trim();
var holder = document.createElement('div');
holder.innerHTML = s;
var template = holder.childNodes;
var episode = document.getElementById('episodes');
Object.keys(XMLHttpRequest).forEach(function(object) {
//Clone Template
var newEpisode = $(template).clone();
//Populate it
$(newEpisode).find(".data.name").html(object.episodetitle);
var img = $(newItem).find(".data.pictures.320wx320h")
$(img).attr("src", object.coverimg)
//Append it
$(".episodes").append(newEpisode);
});
}
$("document").ready(function() {
append_json(XMLHttpRequest);
});
.episodes {
background: white;
display: grid;
grid-gap: 10px;
grid-template-columns: repeat(auto-fit, minmax(320px, 380px));
grid-auto-rows: 370px;
grid-auto-flow: dense;
justify-content: center;
padding-top: 10px;
}
.episode {
background: rgb(255, 255, 255);
border: 1px solid grey;
text-align: center;
}
.episodetitle {
font-size: 20px;
color: red
}
.coverimg {
width: 320px;
max-height: 320px
}
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div class="episodes">
<script type="text/template" id="postTemplate">
<div class="episode">
<img class="coverimg" src="">
<p class="episodetitle"></p>
</div>
</script>
</div>
For some reason, I can't get the data out of the JSON file and it won't show in the HTML. I built this script with a lot of help from this article: Populate grid <div> & <p> with JSON data file
Can someone help me out and get it working with me?
The JSON file that needs to be read is:
https://api.mixcloud.com/itmotr-radio/cloudcasts/
There's a few things going on so I will address each individually, and you can put them together as the learning :) Your general structure is OK though, nice going so far!
jquery
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js">/script>
this is an old version, use
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
AJAX
const Http = new XMLHttpRequest();
const url='https://api.mixcloud.com/itmotr-radio/cloudcasts/';
Http.open("GET", url);
Http.send();
Http.onreadystatechange=(e)=>{
console.log(Http.responseText)
}
This is all taken care of within jquery automatically. Have a read of the AJAX documentation. This is a good example to learn with, it's quite simple (lots of defaults you can use).
$.ajax({
url:'https://api.mixcloud.com/itmotr-radio/cloudcasts/',
success:function(data){
//Do stuff with the data here (as JSON, it should be auto parsed into an object)
//for example (psuedo code..)
for(var i = 0; i < data.length;i++){
//Use the data variable passed in with the success function.
createNewElement(data[i]) // do something with each object in the array (see below)
}
})
Create new element
var newEpisode = $(template).clone();
//Populate it
$(newItem).find(".data.name").html(object.episodetitle);
var img = $(newItem).find(".data.pictures.320wx320h")
$(img).attr("src", object.coverimg)
//Append it
$(".episodes").append(newEpisode);
As you have jquery already we can use a lot of the functions easily. The element to append we can build in jquery, or just use a string in javascript containing your HTML. As you are adding in dynamic data, it makes sense to make the elements.
createNewElement(datum){
// This function creates a new element each time it is called and appends it to the
let $para = $('<p></p>') // make new <p> element
.addClass('episodetitle') // add the class property and actual classes
.text(thing.episodetitle) // set the text content of the element
//we have created "<p class='episodetitle'>This is the Title</p>"
//Alernatively we can do it all in one go
let $img = $('<img class="coverimg" src="'+datum.imagesource+'"/>')
// Now we create the container div for these 2 elements
let $newEpisode = $('<div></div>').addClass('episode')
$newEpisode.append($para) // Add the para into our div
.append($img) // append the image element into the div
$(".episodes").append($newEpisode); // append the div to the coagulate div
}
#Tobin
So now I edited my script to this:
$.ajax({
url:'https://api.mixcloud.com/itmotr-radio/cloudcasts/',
success:function(data){
//Do stuff with the data here (as JSON, it should be auto parsed into an object)
var newEpisode = $(template).clone();
//Populate it
$(newItem).find(".data.name").html(object.episodetitle);
var img = $(newItem).find(".data.pictures.320wx320h")
$(img).attr("src", object.coverimg)
let $para = $('<p></p>').addClass('episodetitle').text(thing.episodetitle)
let $newEpisode = $('<div></div>').addClass('episode')
$newEpisode.append($para)
// GETTING A ERROR :28 Uncaught SyntaxError: Identifier '$para' has already been declared. When trying to do the same for the coverimg.
let $para = $('<p></p>').addClass('coverimg').text(thing.coverimg)
let $newEpisode = $('<div></div>').addClass('coverimg')
$newEpisode.append($para)
//Append it
$(".episodes").append(newEpisode);
}
})
But now de second $para gives me an error because it's already declared...
But I made one change in the first script, changed a 'newItem' to 'newEpisode' and now it renders my layout, but none of the information in the JSON file is loaded in. And it makes 5 items, while there are supposed to be 2 'files' in the JSON file. What goes wrong here?
I have a gallery page that is updated often with new images. I use simple HTML to post the photos. My process currently is copy and paste the set of tags for a photo and change the number to correspond with the image file name. E.G. I change the number 047 to 048. Copy-Paste, change it to 049. This goes on until I have reached the number of additional photos. As you can see, this is very inefficient and there must be a better way of doing this. I was wondering if there is a simpler way to achieve this with Javascript? Perhaps generate additional tags by inputing a certain number or range?
Any ideas that would make this process efficient are welcomed please! Thank you!
<div class="cbp-item trim">
<a href="../assets/images/trim/img-trim-047.jpg" class="cbp-caption cbp-lightbox" data-title="">
<div class="cbp-caption-defaultWrap">
<img src="../assets/images/trim/img-trim-047.jpg" alt="">
</div>
</a>
</div>
You could use a templating solution. There are several libraries for that, but you can also implement it yourself.
Here is one way to do that:
Put the HTML for one image in a script tag that has a non-standard language property so the browser will just ignore it
Put some keywords in there that you'll want to replace, e.g. {url}. You can invent your own syntax.
Read that template into a variable
In the JS code, put all the images' URLs in an array of strings
For each element in that array, replace the keywords in the template string with that particular URL, and concatenate all these resulting HTML snippets.
Inject the resulting HTML into the appropriate place in the document.
Here is a snippet doing that:
// Add new images here:
var images = [
"https://upload.wikimedia.org/wikipedia/commons/thumb/e/e0/SNice.svg/330px-SNice.svg.png",
"https://nettemarie357.files.wordpress.com/2014/09/smiley-face.jpg?w=74&h=74",
];
// Load the template HTML
var template = document.querySelector('script[language="text/template"]').innerHTML;
// Use template to insert all the images:
container.innerHTML = images.map(url => template.replace(/{url}/g, url)).join('');
img { max-width: 50px }
<div id="container"></div>
<script language="text/template">
<div class="cbp-item trim">
<a href="{url}" class="cbp-caption cbp-lightbox" data-title="">
<div class="cbp-caption-defaultWrap">
<img src="{url}" alt="">
</div>
</a>
</div>
</script>
This would help you creating it programatically:
var new_row = document.createElement('div');
new_row.className = "cbp-item trim";
var a = document.createElement('a');
a.href = "../assets/images/trim/img-trim-047.jpg";
a.className= "cbp-caption cbp-lightbox";
document.body.appendChild(a);
var div = document.createElement('div');
div.className = "cbp-caption-defaultWrap";
var img = document.createElement('img');
img.src= "../assets/images/trim/img-trim-047.jpg";
div.appendChild(img);
a.appendChild(div);
new_row.appendChild(a);
If it is just about printing HTML, I suggest you to use plugins like Emmet for Sublime Text editor.
When you install this plugin and see how it works, you can simple create a complex html in a way that 'for' loop would do this. This will help you to change only the image/link number of every item.
Check the demo in the link, that I added.
Here's an example in Java Script that will generate the html you will need. Set the total to whatever number you need to generate the number of images you want.
var total = 47;
var hook = document.getElementById('hook');
// Main Node for SlideShow
var node = document.createElement('div');
node.classList = "cbp-item trim";
// Work out the correct number
var n = function(int) {
var length = int.toString().length;
return length === 1
? '00' + int
: length === 2
? '0' + int
: length
}
// Create the item
var createItem = function(int){
// Create Anchor
var a = document.createElement('a');
a.href = '../assets/images/trim/img-trim-' + ( n(int) ) + '.jpg" class="cbp-caption cbp-lightbox';
a.classList = 'cbp-caption cbp-lightbox';
// Create Div
var div = document.createElement('div');
div.classList = 'cbp-caption-defaultWrap';
// Create Image
var img = document.createElement('img');
img.src = '../assets/images/trim/img-trim-' + ( n(int) ) + '.jpg';
img.alt = 'gallery image';
// Finalise Dom Node
var container = div.appendChild(img)
a.appendChild(div);
// Return Final Item
return a
}
// Create Items
for (var i = 1; i < total + 1; i++) {
node.appendChild(createItem(i));
}
// Append Main Node to Hook
hook.appendChild(node);
<div id="hook"></div>
I want to load the CSS file for everything.
For elements: tabs, sidebars, tags , windows, options, developer tools, etc.
I need this to change the scroll bars.
How to do it in Firefox addons-sdk?
By evrything you actually mean the browser area. So what you want to do is write CSS within the brackets of #-moz-document url("chrome://browser/content/browser.xul") { and }. Otherwise the CSS will affect things within webpages.
There are two ways to load in a CSS sheet, one is with the nsIStyleSheetService and one is with
window.loadSheet.
The window.loadSheet is the recommended way. You would do it something like this:
function registerWindows() {
var _uri = Services.io.newURI("chrome://aus-view/skin/toolbar.css", null, null);
aWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils).loadSheet(_uri, 1);
}
function unregisterWindows() {
var _uri = Services.io.newURI("chrome://aus-view/skin/toolbar.css", null, null);
aWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils).removeSheet(_uri, 1);
}
You would have to make sure to load your sheet into newly opened windows.
With the nsIStyleSheetService, you just loadAndRegisterSheet and then you don't have to worry about window opening and closing. But it's harder on performance I heard. I don't know the source on this performance though.
Cu.import('resource://gre/modules/Services.jsm');
var sss = Cc['#mozilla.org/content/style-sheet-service;1'].getService(Ci.nsIStyleSheetService);
var cssUri = Services.io.newURI('chrome://content/path/to/your/file.css', null, null);
sss.loadAndRegisterSheet(cssUri, sss.USER_SHEET);
Then when you want to remove it you just do:
sss.unregisterSheet(cssUri, sss.USER_SHEET);
Now those both used files. You can make a URI without any files like this:
var css = '';
css += '* { background-color: red; }';
css += '*.hover { background-color: blue; }';
var cssEncoded = encodeURIComponent(css);
var cssEncodedWithDataURL = 'data:text/css,' + cssEncoded
Then we just make our URI the same way: var cssUri = Services.io.newURI(cssEncodedWithDataURL, null, null); Then you just load the stylehseet the same way. (Example using 2nd method: sss.unregisterSheet(cssUri, sss.USER_SHEET))
trying to come up with very simple image rotation using pure javascript without jQuery.
Something that I could call like that and it could place the image in same spot rotating it one by one.
rotator('<img src="image1.gif"/ >','<img src="image1.gif"/ >');
maybe someone could suggest a way of doing it? thank you.
UPDATE: By Rotation I meant, one disappears, another appears. Not angle rotation.
This sort of steps beyond the call of duty and probably isn't the best solution but nonetheless. A full Javascript function (handles by tag not by image)
<html>
<head>
<script>
/*rotate
desc: Rotate a set of first level child objects based on tag name
params:
id = Rotate elements container id
tag = Tag (nodeName - see textNode issue) of DOM objects to be cycled
*/
function rotate(id, tag)
{
/*Normalise string for later comparison*/
tag = tag.toLowerCase();
/*Get container DOM Object*/
var el = document.getElementById(id),
visibleIdentified = false;
hasBeenSet = false,
firstMatchingChild = false;;
/*Iterate over children*/
for(i = 0; i < el.childNodes.length; i++){
/*Set child to var for ease of access*/
var child = el.childNodes[i];
/*If element has the correct nodeName and is a top level chlid*/
if(child.parentNode == el && child.nodeName.toLowerCase() == tag){
/*Set first matching child in case the rotation is already on the last image*/
if(!firstMatchingChild)
firstMatchingChild = child;
/*If child is visible */
if(child.style.display == "block"){
/*Take note that the visible element has been identified*/
visibleIdentified = true;
/*Toggle its visibility (display attribute)*/
child.style.display = "none";
/*Once the visibile item has been identified*/
}else if(visibleIdentified){
/*If the next item to become visible has been set*/
if(hasBeenSet){
/*Toggle visibility (display attribute)*/
child.style.display = "none"
}
/*Catch the next item to become visible*/
else{
/*Toggle visibility (display attribute)*/
child.style.display = "block";
/*Take note that the next item has been made visible*/
hasBeenSet = true;
}
}
}
}
/*If the hasBeenSet is false then the first item is to be made visible
- Only do so if the firstMatchingChild was identified, more or less redundant
exception handling*/
if(!hasBeenSet && firstMatchingChild)
firstMatchingChild.style.display = "block";
}
/*Declare cycle*/
setInterval("rotate('test','div')",1000);
</script>
</head>
<body>
<!-- Example container -->
<div id="test">
<div style="display:block">fire</div>
<div style="display:none">water</div>
<div style="display:none">shoe</div>
<div style="display:none">bucket</div>
</div>
</body>
</html>
Your specific question I haven't seen before, but your basic premise has been asked many times. The reason why you can't find a call like
rotate('<img src="1" />', '<img src="2" />');
is because it is a bad idea according to programming practices. You are mixing content with script. Client-side web design relies on sandboxing certain features to speed development and make debugging easier. Content, Styling and Scripting are the major areas. Here you mix content (images) with scripting. You should really use one of the many existing image rotation scripts that rely on taking existing markup and rotating them.
<img src="a" />
<img src="b" />
<script>rotateImages();</script>
If you want to do it your way then you will need to parse your strings and then create element nodes based on them. Honestly I don't think its worth the time to code one up in that format unless this is for curiosity's sake.
I am going to answer my own question as I came up with solution by my own. Sorry if I did not explain well and I hope it could be useful to someone as well. I had to avoid jQuery for a special reason, sometimes its just has to be that way. Here is the code, feel free to comment and improve... a working version is here http://jsbin.com/oxujuf/3
function rotator(options) {
var a = options.delay;
var b = options.media;
var mediaArr = [];
for(var i = 0, j = b.length; i < j; i++) {
mediaArr.push(b[i].img);
}
document.write('<div id="rotatorContainer"></div>');
var container = document.getElementById('rotatorContainer');
var Start = 0;
rotatorCore();
function rotatorCore() {
Start = Start + 1;
if(Start >= mediaArr.length)
Start = 0;
container.innerHTML = mediaArr[Start];
setTimeout(rotatorCore, a);
}
}
And then later you may call it like that, with a simple API.
rotator({
delay : 3500,
media : [{
img : '<img src="http://lorempixel.com/output/abstract-h-c-149-300-7.jpg" width="149" height="300" border="0" />'
}, {
img : '<img src="http://lorempixel.com/output/abstract-h-c-149-300-2.jpg" width="149" height="300" />'
}]
});
This is covered on many older forums and blogs.
Here are a couple links:
http://www.go4expert.com/forums/showthread.php?t=1012
http://www.reachcustomersonline.com/2008/03/19/09.38.04/?doing_wp_cron=1326819656