How I can get the total number of addedfiles in addedfile event?
uploader.on("addedfile", function(file){
here - how I can get the total number of addedfiles?
});
Thanks a lot for the help.
this.files always holds the list of all files that have been dropped.
If you only want to get the files that have been accepted, you can use this.getAcceptedFiles();
So to answer your question, use either of those:
var totalFileCount = this.files.length;
// or
var totalFileCount = this.getAcceptedFiles().length;
Related
I put together a script for Google Sheets which resets the filters on each sheet (YR5, YR6, YR7 and YR8) and then re-orders the sheets by 3 columns. It's needed as users often leave the sheets filtered and then mistakes are made when entering data as rows are hidden.
The script works as expected, but is there a way to optimise this so it will run any faster? I'm very new to Google Apps script and have put this together from various other people's work.
Thanks :)
This is the script:
function clearFilter(sheet) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var YRS = ['YR5','YR6','YR7','YR8'];
var pos = 0;
for (var i = 0; i <=3; i = i + 1) {
var sheet = ss.getSheetByName(YRS[pos]);
var filter = sheet.getFilter();
var range = filter.getRange();
filter.remove();
range.createFilter();
var filter = sheet.getFilter();
filter.sort(1, true);
filter.sort(4, true);
filter.sort(6, true);
pos = pos + 1
}
SpreadsheetApp.getUi().alert("Ready to edit");
}
I think your best bet is to try checking if the filters have been changed before recreating them. This wouldn't help in cases where every sheet's filter has been changed, though. Using filter.getColumnFilterCriteria(columnPosition) looks helpful for this.
Instead of removing the filter, is it enough to only re-sort the first, fourth, and sixth columns? This could make a reasonable dent in performance. But you'd probably want to call filter.removeColumnFilterCriteria(columnPosition) for each column before re-sorting, though, and I don't know if doing that will be slower than just removing and re-creating a filter.
(Other methods on the filter object)
Finally, I'll mention a couple very minor optimizations that probably won't make a dent, which are removing the 'sheet' parameter and making it a local variable, and removing the pos variable and using i instead for accessing the YRS array.
If the problem is that users leave a sheet in a filtered state, you can avoid the whole issue by instructing them to use filter views instead of a regular filter. This feature lets multiple simultaneous users sort, filter and edit the sheet without disturbing each other.
For additional ease of use, you can insert links in the frozen section of the sheet to easily switch between filter views, instead of having to go to Data > Filter views to switch. See the Filter views example spreadsheet for an illustration.
I have j-Query data-table with many records and I have builtin search-box. What I am trying is to sum all values in all the tds which have class="amount". It's happening succesfully. Now, the problem is search box. I want to sum the values of tds with class name amount which are only visible. I tried many ways but nothing worked Following is my code:
var salaryTable = $('#tblSalary').DataTable();
salaryTable.on('search', function () {
var sum = 0;
$(".amount").each(function() {
var value = $(this).text();
if(!isNaN(value) && value.length != 0) {
sum += parseFloat(value);
}
});
alert(sum);
});
This logic is not working as expected. How can I solve this or What am I doing wrong? Is there any better approach?
Update: The problem is when I search something it gives me total of visible and invisible records. When I clear the search box with backspace, it gives me total of all records where were visible before.
If you only want visible elements with class amount you could use the jQuery :visible selector
$(".amount:visible").each(...)
jQuery docs https://api.jquery.com/visible-selector/
I'm using leaflet-ajax to load geoJSON on demand. I want to find the maximum theProperty value so I can use that to scale the feature's fill colors before I add them to the map.
Here's my general approach:
function maxBinPropertyValue(theProperty) {
var theGeoJson = null;
var maxPropertyValue = 0;
var propertyValue = null;
var theGeoJson = new L.GeoJSON.AJAX(binsFileName());
theGeoJson.on('data:loaded', function() {
console.log('The data is loaded');
theGeoJson.eachLayer(function(layer) {
console.log('Looping through the layers');
propertyValue = feature.properties[theProperty];
if (propertyValue > maxPropertyValue) {
maxPropertyValue = propertyValue;
console.log('Max so far: ' + maxPropertyValue);
};
});
});
theGeoJson = null;
console.log('The final maximum value: ' + maxPropertyValue);
return maxPropertyValue;
};
I'm trying to wait for the data:loaded event, then loop through all the features to find the maximum value of theProperty, which is returned to the calling routine.
Except it doesn't work. The first console.log says 'The data is loaded'. The second and third console.logs are never reached, and the fourth and final one reports a value of 0 for maxPropertyValue.
How can I examine all the features in a featureset before styling them, in a way guaranteed to not have asynchronous problems?
PS: I'm pretty sure I can't use onEachFeature: instead of the above approach, because I need to examine every feature's property to determine the maximum value in the set before I can style any of the features.
As for your issue about inspecting your data and retrieving the maximum value, you are indeed facing the classic asynchronous concept of JavaScript.
See How do I return the response from an asynchronous call?
Asynchronism is a problem if not dealt with properly, but an advantage if correctly handled.
To put the concept shortly, you do not manage asynchronism in a "standard" sequential way, but you should rather consider parts of code (callbacks) that are executed at a later time based on events.
Whenever you provide a function as an argument, it is certainly a callback that will be executed at a later time, but very probably much later than the next instructions.
So in your case, your 2nd and 3rd console.log are within a callback, and will be executed once your data is loaded, which will happen much later than your 4th console.log.
As for your next step (styling and adding to map), you actually do not need to perform an extra AJAX call, since you already have all data available in theGeoJson variable. You simply need to refactor / restyle it properly.
It is a good approach to break your problem in small steps indeed.
Good luck!
PS: that being said, ES7 provides async and await functionalities that will emulate a sequential execution for asynchronous functions. But to be able to use those, you need latest browser versions or transpilation, which is probably more work to learn and configure as of today for a beginner than understanding how to work with async JS.
I also had this problem and had to wrap my head around this, so giving an explicit example for solution here;
// make a request with your "url"
var geojsonLayer = new L.GeoJSON.AJAX("url");
// define your functions to interact with data
function thingToDoBeforeLoadingStarts () {
// do stuff
}
function thingToDoForEachFileDownloaded () {
// do stuff
}
function thingToDoAfterAllDownloadEnds () {
// do stuff
}
// attach listeners
geojsonlayer.on("data:loading",thingToDoBeforeLoadingStarts);
geojsonLayer.on("data:progress",thingToDoForEachFileDownloaded)
geojsonLayer.on("data:loaded",thingToDoAfterAllDownloadEnds);
At the moment i have the following problem, i'm applying span tags with the applyStyle Method from CKEDITOR 4.x. But when a span is partial selected and i execute the applyStyle method a new span will be made with the selection, but the other half of the selected span isn't restored and loses his span.
First Question: Is it possible to prevent partial selection of a certain element?
IF NOT My Second Question: Is it possible to extend the Selection only on one side, the side where the span(With a certain class or attribute) is partial selected. So that it will be fully selected for processing.
A Example:
This is 'my text <span class"testClass">, This' is </span> Other Text
And now we want a solution to create:
This is <span class"testClass2"> my text, This</span> <span class"testClass"> is </span> Other Text
Please take notice of the following:
The hard part in this is to maintain the html structure. when half of the selection is in an other block level element, it may not brake! That is the reason that i started using the applyStyle method.
First Question: Is it possible to prevent partial selection of a certain element?
Hmm... You can check placeholder plugin's sample - it uses non-editable inline elements to create those placeholders which at least on Chrome cannot be partially selected. Though, I think it's not a satisfying solution for you :)
Another possible solution is using editor#selectionChange event on which you can check if one of selection ends is located inside that element and if yes, set it before or after that element. It'd look like (I haven't tested this code, it's just a proto):
editor.on( 'selectionChange', function( evt ) {
var sel = evt.data.selection,
range = sel.getRanges()[ 0 ];
if ( protectedElement.contains( range.startContainer ) || protectedElement.equals( range.startContainer ) )
range.setStartAt( protectedElement, CKEDITOR.POSITION_BEFORE_START );
if ( protectedElement.contains( range.endContainer ) || protectedElement.equals( range.endContainer ) )
range.setEndAt( protectedElement, CKEDITOR.POSITION_AFTER_END );
sel.selectRanges( [ range ] );
} );
Although, this kind of solutions are always dangerous and can cause many unpredictable situations. But it may be worth checking it.
Back to the root of your problem - I understand that you want to create styles which work on the same level - i.e. only one can be applied in one place. This isn't possible using styling system. You would have to prepare range before applying style. The code would be similar to the selectionChange listener - you check if ends are anchored in style element, if yes you need to move range's ends out of it. The only question is how to exclude entire element from range in this situation:
<p>foo[bar<span class="st1">bom</span>bim]foo</p>
The result should be two ranges:
<p>foo[bar]<span class="st1">bom</span>[bim]foo</p>
Unfortunately current range's API does not include helpful method like range#exclude, therefore you need to implement yours. I would try doing this with walker. Iterate from range's start to end and remember all style elements. If you'll do this in both directions you'll gather also partially selected elements on both ends, so the first step I described will be unnecessary. When you'll have list of elements which you want to exclude from range, then you just need to create ranges at both ends and between these elements - this part should be easy. Element#getPosition will be helpful, but you'll need to check its code to understand how to use it because it isn't documented.
I have been looking and trying for hours. And chose to make an enlarge function myself to expand the selection. I made my own enlarge/expand function as i wanted to have more control which the enlarge of CKEDITOR doesn't provide.
The code:
//Vars
var firstNode = range.startContainer.getParent();
var lastNode = range.endContainer.getParent();
//Make end Get full if is tcElement
if(lastNode.type === CKEDITOR.NODE_ELEMENT && lastNode.getName() === "myElement")
{
range.setEndAfter(lastNode);
}
//Make end Get full if is tcElement
if(firstNode.type === CKEDITOR.NODE_ELEMENT && firstNode.getName() === "myElement")
{
range.setStartBefore(firstNode);
}
range.select();
Other nice piece of code, which isn't very hard but can be useful for other people.
This code i used to split the code in 2 or 3 parts.. where part 1 and 3 are the partial selection if existed.
Spliting to multiple ranges
//Vars
var newRanges = [];
var allWithinRangeParent = range.getCommonAncestor().getChildren();
var firstNode = range.startContainer;
var lastNode = range.endContainer;
var firstNodeStart = range.startOffset;
var lastNodeEnd = range.endOffset;
//TODO make if to check if this needs to be made.
//make end partial
var newEndRange = new CKEDITOR.dom.range( editor.document );
newEndRange.selectNodeContents( lastNode );
newEndRange.endOffset = lastNodeEnd;
newRanges.push(newEndRange);
//TODO make if to check if this needs to be made.
//Make start partial
var newStartRange = new CKEDITOR.dom.range( editor.document );
newStartRange.selectNodeContents( firstNode );
newStartRange.startOffset = firstNodeStart;
newRanges.push(newStartRange);
//Make center selection.
var tempRange = new CKEDITOR.dom.range( editor.document );
tempRange.setStartBefore(firstNode.getParent().getNext());
tempRange.setEndAfter(lastNode.getParent().getPrevious());
newRanges.push(tempRange);
selection.selectRanges(newRanges);
How can I set the minTime and maxTime options after the calendar is created?
I tried the following, which doesn't work:
$('#calendar').fullCalendar('option', 'minTime', 7);
$('#calendar').fullCalendar('render');
I don't know if it is still relevant but I can change the options with the following statement:
example for selectable:
$('#calendar').fullCalendar('getView').calendar.options.selectable = false;
$('#calendar').fullCalendar('render'); // rerender to see visual changes
Though it's not dynamically but at least you don't have to destroy the whole calendar and refetch your events :-)
This way you can change as many calendar options you like:
// save the calendar options in a variable
var calendarOptions = $('#calendar')
.fullCalendar('getView')
.options;
// make your changes to the calendar options
// I wanted to change the slotDuration
calendarOptions.slotDuration = '00:20:00';
// destroy the calendar
$('#calendar')
.fullCalendar('destroy');
//Lets load the calendar with the new options
$('#calendar')
.fullCalendar(calendarOptions);
Hope this helps. Thanks.
This functionality has been officially release in v2.9.0: http://fullcalendar.io/docs/utilities/dynamic_options/
Can't be done without recreating the calendar.
Update:
Can be done in v 2.9: See below
There's an open issue for this functionality here:
https://code.google.com/p/fullcalendar/issues/detail?id=293
just me dude's answer is actually the only way I found myself.
This is just an addendum to this former answer :
If you want to change the editable option, which is very useful if you want to lock the events for asking confirmation on a change before updating your database, it's a little more tricky. In case it can save some time to someone I dump the code:
var view = $('#calendar').fullCalendar('getView');
view.calendar.options.editable = false;
view.calendar.overrides.editable = false;
view.calendar.viewSpecCache.month.options.editable = false;
view.calendar.viewSpecCache.agendaWeek.options.editable = false;
view.calendar.viewSpecCache.agendaDay.options.editable = false;
$('#calendar').fullCalendar('render');
You obviously change all those false to true to unlock.
This code just did fine for me. Call this function anywhere and pass as many custom variables to it, but don't forget to destroy the previous calendar first
function initializeCalendar( timeIntervalCustom ) {
$('#calendar'+id).fullCalendar({
slotMinutes: timeIntervalCustom,
});
}
$('#calendar').fullCalendar("destroy");
initializeCalendar(10);