How to efficiently have many readonly Monaco Diff Views on one page? - javascript

My understanding is that Monaco is optimized for editing, and for having showing one file at a time, with a fixed size editor that has its own scroll bar.
Instead I am trying to build one page with the diffs of multiple files below each other
allowing showing/hiding each file, up to ~100 files
hiding portions of the file that have not changed (and allowing to show them as context if desired)
not have one scrollbar per file, but one for the entire page
the files are usually view-only, but editing should be supported for one file at a time
I realize this is quite the departure from what Monaco was built for, but in the end it seems as if the same viewport and virtual rendering tricks would apply, so maybe it is somehow possible?
I tried creating one Monaco instance per file, but that starts getting really sluggish around 30 instances.
One pretty ugly workaround might be to have a single Monaco instance, concat all the files, and then work with ViewZones, custom line number providers and code folding providers to achieve the impression of multiple files. Is that as crazy as it sounds, or might that actually work?
Any other suggestions? Why does IStandaloneDiffEditor have standalone in the name? Does that mean there is another way to create many diff editors that is more efficient?

Citate from your question:
I tried creating one Monaco instance per file, but that starts getting really sluggish around 30 instances.
The solution for your question
As you mentioned the perfomance was sluggish. This is because your server or may be your client has not enough memory. You have to add more memory to the server or may be to the client for more perfomance. Because I do not have enough information I can not say it is the server or the client. But this method is not efficient.
Citate from your question:
Why does IStandaloneDiffEditor have standalone in the name? Does that mean there is another way to create many diff editors that is more efficient?
Nothing from it. In Wikipedia I found the answer what standalone means:
Standalone software may refer to:
Computer software that can work offline, i.e. does not necessarily require network connection to function.
Software that is not a part of some bundled software.
A program that run as a separate computer process, not an add-on of an existing process.
Standalone program, a program that does not require operating system's services to run.
A portable application, which can be run without the need for installation procedure.
This means that standalone has nothing to do with single instance and you could have multiple instances of this editor. But you have to have more memory on your computer(s) to create 100 instances from this editor. And this it not efficient because you have 100 big JavaScript objects more in your memory.
On other services for display the difference between changed files they make it with DOM objects only or with DOM objects + one big instance from big JavaScript object which creates this objects, but not additional 100 big instances from big JavaScript objects.
Accordingly to this princip in this case you could use code from my recommended solution below and in background cleate only one instance from this difference editor. Then you have to put to this instance all your 100 files one after other and copy in each case from one file following DOM objects:
<div class="editor original showUnused" ...
<div class="editor modified showUnused" ...
This could you do for example with following code:
var diffPartContainars = document.querySelector('#container').querySelectorAll('.showUnused'),
editorOriginalPartHTML,
editorModifiedPartHTML;
for(var i = diffPartContainars.length; i--;)
{
var obj = diffPartContainars[i],
cln = obj.className;
if(cln.indexOf('editor original') > -1)
{
obj.removeAttribute('style');
editorOriginalPartHTML = obj.outerHTML;
}
if(cln.indexOf('editor modified') > -1)
{
obj.removeAttribute('style');
editorModifiedPartHTML = obj.outerHTML;
}
}
Then you have to delete from each editorOriginalPartHTML and editorModifiedPartHTML following DOM objects:
<div class="invisible scrollbar horizontal" ...
<canvas class="decorationsOverviewRuler" ...
<div class="visible scrollbar vertical" ...
and all other objects which you can not use. You can do it when you add editorOriginalPartHTML and editorModifiedPartHTML to your DOM. Then you can add around each from it one div object with suitable width, height and style="overflow:auto". And one thing you could do more: for each from this div objects you could add one onclick or onmouseover listener and then replace this div object view with your difference editor instance.
This is only one way in my opinion to be more efficient. Good luck!
The recommended efficient solution
The quickly, comfortable and efficient way to have only one instance of this editor and load a new sources on the click on the file names like below.
var diffEditor = null;
var filesContent =
{
'SomeJavaScriptFile.js':
{
originalContent: 'alert("heLLo world!")',
modifiedContent: 'alert("hello everyone!")',
type: 'text/javascript'
},
'AnotherJavaScriptFile.js':
{
originalContent: 'function open(str)\n{\n\talert(str)\n}',
modifiedContent: 'function output(value)\n{\n\tconsole.log(value)\n}',
type: 'text/javascript'
}
};
document.querySelector('#files').addEventListener('change', function(e)
{
var fileName = this.options[this.selectedIndex].text,
file = filesContent[fileName];
openInDiffEditor(file);
});
function openInDiffEditor(file)
{
if(!diffEditor)
diffEditor = monaco.editor.createDiffEditor(document.querySelector('#container'));
diffEditor.setModel({
original: monaco.editor.createModel(file.originalContent, file.type),
modified: monaco.editor.createModel(file.modifiedContent, file.type)
});
}
//open the first file in select list:
var firstFileName = document.querySelector('#files').options[0].text;
openInDiffEditor(filesContent[firstFileName]);
<p>Please select one file on the left list to see the file differences after changes.</p>
<select id="files" size="3">
<option selected>SomeJavaScriptFile.js</option>
<option>AnotherJavaScriptFile.js</option>
</select>
<div id="container" style="height:100%;"></div>
And file contents you have to load over AJAX. But in the case if you do not understand how to load it then ask me and I will write it.
The screenshot of this recommended solution

Related

Manipulate values ​between html pages

I'm creating a portfolio, and in that portfolio there will be several cards, and the purpose of these cards will be for them to be redirected to another page with detailed information. And that's where the question comes in, instead of creating an html page for each card wouldn't it be advantageous to make a page only, and change the values ​​between each card when clicked on js ?
A buddy told me that there is a rounter property of react, where it is possible to do this, but the project is simple for now, and I would like to solve this issue with js.
Below is a separate example (which is not part of the main project):
Main page:
Aqui
Teste
Page 2
<div id="main">
<h1 id="title">Lindo</h1>
</div>
Js
let a1 = document.getElementById('a1');
var aa = document.getElementById('aa');
var h1 = document.querySelector('#title');
var main = document.getElementById('main');
if (onclick == a1) {
title.innerText = "Leandro O cachorro";
main.style.backgroundColor = 'green';
}else if(onclick == aa){
console.log('era pra estar vermelho');
title.innerText = "Belle Belinha";
main.style.backgroundColor = 'red';
}
I tried to use the if-else sentence, but it only takes the first if, even clicking on link 2
instead of creating an html page for each card wouldn't it be advantageous to make a page only, and change the values ​​between each card when clicked on js ?
Of course, everyone loves that way.
Frankly speaking, it is possible but you can't achieve this with just what you are showing above. I think you can't achieve what you want in that way.
So instead, I will recommend you to use react. In case you don't like it, take a look of alternatives below.
If you consider react is overkill, you can try a simpler solution: static site generator. Check: Hugo, Jekyll, Eleventy, etc... These approaches help you focus on site building instead of architecture and technical building.
If you want a lighter solution and prefer to do more stuff, then pick a bundler like webpack, rollup, parcel, etc... and then apply templating libraries likes Handlebar JS, Mustache JS, Liquid JS, EJS, etc... This approach will give you more chance to do low-level stuff and super lightweight.
Lastly, build everything from scratch. yes, still possible but sure unless you know most of the things and know where to go, and what to do.
The only one trick I could think of for exchanging information between different pages while only using front-end javascript: You can link to the other page using parameters at the end:
I.E.:
myUrl + "?myParameter1=myValue1&myParameter2=myValue2"
Now on that second page you could retrieve those parameters using:
var url = new URL(window.location.href);
url.searchParams.get("myParameter1"); // "myValue1"
url.searchParams.get("myParameter2"); // "myValue2"
//...
...and depending on the parameter(s) passed, you can now display different content on the page, which can even be bookmarked or even shared via the link (as a nice sideffect).
Edit: Sorry, I might have misunderstood your question, but maybe this helps you to find an alternate solution anyway (at least you won't have to make a new html page for EVERY card, just one).

Some SiteCatalyst eVar values not passing in Custom Link

I'm facing a crazy matter with a SiteCatalyst Custom Link (internal) request.I'm firing an s.tl() through the code below:
var s_custom = s_gi("report-suite");
s_custom.linkTrackVars = "eVar76,events,list3";
s_custom.linkTrackEvents = "event87";
s_custom.events = "event87";
s_custom.eVar76 = "value";
s_custom.list3 = "option1,option2";
s_custom.tl(this, 'o', 'link name');
The issue concerns the eVar76, whose value is not included in the request, even if the "s_custom" TrackerObject contains it. In fact, if I inspect that object I find it.This strange seems to affect just "high" number eVars, like eVar76, 77, 80, 99 and so on, not lower ones.Replacing eVar76 with eVar55, 56 or 60, for ex, is resulting in a normale behaviour where values are normally included in requests.This is not depending on eVars existance, or activation, in the report suite and this is expected because no preliminar calls are made to Adobe server in order to check the set, or enabled, eVars in that report suite.This is a very silly behaviour forcing me to replace the desired eVar with another one.I just add that this Custom Link is prepared by a Page-load (DOM ready) rule in the Adobe DTM, but I suppose that no particular setting should be done in order to fix it.This is the first time that an SC variable is not included in request as expected.Thanks so much for supporting me.
The core Adobe Analytics library code builds the request string with a loop that looks for events/eVars up to the max available. Adobe Analytics only recently expanded events from 100 to 1000 and eVars from 75 to 100/250, so in order to accommodate this increase, an update to the core AppMeasurement library code was made.
Note: Although Adobe has been making updates to the Legacy H library alongside AppMeasurement, they did not update the Legacy H library to accommodate this increase. So, in order to track eVar76+ and event101+ within javascript as the variable (e.g. s.eVar76='foobar'), you must upgrade to the latest AppMeasurement library.
Alternatively, if you are using Legacy H.23+ library you can instead populate it as a contextData variable and then map it to the event/eVar/prop in a processing rule (e.g. s.contextData['eVar76']='foobar' and then in processing rule you'd have e.g. if [(contextdata) eVar76] [is set] then overwrite [eVar76] with [(contextdata) eVar76])
Reference: https://marketing.adobe.com/resources/help/en_US/sc/implement/evars_events.html

html iframes vs jquery.load() when adding content dynamically (no php, etc.) [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 9 years ago.
Improve this question
I am working on a project where I need to dynamically build up web content coming from different sources (same domain). All the main libraries and css are managed centrally but depending on a configuration I have to add pages (html and embedded JavaScript) as 'tab content'.
My first approach was using iframes and it worked well besides the annoyance that I had some duplicte code (especially the header). I also had some issues with frame sizes but I could handle that in the end.
Now of course I read that iframes are evil but almost all the alternatives I found were using php or something else server-side. Unfortunately my web server does not provide anything like that, so I came across jQuery's load function. My first attempt is satisfying but what unsettles me now is managing (global) variables (and functions). Because jQuery.load() simply inserts the code into the DOM I always need to be extremely careful about naming here. For example I usually have a function called init() which is included in the body for the onload-Event. But every other page will need one of those as well.
The project is very likely to grow (maybe at some point even external developers will take part). I am now at a point where I have to decide which path to take and I am torn.
So my Question: Even though iframes are evil, im my experience it is a lot easier and secure than inserting the code via jQuery (in this particular case). Oh, that was not a question... The question would be: Is there any way to encapsulate variables and functions into the content that I load with jQuery? Or might there be a better way of handling variables/functions in this case anyways.
I am grateful for any suggestions.
I don't want to suggest to do it this way, but because you want to to know how this can be done, here some code to illustrate how it could be done (only rudimentary tested and should not be used without further testing).
While I'm not sure if you could (and i think you should not) structure your project that way i hope that it will help to solve your problem.
The main code of your page:
var app = {};
(function() {
var nextId = 1;
var elementById = {};
app.registerContent = function( id, initFunction ) {
try {
initFunction(elementById[id]);
} catch( e ) {
//if an error happend in the init script catch it so that the script will not break
console.error(e);
}
//remove the jquery element from the list
delete elementById[id];
}
//custom loader to handle init script
jQuery.fn.customLoader = function(url) {
var elm = $(this);
var id = nextId++;
//store the element where the data is loaded to in a list
elementById[id] = elm;
$.get(url,function(data) {
//replace the id in the script so that the element the data is loaded into
// can be passed to the init script later.
data = data.replace("%%unique-id%%",id);
elm.html(data); //append the data to the element
});
}
//a sample how you would load the content
$(function() {
$(".dest").customLoader("content.html");
});
})();
The code in your requested data:
<div>some content</div>
<!-- the script that correspons to that part -->
<script>
//create a scope using a function that is executed directly
(function() {
//using var to make the variables only visible to this place
var uniqueId = %%unique-id%%; //this will be replaced by the loader to identify the element where the data is loaded to
var someVar = 1;
app.registerContent(uniqueId, initFunctionForTheContent)
function initFunctionForTheContent(element) {
element.css("background-color", "red")
}
})();
</script>
Not having a back end with a huge app and many developers sounds like hell. Sometimes things are best fitted on the server side e.g php's include.
Either way I would go with an MVC solution.
I have experience with backbone and underscore so I will give an example with that but there are many other MVC solutions.
If all you need to do is load some data you can use underscores templating which is very lightweight
You can do stuff like:
In the model:
sum: function() {
Sum certain properties of your objects.
}
In index.html
<script type="text/template" id="sum-template">
sum: <% print(sum) %>
</script
In the view
sumTemplate: _.template($('#sum-template').html()),
this.$el.find('#sum').html(this.sumTemplate({sum:Expenses.sum()}));
As you can see you can get data from different places and load them to certain HTML elements. It easy to manage on the long run.
In order to persist data you can free and paid hosted data bases a simple google search for
redis hosting, mongodb hosting etc... so you are not dependent on your current server.

Manage javascript include files

Currently we have an extensive web-based office application written in PHP, javascript to manage various processes (billing, ordering, user management, reporting, subscription management, article managementm, warehousing etc.)
The application uses iframes to load pages that perform various functions within the main application interface. From the main page tabs are created so you can access all open pages if needed. Each page has their own javascript include-files, css etc to perform complex tasks. All iframed-pages (around 600) are on the same domain/host.
Since many people describe using iframes as 'evil', I was examining on how I could convert the application into using divs only.
The quesions I have are:
1) in a situation where there are no iframes anymore, do I need to include every used javascript files on the main start page? Or is it possible to dynamically load javascript files into the memory depending on which page you access? (inluding new function declarations etc.)
2) Can these include-files be removed completely out of the memory when someone closes a page? (in this case a div). This to avoid possible conflicts between function names & variables of different files and also not to burden the browser's memory usage.
3) Or perhaps iframes are not that 'evil' afterall, and this is a correct way for using iframes?
thanks for the advise
chees
Patrick
have you tried any code or just asking?
you can use jquery (see here)
$.getScript("ajax/test.js", function(data, textStatus, jqxhr) {
console.log(data); //data returned
console.log(textStatus); //success
console.log(jqxhr.status); //200
console.log('Load was performed.');
});
As long as your javascript is modular, you can unload it whenever you want.
In case you don't know, in Javascript functions are objects. And with objects you can do this:
var a = {b:10, c:20, d:30}; //Some memory is allocated for object a
a = null; //Object a will be deleted, and no longer need any memory
How can you use that to handle functions? Here's easiest explanation:
var myFunction = function(a,b,c) {
alert(a+b+c);
}; //Here we have a function stored in memory
myFunction = null; //And now we don't
You can make whole libraries of functions this way and then remove them with one operation. Example:
var MyMath = {};
MyMath.abs = function(a) {
return (a<0)?-a:a;
};
MyMath.min = function(a,b) {
return a>b?b:a;
}; //MyMath uses some memory.
alert(MyMath.min(5,10));
MyMath = null; //Now it does not
So, wrap all of your libraries into objects, and unload those objects whenever you need.
Added:
When your browser sees some new Javascript code - it executes it all at once. It also does save it in memory, but never uses it again (basically it is stored the same way hello is stored in <div>hello</div>). Therefore the best solution would be:
1) Add <script> tags dynamically to load desired Javascript files on demand. It will look something like:
if (MyMathLibrary == null || MyMathLibrary == undefined) {
createScriptElementForMathLibrary();
}
alert(MyMathLibrary.calculateEnthropyOfTheUniverse());
2) Whenever you no longer need the library, you just do MyMathLibrary = null. You can also delete it from DOM at this point, it won't do any harm, as I said, it is no more than invisible div at this point.
But honestly, are you sure this is worth the bother? People nowadays write 3D shooters purely in Javascript and computers come with 4-16 GB of memory. Also, it's common practice to first make a working program and bother with optimizations only if it lags. Otherwise it is likely that you will spend a month of work for something no user will ever notice.

Gloal Abatement - Using a Single Object Literal

So I just need a sanity check on the way in which I layout my code for an application. I'm always keen to learn better approaches.
I basically use an Object Literal to organise my code meaning that I have one single global variable. Then for each section of the application I create a separate object - something like:
var MYAPP = {
init : function() {
//site wide common js
},
sections : {
homepage : function() {
//homepage js
},
anotherpage : function() {
//another page js
tools.usefultool();
}
},
tools : {
usefultool : function() {
//useful reuseable method
}
}
};
My question is while this helps code organisation, I'm wondering about objects being initialised but never used. For example - if I'm on a site's homepage I'll just call MYAPP.sections.homepage() . I don't actually need any of the other objects so I'm wondering - does this structure have a performance implication? Is there a better way? The structure closely follows the the great Rebecca Murphy article "Using Object to Organise Your Code" (http://blog.rebeccamurphey.com/2009/10/15/using-objects-to-organize-your-code).
Thanks!
Yes, there's always a performance hit in unused code as the parser has to actually interpret the code even if it's not executed. But any performance hit here is so minute that you're never going to notice it. The only real hit in unused code like this is in the bandwidth required to download it. If you have a 100kb file downloaded that you never use then you're wasting the time to download that file.

Categories