Jump to content

pconkie

Frog Community Genius
  • Posts

    598
  • Joined

  • Last visited

Everything posted by pconkie

  1. Help! @Chris.Smith @Graham Quince Some staff can not attach files to their notices. They get error: {"status":{"code":3000,"message":"You do not have the api.assetsfiles.add role"},"params":{"method":"assetsfiles.add"},"data":null} BUT.... I can't find this role in Groups and Policies - how do i give all staff this role? Paul
  2. pconkie

    User photos

    Just been told by the service desk that there is no way to bulk upload user photos into frog user accounts using frog extractor If I upload the photos to frogdrive and I know which photo is linked to which user account, is there a way to do it with FrogCode? 1. Starting with user1, I would need to go and get user1_photo. 2. Attach (copy) user1_photo to user1 account and update (save) 3. Move onto user2... I can do 1 & 3, but not 2. Anyone got any ideas? Don't fancy manually updating almost 2000 user accounts! Just think about all the possibilities like visual class lists, seating plans etc Paul
  3. Ok, @Graham Quince @Chris.Smith come on, this is getting in the way of writing the timetable for next year! This is almost 'finished' - thought you might want a look... This has now replaced the frog noticeboard on our dashboard You can: Choose your title font colour Add attachments without needed a file drop! Changed the default date options to "until" rather than "from" This one is on the student dashboard You can insert hyperlinks (like the final notice) but not easily! Better if CKEditor was available! Found this.options.sitePermission so that I could hide the 'Create Notice' button for users that only have 'view' permissions. BTW: The Croak is our in house student run magazine on frog - it's great! At the moment I have to drag a frog noticeboard onto a page and grab the forum uuid to enter as a preference in my widget. If the forum uuid is not set, the widget won't work (I do test for this and load in another view,ejs to let them know in detail what to do). So is there a way to generate a forum uuid from scratch as I presume the real noticeboard widget does? This must be possible, right? Thanks Paul
  4. pconkie

    BUGS?

    Thanks Chris Yes I believe we logged it earlier on the frog support desk, just wanted to give you a heads up too. BTW first time this happened it was sensible o'clock..... Cheers Paul
  5. pconkie

    BUGS?

    @Chris.Smith Twice now I've been using FrogCode and FrogLearn has crashed. Both times the server has needed restarting by the network manager to get frog back up. In both cases FrogCode froze up causing me to close and re-open chrome. Then immediately got a 500 error on desktop - frog redirects to app/redirect on mobile. If there are logs that can uncover what is actually going on here and if indeed linked to FrogCode then the last occurance was approx 02.00 Monday morning. Hopefully you can track the cause down! Thanks Paul
  6. pconkie

    BUGS?

    Ignore this. I've really got to use .bind properly.
  7. pconkie

    BUGS?

    Thanks Chris for looking at this, I really appreciate you taking the time. I can see now that the update is actually occurring. I have my widget on a site and I have that site embedded on another site. In both cases the console give me the same site_uuid, which is great. I found a solution I'm happy with for the styling, but will eventually do as you have suggested. I guess the only thing I would like to try and get sorted before considering this notice board widget "finished for now" is to create a forum in code rather than use an existing forum uuid. Looking forward to seeing if this is possible. I also want to swap out the standard confirm for the Frog.JS confirm, but am having a few problems - Uncaught TypeError: this.confirm is not a function.
  8. pconkie

    BUGS?

    Hi @Chris.Smith Another possible bug? This started all of a sudden. I have updated and re-deployed a FC Widget before without issue. But yesterday the Notice Board widget stopped being update-able. I tried uninstalling and reinstalling, but that didn't help. The widget runs without error in preview, but fails silently when being updated. Hopefully you can see from the screen grab the 500 error on packages.update method. Any ideas? Thanks for your help yesterday. I presume form what you said about site uuids that inside FrogCode something like this would check to see if the page is nested and return the origin site uuid if true, otherwise returning the site uuid? var site_uuid = this.options.origin_site_uuid; if (typeof site_uuid === 'undefined') { //not nested on another page site_uuid = this.options.site_uuid; } Paul
  9. pconkie

    BUGS?

    Don't think this one is a 'bug', but.... var site_uuid = this.elements.site.find('[data-site-uuid]:first').data('site-uuid'); This line works in a html widget but not in FrogCode.
  10. pconkie

    BUGS?

    Possible bug - Just created first FrogCode Widget on own platform. Styles appeared correctly during testing, but once the widget was deployed and dragged onto a page in a site the widget didn't have the styles applied. Styles were written as suggested: [data-name="Widget.TimetableViewer"].widget-content { background: none; text-align: left; width: 100%; margin: 0; } And all looked good when previewing from within the FrogCode Editor. To get the styles to be applied correctly I had to remove the .widget-content part of the css above. Paul
  11. What about using Google Docs? You could create a folder in google that contains a document for each student. You can set permissions on each document so that students can not open each others. You could then place the google folder on a frog site. We have single sign on between google and frog enabled so you shouldn't notice where frog ends and google starts. Just an idea, haven't tried to set this up.
  12. Hi @Angeliki Messari here are my suggested changes so that you can have multiple carousels on the same page. The issue is with the use of $("") and the fact that both carousels have the same ID. <style> .carousel-fade .carousel-inner .item { opacity: 0; -webkit-transition-property: opacity; -moz-transition-property: opacity; -o-transition-property: opacity; transition-property: opacity; } .carousel-fade .carousel-inner .active { opacity: 1; } .carousel-fade .carousel-inner .active.left, .carousel-fade .carousel-inner .active.right { left: 0; opacity: 0; z-index: 1; } .carousel-fade .carousel-inner .next.left, .carousel-fade .carousel-inner .prev.right { opacity: 1; } .carousel-fade .carousel-control { z-index: 2; } .carousel-inner img { max-width: 100%; height: 300px; margin-left: auto; margin-right: auto; min-width: 300px; } .carousel-arrow-left, .carousel-arrow-right { top: 50%; border: solid transparent; content: " "; height: 0; width: 0; position: absolute; pointer-events: none; border-width: 15px; margin-top: -15px; } .carousel-arrow-right { left: 35%; border-left-color: #FFFFFF; } .carousel-arrow-left { right: 35%; border-right-color: #FFFFFF; } </style> <div id="Carousel" class="carousel slide carousel-fade col-lg-8 col-offset-2"> <ol id="filedrop-slide-show-count" class="carousel-indicators"> </ol> <div id="filedrop-slide-show-img" role="listbox" class="carousel-inner"> </div> <!-- Left and right controls --> <a class="left carousel-control" href="#Carousel" data-slide="prev"> <span class="carousel-arrow-left"></span> </a> <a class="right carousel-control" href="#Carousel" data-slide="next"> <span class="carousel-arrow-right"></span> </a> </div> <script type="text/javascript"> var unique_name = makeid(); this.element.find('#Carousel').attr("id",unique_name); var $carousel = this.element.find('#'+unique_name); $carousel.find('.carousel-control').attr("href",'#'+unique_name); $carousel.carousel({interval: 500}); var baseURL = Frog.Utilities.getBaseUrl(), // Change fileDropUuid to the UUID of your file drop widget fileDropUuid = '223DFB4C20028F362EC85F27258F050F3505A2BC8F1561F1'; Frog.Model .api('filedrop.get', { filedrop: fileDropUuid }).done(function(filesResponse) { var $fileList = $carousel.find('#filelist'), $slideShowCount = $carousel.find("#filedrop-slide-show-count"), $slideShowImageContainer = $carousel.find("#filedrop-slide-show-img"), fileCount = 0; filesResponse.data.resources.forEach(function(file, index) { // Check whether the file is one of these filetypes; Want to add more? Add to the array if (['jpg', 'jpeg', 'gif', 'png'].indexOf(file.file.ext.toLowerCase()) > -1) { $slideShowCount .append( $('<li>') .attr('data-target', 'Carousel') .attr('data-slide-to', fileCount) .addClass(function() { if (fileCount === 0) { return 'active'; } }) ); $slideShowImageContainer .append( $('<div>').addClass('item') .addClass(function() { if (fileCount === 0) { return 'active'; } }) .append( $('<img />').addClass('img-responsive') /* ?width=400&height=500 this addition creates a new image on your Frog server at 400 pixels wide by 500 pixels high. This prevents the gallery from serving much larger pictures than required - which can cause your Frog to slow down */ .attr('src', baseURL + '/app/file/resource/' + file.file.uuid + '?width=400&height=500') .attr('align', 'center') ) ); fileCount++; } }); }); function makeid() { var text = ""; var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; for( var i=0; i < 6; i++ ) text += possible.charAt(Math.floor(Math.random() * possible.length)); return text; } </script> Hopefully you can spot the lines I have changed and the bits I have added. Let me know if you have any problems, and don't forget to change the file widget uuid back to match yours. Paul
  13. We use the frog noticeboard widget on our dashboards (all-staff email groups don't exist!) and a filedrop for any attachments. This doesn't work great - it's sometimes hard to find the right attachment and files remain long after notices have expired. So I thought i'd have a go at recreating the noticeboard widget with the option to attach files directly to the notice. I've managed to do this. But I have a few things on the wishlist....... 1. With advice from @Chris.Smith i'm using the site assets to store the attachments. However, I've noticed that when the page with my noticeboard is nested on our dashboard the attachments get stored in the dashboards assets instead. I'd rather not do this, so i'm wondering if there is a way to get the uuid of the site the widget is on when that site is nested on a dashboard? This: var site_uuid = this.elements.site.find('[data-site-uuid]:first').data('site-uuid'); doesn't do it. 2. I currently have to drag a frog noticeboard widget onto a page and hunt down the uuid of the forum that got created to hijack. I then provide that forum uuid to the widget via a preference. Is there a way in edit mode when my noticeboard is dragged onto a page to create a new forum and return the uuid (and i suppose to be tidy, delete a forum when the widget is deleted from a page). 3. Frog seems to use CKeditor in various places in order to add custom mark-up to text. Is it possible to turn my 'content' textarea into a WYSIWYG enabled element using CKeditor? 4. I'm using this https://froglearn.backwellschool.net/app/public/sprite/os-icon-ext/sprite.png frog sprite map to get the correct file type images for each attachment. However is this reliable across different froglearn instances? Should i be uploading as a widget asset? I'm also getting a weird border around the images which I think is actually sue to not setting a src on the image placeholder i'm using. Is there a frog transparent.png somewhere i can use or again, should i be uploading one as an asset. That's it for now! Thanks Paul
  14. AMAZING. Took me two hours to get this far... <button id="btn1" type="button">Click Me!</button> <script> $('#btn1').on('click', function(ev) { $(this).trigger('os.app.upload', { data: { folder: 'C02427692002F19993597F2E4A88B90FAE7026CCA52EF2A9', method: 'resources.files.add', type: 'staff' } }); }); </script> With no call back for grabbing the file uuids. And at first had no idea where my files were going (until i looked in my frogdrive). I'm looking forward to finding some time to try your code out......already got a really great idea for it. Thanks Chris. Paul
  15. I decided to use offset = 0 and limit = 4 on the api call as this was the minimum number of weeks of timetable data i needed to loop through to ensure an accurate list is always returned for any school (it gets around everything expect the summer holidays). Had to write this to prevent duplicates (because they would have multiple lessons with that teachers in that subject over the next 4 weeks) function arrayFind(arr, fn) { for( var i = 0, len = arr.length; i < len; ++i ) { if( fn(arr[i]) ) { return i; } } return -1; } Found this for sorting arrays, so the list could be alphabetical by subject function dynamicSort(property) { var sortOrder = 1; if (property[0] === "-") { sortOrder = -1; property = property.substr(1); } return function (a,b) { var result = (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0; return result * sortOrder; }; } I looped through each week, day and period, checking for duplicates, building a new json object which i then sorted and created a tbody from. ////if data contains the api response and myarr will hold the new object var data = thisResponse.data[0]; myarr = []; $.each(data.weeks, function(i,weeks) { $.each(weeks.days, function(p,days) { $.each(days.periods, function(q,periods) { var x = {display: periods.teacher.displayname, subject: periods.subject, email:periods.teacher.email}; var result = arrayFind(myarr, function(v){ return v.email === periods.teacher.email && v.subject === periods.subject; }); if (result === -1) { myarr.push(x); } }); }); }); myarr.sort(dynamicSort("subject"));
  16. Yep. I would like to code a button like this: To open this: And return the uuid(s) of any file(s) uploaded. I assume the file up-loader needs somewhere to put the files? But if this can all be done without using a filedrop at all, then even better. Thanks, I know your busy. Any hint what the "top secret" stuff is your working on? Paul
  17. Live mode, assuming the filedrop already exists somewhere in frog.
  18. Hi @Chris.Smith Is it possible to open the fileupload dialogue and simultaneously pass the filedrop uuid using a similar approach to the code above? That would open up some interesting possibilities.
  19. If anyone is interested, I went with option 3 above. It displays slightly differently when staff or parents view a page with it on. This is what a student sees:
  20. @Chris.Smith @Graham Quince OK - it's now a FrogCode Widget! Deployed on the alpha site. All seems to be working, but as your site doesn't have any timetable data in it the testing that can be done is limited! What do you think? I'd like to get rid of the preference for the lesson labels and either get this from the api or get the user to select the correct format for lesson labels. The api only sends the lesson labels for the lessons where a user has a lesson (if that makes sense) which wouldn't work. Already been asked if it can do room timetables as staff are often looking for a free room - I think the answer is no as the api doesn't seem to support room timetables? Thanks for your help with this. Paul
  21. Hi @mobrien Here are a couple of tips... Styles need to go inside the <style> tag. So, yes, they could go where you suggested or above .template {, just as long as they come after <style> and before </style>. <style> .template { display: none; } thead { background-color: red; } th, tbody { border-width: 1px; border-color: #e6e6e6; border-style: double; padding: 10px; font-size:14px } td.bowman { background-color: red; } td.fulford { background-color: green; } </style> This is the mark-up for a typical table row in HTML <tr> <td></td> <td></td> <td></td> <td></td> <td></td> <td></td> </tr> <tr></tr> - row (td or th inside) <td></td> - standard cell (content goes inside) Like your table the row above contains 6 cells which over a series of rows form the 6 columns. One of your table rows looks like this: <tr> <td data-field="name">Student 1</td> <td data-field="house">Bowman</td> <td data-field="tutor">ACR</td> <td data-field="achievement">1100</td> <td data-field="behaviour">10</td> <td data-field="total">1090</td> </tr> To add a style such as a specific colour to a cell you would need to give that cell (<td>) a style class (which we have defined in the <style> section of our code). What that looks like is this (look at line 2): <tr> <td data-field="name">Student 1</td> <td data-field="house" class="bowman">Bowman</td> <td data-field="tutor">ACR</td> <td data-field="achievement">1100</td> <td data-field="behaviour">10</td> <td data-field="total">1090</td> </tr> You need to add the correct class to every house cell (<td>). That means when a student in Bowman House appears you add class="bowman" but when a student in Fulford House appears you add class="fulford" etc Just to make things a bit more complicated: your table is dynamically generated your house names are capitalised but your style names are in lower case (which won't work) your table already has a style applied to it which will over-ride what you want to do with the House <td>'s //Find this line $tbody.append($row); //and make a new line below it and add this $row.find('td[data-field=house]').addClass(datum.house.toLowerCase()); //this is what Chris gave you with .toLowerCase() added to make your class names match your House names. //this line finds all of your House <td>'s (yes, all of them in one go) and applies the correct house style. Next you have to either take the striped style off the table /////this line <table class="table table-striped"> ////changed to this <table class="table"> or over-ride the striped style by adding the !important css attribute td.bowman { background-color: red !important; } td.fulford { background-color: green !important; } That should do it. Let me know if you have any problems.
  22. I'd like to display a simple list of classes a students is in, along with the name of their teacher. It's important to me that where a class has more than one teacher that all the teachers are named. Looking for advice on the best way to do this. Current thoughts.... 1. Use users.getSummary. This gives a nice list of the classes, but no uuid returned for the classes and no teacher details. 2. Use users.getDataInCategory. Using category uuid 632EA3F52004C7F91BDF4FFCBB6D1C0B5AFBFF7CEAF86E45 returns group membership. This time the api does return the uuid of the classes, but still no teacher details. 3. Use timetables.getTimetable. The data returned from this api would need a lot of work to reduce down to one simple list of classes, but it's all in the return (including the teacher details). 4. There is a better api that I have missed for doing this, which somebody could tell me about! Thanks in advance Paul
  23. Actually i figured this one out....found the tap event. changed to... $mywrapper.find('ul.typeahead.dropdown-menu').on('click tap', 'li', function (e) { }); Right fully working code here <style> .frogui_components_search { border: 0 !important; } .table tbody tr { height: 50px; } .table th { text-align: center; } .table { background-color: #FFFFFF; } .table td { line-height: 15px; padding: 4px; } img { margin: 0px auto; display: block; } </style> <div class="mywrapper"> <div class="widget_timetable widget_timetable_user widget_timetable_user_search"> <div class="theme-headerbg clearfix"> <h2 class="widget-title btn btn-text os-ellipsis" id="searchResult"></h2> <button type="button" class="btn btn-text pull-right" id="toggleSearch"><i class="os-icon search-icon"></i></button> </div> <div class="frogui_components_search" data-component="search" style="display: none;"> <form class="search"> <input autocomplete="off" type="text" name="needle" placeholder=""> <ul class="typeahead dropdown-menu" style="top: 30px; left: 0px; display: none;"></ul> <button id="btn-clear" class="search-btn os-icon search-icon search-btn-clear" type="button"></button> </form> </div> </div> <img id="loader" src="../app/public/icon/UI/loading.gif"> <div id="week1" class="table-responsive"> <table class="table table-bordered"> <thead> <tr> <th class="span1">WEEK 1</th> <th class="span2">Monday</th> <th class="span2">Tuesday</th> <th class="span2">Wednesday</th> <th class="span2">Thursday</th> <th class="span2">Friday</th> </tr> </thead> <tbody></tbody> </table><br /> <button type="button" id="wk1btn" class="btn btn-primary" style="display: none;">Click for Week 2</button> </div> <div id="week2" class="table-responsive"> <table class="table table-bordered"> <thead> <tr> <th class="span1">WEEK 2</th> <th class="span2">Monday</th> <th class="span2">Tuesday</th> <th class="span2">Wednesday</th> <th class="span2">Thursday</th> <th class="span2">Friday</th> </tr> </thead> <tbody></tbody> </table><br /> <button type="button" id="wk2btn" class="btn btn-primary">Click for Week 1</button> </div> </div> <script> ///////////these vars should become the preferences in the eventual forg code widget //////// var school_weeks = 2; var school_periods_in_day = 7; //total including any reg/tutor that will appear in your achool_lesson_labels var school_lesson_labels = ["REG","LESSON 1","LESSON 2","LESSON 3","LESSON 4","LESSON 5","LESSON 6"]; var school_period_labels = ["1Mon REG","1Mon 1","1Mon 2","1Mon 3","1Mon 4","1Mon 5","1Mon 6","1Tue REG","1Tue 1","1Tue 2","1Tue 3","1Tue 4","1Tue 5","1Tue 6","1Wed REG","1Wed 1","1Wed 2","1Wed 3","1Wed 4","1Wed 5","1Wed 6","1Thu REG","1Thu 1","1Thu 2","1Thu 3","1Thu 4","1Thu 5","1Thu 6","1Fri REG","1Fri 1","1Fri 2","1Fri 3","1Fri 4","1Fri 5","1Fri 6","2Mon REG","2Mon 1","2Mon 2","2Mon 3","2Mon 4","2Mon 5","2Mon 6","2Tue REG","2Tue 1","2Tue 2","2Tue 3","2Tue 4","2Tue 5","2Tue 6","2Wed REG","2Wed 1","2Wed 2","2Wed 3","2Wed 4","2Wed 5","2Wed 6","2Thu REG","2Thu 1","2Thu 2","2Thu 3","2Thu 4","2Thu 5","2Thu 6","2Fri REG","2Fri 1","2Fri 2","2Fri 3","2Fri 4","2Fri 5","2Fri 6"]; var timetableweek_toview = new Date("2017-07-01"); //this is the start of the week or fortnight we will use as 'week1' and 'week2'. Make sure its a normal representative block of time as late as possible in the academic year (avoid holidays, bank holiday funny timetable weeks like enrichment week etc). ///////////other vars /////////////////////////////////////// var currentuser = FrogOS.getUser(); var today = new Date(); var offsetweeks = Math.round((timetableweek_toview-today)/ 604800000); var school_days_in_week = 5; var school_cyclelength = school_weeks * school_days_in_week * school_periods_in_day; var school_weeklength = school_days_in_week * school_periods_in_day; var $mywrapper = this.element.find(".mywrapper"); ////////////////////////////////////////////////////////// var getTimetable = function(anyuuid) { $mywrapper.find("#week1").hide(); $mywrapper.find("#week2").hide(); $mywrapper.find("#loader").show(); $mywrapper.find("table td").html(''); $mywrapper.find("table td").css("background-color",''); Frog.Model .api( 'timetables.getTimetable', { limit: 2, offset: offsetweeks, week_starts_on: 1, user_uuid: currentuser.uuid, target: [anyuuid] } ).done(function(thisResponse) { if (thisResponse.status.code === 0) { var data = thisResponse.data[0]; $.each(data.weeks, function(i,weeks) { $.each(weeks.days, function(p,days) { $.each(days.periods, function(q,periods) { $mywrapper.find("table tr td[id='"+periods.name+"']").html(periods.subject+'<BR />'+periods.teacher.displayname+'<BR />'+periods.room.slice(-3)); var bgcolor = stringToColour(periods.subject+periods.teacher.username); $mywrapper.find("table tr td[id='"+periods.name+"']").css("background-color", bgcolor); $mywrapper.find("table tr td[id='"+periods.name+"']").css("color", getForegroundColor(bgcolor)); }); }); }); $mywrapper.find('#searchResult').html('Timetable for '+data.user.displayname); $mywrapper.find("#loader").hide(); $mywrapper.find("#week1").show(); } }); }; var delay = (function(){ var timer = 0; return function(callback, ms){ clearTimeout (timer); timer = setTimeout(callback, ms); }; })(); var stringToColour = function(str) { var hash = 0; for (var i = 0; i < str.length; i++) { hash = str.charCodeAt(i) + ((hash << 5) - hash); } var colour = '#'; for (var p = 0; p < 3; p++) { var value = (hash >> (p * 8)) & 0xFF; colour += ('00' + value.toString(16)).substr(-2); } return colour; }; var getForegroundColor = function(hexcolor) { var r = parseInt(hexcolor.substr(1,2),16); var g = parseInt(hexcolor.substr(3,2),16); var b = parseInt(hexcolor.substr(5,2),16); var yiq = ((r*299)+(g*587)+(b*114))/1000; return (yiq >= 128) ? 'black' : 'white'; }; $mywrapper.find('#wk1btn').click(function() { $mywrapper.find('#week1').hide(); $mywrapper.find('#week2').show(); }); $mywrapper.find("#wk2btn").click(function() { $mywrapper.find("#week1").show(); $mywrapper.find("#week2").hide(); }); $mywrapper.find("#toggleSearch").click(function(e) { $mywrapper.find(".frogui_components_search").toggle(); e.stopPropagation(); }); $mywrapper.find("#btn-clear").click(function() { $mywrapper.find('.search input').val(''); $mywrapper.find('.dropdown-menu').hide(); $mywrapper.find("ul.typeahead.dropdown-menu").empty(); }); $(this.body).click(function() { $mywrapper.find('.dropdown-menu').hide(); }); //this seems to be needed for IE to do anything right! $mywrapper.find('.search input').on('click', function(e) { e.stopPropagation(); }); $mywrapper.find('.search input').keypress(function(e) { if (e.which === 13) { e.preventDefault(); return false; } }); $mywrapper.find('ul.typeahead.dropdown-menu').on('click tap', 'li', function (e) { $mywrapper.find(".frogui_components_search").hide(); $mywrapper.find('.dropdown-menu').hide(); $mywrapper.find("ul.typeahead.dropdown-menu").empty(); $mywrapper.find('.search input').val(''); getTimetable($(this).data("value")); }); $mywrapper.find('.search input').keyup(function() { var s = $mywrapper.find('.search input').val(); if(s.length > 1) { delay(function(){ Frog.Model .api( 'textsearch.search', { profile: 'student,staff', find: s, type: 'user', include_associations: true, exclude_sources: ['temporary'] } ).done(function(thisResponse) { if (thisResponse.status.code === 0) { $mywrapper.find("ul.typeahead.dropdown-menu").empty(); var rusers = thisResponse.data.user; if (rusers.length) { $.each(rusers, function(i,users) { $mywrapper.find("ul.typeahead.dropdown-menu").append('<li data-value="'+users.uuid+'"><a href="#"><span title="'+users.displayname+'">'+users.profile.name+': '+users.displayname+'</span></a></li>'); }); $mywrapper.find('.dropdown-menu').show(); } else { $mywrapper.find('.dropdown-menu').hide(); } } }); }, 800 ); } }); //render the timetable grid var y; var b = 0; for (var i = 0; i < school_periods_in_day; i++) { var trsource = ''; trsource = trsource + '<tr><th>'+school_lesson_labels[b]+'</th>'; for (y = b; y < school_weeklength; y=y+school_periods_in_day) { trsource = trsource + '<td id="' + school_period_labels[y] + '"></td>'; } trsource = trsource + '</tr>'; $mywrapper.find("#week1 table tbody").append(trsource); b++; } if (school_weeks === 2) { var b = 0; for (var i = 0; i < school_periods_in_day; i++) { var trsource = ''; trsource = trsource + '<tr><th>'+school_lesson_labels[b]+'</th>'; for (y = (b+school_weeklength); y < school_cyclelength; y=y+school_periods_in_day) { trsource = trsource + '<td id="' + school_period_labels[y] + '"></td>'; } trsource = trsource + '</tr>'; $mywrapper.find("#week2 table tbody").append(trsource); $mywrapper.find("#wk1btn").show(); b++; } } $mywrapper.find('#searchResult').html('Timetable for '+currentuser.displayname); getTimetable(); </script>
  24. Alternative Timetable Viewer Here is all the code in one go: <style> .frogui_components_search { border: 0 !important; } .table tbody tr { height: 50px; } .table th { text-align: center; } .table { background-color: #FFFFFF; } .table td { line-height: 15px; padding: 4px; } img { margin: 0px auto; display: block; } </style> <div class="mywrapper"> <div class="widget_timetable widget_timetable_user widget_timetable_user_search"> <div class="theme-headerbg clearfix"> <h2 class="widget-title btn btn-text os-ellipsis" id="searchResult"></h2> <button type="button" class="btn btn-text pull-right" id="toggleSearch"><i class="os-icon search-icon"></i></button> </div> <div class="frogui_components_search" data-component="search" style="display: none;"> <form class="search"> <input autocomplete="off" type="text" name="needle" placeholder=""> <ul class="typeahead dropdown-menu" style="top: 30px; left: 0px; display: none;"></ul> <button id="btn-clear" class="search-btn os-icon search-icon search-btn-clear" type="button"></button> </form> </div> </div> <img id="loader" src="../app/public/icon/UI/loading.gif"> <div id="week1" class="table-responsive"> <table class="table table-bordered"> <thead> <tr> <th class="span1">WEEK 1</th> <th class="span2">Monday</th> <th class="span2">Tuesday</th> <th class="span2">Wednesday</th> <th class="span2">Thursday</th> <th class="span2">Friday</th> </tr> </thead> <tbody></tbody> </table><br /> <button type="button" id="wk1btn" class="btn btn-primary" style="display: none;">Click for Week 2</button> </div> <div id="week2" class="table-responsive"> <table class="table table-bordered"> <thead> <tr> <th class="span1">WEEK 2</th> <th class="span2">Monday</th> <th class="span2">Tuesday</th> <th class="span2">Wednesday</th> <th class="span2">Thursday</th> <th class="span2">Friday</th> </tr> </thead> <tbody></tbody> </table><br /> <button type="button" id="wk2btn" class="btn btn-primary">Click for Week 1</button> </div> </div> <script> ///////////these vars should become the preferences in the eventual forg code widget //////// //////////change these to match the timetable used by your school or nothing will work!/////// var school_weeks = 2; var school_periods_in_day = 7; //total including any reg/tutor that will appear in your achool_lesson_labels var school_lesson_labels = ["REG","LESSON 1","LESSON 2","LESSON 3","LESSON 4","LESSON 5","LESSON 6"]; var school_period_labels = ["1Mon REG","1Mon 1","1Mon 2","1Mon 3","1Mon 4","1Mon 5","1Mon 6","1Tue REG","1Tue 1","1Tue 2","1Tue 3","1Tue 4","1Tue 5","1Tue 6","1Wed REG","1Wed 1","1Wed 2","1Wed 3","1Wed 4","1Wed 5","1Wed 6","1Thu REG","1Thu 1","1Thu 2","1Thu 3","1Thu 4","1Thu 5","1Thu 6","1Fri REG","1Fri 1","1Fri 2","1Fri 3","1Fri 4","1Fri 5","1Fri 6","2Mon REG","2Mon 1","2Mon 2","2Mon 3","2Mon 4","2Mon 5","2Mon 6","2Tue REG","2Tue 1","2Tue 2","2Tue 3","2Tue 4","2Tue 5","2Tue 6","2Wed REG","2Wed 1","2Wed 2","2Wed 3","2Wed 4","2Wed 5","2Wed 6","2Thu REG","2Thu 1","2Thu 2","2Thu 3","2Thu 4","2Thu 5","2Thu 6","2Fri REG","2Fri 1","2Fri 2","2Fri 3","2Fri 4","2Fri 5","2Fri 6"]; var timetableweek_toview = new Date("2017-07-01"); //this is the start of the week or fortnight we will use as 'week1' and 'week2'. Make sure its a normal representative block of time as late as possible in the academic year (avoid holidays, bank holiday funny timetable weeks like enrichment week etc). ///////////other vars /////////////////////////////////////// var currentuser = FrogOS.getUser(); var today = new Date(); var offsetweeks = Math.round((timetableweek_toview-today)/ 604800000); var school_days_in_week = 5; var school_cyclelength = school_weeks * school_days_in_week * school_periods_in_day; var school_weeklength = school_days_in_week * school_periods_in_day; var $mywrapper = this.element.find(".mywrapper"); ////////////////////////////////////////////////////////// var getTimetable = function(anyuuid) { $mywrapper.find("#week1").hide(); $mywrapper.find("#week2").hide(); $mywrapper.find("#loader").show(); $mywrapper.find("table td").html(''); $mywrapper.find("table td").css("background-color",''); Frog.Model .api( 'timetables.getTimetable', { limit: 2, offset: offsetweeks, week_starts_on: 1, user_uuid: currentuser.uuid, target: [anyuuid] } ).done(function(thisResponse) { if (thisResponse.status.code === 0) { var data = thisResponse.data[0]; $.each(data.weeks, function(i,weeks) { $.each(weeks.days, function(p,days) { $.each(days.periods, function(q,periods) { $mywrapper.find("table tr td[id='"+periods.name+"']").html(periods.subject+'<BR />'+periods.teacher.displayname+'<BR />'+periods.room.slice(-3)); var bgcolor = stringToColour(periods.subject+periods.teacher.username); $mywrapper.find("table tr td[id='"+periods.name+"']").css("background-color", bgcolor); $mywrapper.find("table tr td[id='"+periods.name+"']").css("color", getForegroundColor(bgcolor)); }); }); }); $mywrapper.find('#searchResult').html('Timetable for '+data.user.displayname); $mywrapper.find("#loader").hide(); $mywrapper.find("#week1").show(); } }); }; var delay = (function(){ var timer = 0; return function(callback, ms){ clearTimeout (timer); timer = setTimeout(callback, ms); }; })(); var stringToColour = function(str) { var hash = 0; for (var i = 0; i < str.length; i++) { hash = str.charCodeAt(i) + ((hash << 5) - hash); } var colour = '#'; for (var p = 0; p < 3; p++) { var value = (hash >> (p * 8)) & 0xFF; colour += ('00' + value.toString(16)).substr(-2); } return colour; }; var getForegroundColor = function(hexcolor) { var r = parseInt(hexcolor.substr(1,2),16); var g = parseInt(hexcolor.substr(3,2),16); var b = parseInt(hexcolor.substr(5,2),16); var yiq = ((r*299)+(g*587)+(b*114))/1000; return (yiq >= 128) ? 'black' : 'white'; }; $mywrapper.find('#wk1btn').click(function() { $mywrapper.find('#week1').hide(); $mywrapper.find('#week2').show(); }); $mywrapper.find("#wk2btn").click(function() { $mywrapper.find("#week1").show(); $mywrapper.find("#week2").hide(); }); $mywrapper.find("#toggleSearch").click(function(e) { $mywrapper.find(".frogui_components_search").toggle(); e.stopPropagation(); }); $mywrapper.find("#btn-clear").click(function() { $mywrapper.find('.search input').val(''); $mywrapper.find('.dropdown-menu').hide(); $mywrapper.find("ul.typeahead.dropdown-menu").empty(); }); $(this.body).click(function() { $mywrapper.find('.dropdown-menu').hide(); }); //this seems to be needed for IE to do anything right! $mywrapper.find('.search input').on('click', function(e) { e.stopPropagation(); }); $mywrapper.find('.search input').keypress(function(e) { if (e.which === 13) { e.preventDefault(); return false; } }); $mywrapper.find('ul.typeahead.dropdown-menu').on('click', 'li', function (e) { e.preventDefault(); $mywrapper.find(".frogui_components_search").hide(); $mywrapper.find('.dropdown-menu').hide(); $mywrapper.find("ul.typeahead.dropdown-menu").empty(); $mywrapper.find('.search input').val(''); getTimetable($(this).data("value")); }); $mywrapper.find('.search input').keyup(function() { var s = $mywrapper.find('.search input').val(); if(s.length > 1) { delay(function(){ Frog.Model .api( 'textsearch.search', { profile: 'student,staff', find: s, type: 'user', include_associations: true, exclude_sources: ['temporary'] } ).done(function(thisResponse) { if (thisResponse.status.code === 0) { $mywrapper.find("ul.typeahead.dropdown-menu").empty(); var rusers = thisResponse.data.user; if (rusers.length) { $.each(rusers, function(i,users) { $mywrapper.find("ul.typeahead.dropdown-menu").append('<li data-value="'+users.uuid+'"><a href="#"><span title="'+users.displayname+'">'+users.profile.name+': '+users.displayname+'</span></a></li>'); }); $mywrapper.find('.dropdown-menu').show(); } else { $mywrapper.find('.dropdown-menu').hide(); } } }); }, 800 ); } }); //render the timetable grid var y; var b = 0; for (var i = 0; i < school_periods_in_day; i++) { var trsource = ''; trsource = trsource + '<tr><th>'+school_lesson_labels[b]+'</th>'; for (y = b; y < school_weeklength; y=y+school_periods_in_day) { trsource = trsource + '<td id="' + school_period_labels[y] + '"></td>'; } trsource = trsource + '</tr>'; $mywrapper.find("#week1 table tbody").append(trsource); b++; } if (school_weeks === 2) { var b = 0; for (var i = 0; i < school_periods_in_day; i++) { var trsource = ''; trsource = trsource + '<tr><th>'+school_lesson_labels[b]+'</th>'; for (y = (b+school_weeklength); y < school_cyclelength; y=y+school_periods_in_day) { trsource = trsource + '<td id="' + school_period_labels[y] + '"></td>'; } trsource = trsource + '</tr>'; $mywrapper.find("#week2 table tbody").append(trsource); $mywrapper.find("#wk1btn").show(); b++; } } $mywrapper.find('#searchResult').html('Timetable for '+currentuser.displayname); getTimetable(); </script> Copy and paste into a HTML widget on a page and then you must change the variables in this section ////////////////////////////////////////////////////////////////////////////////////////////////////////// var school_weeks (number) 1 or 2 supported var school_periods_in_day (number) as many as you need var school_lesson_labels[] (array) whatever you like but should be the same number of items in this array as value for school_periods_in_day var school_period_labels[] (array) type exactly what SIMS uses as shorthand for your periods e.g. 'Mon1', 'Mon 1', '1Mon1', '1Mon 1' etc in order var timetableweek_toview (date) pick a Monday as late in the academic year as possible to be the start of the week (or fortnight) that we will use as 'week1' and 'week2'. A date in the future will always result in the most recent timetable being displayed to the user (avoid holidays, bank holiday funny timetable weeks like enrichment week etc). ////////////////////////////////////////////////////////////////////////////////////////////////////// @Chris.Smith one issue remains that I am aware of. The searching for a user works great on all desktop browsers that I have tried it on. However on a touch device (e.g. iPad) the list of matched users appears but tapping on one of them fails to load their timetable. I guess this is the event that fails to fire on iPad... $mywrapper.find('ul.typeahead.dropdown-menu').on('click', 'li', function (e) { e.preventDefault(); $mywrapper.find(".frogui_components_search").hide(); $mywrapper.find('.dropdown-menu').hide(); $mywrapper.find("ul.typeahead.dropdown-menu").empty(); $mywrapper.find('.search input').val(''); getTimetable($(this).data("value")); });
  25. Step 6b The code (re-written following advice from Chris) 1. Toggling the visibility of the search box when the search icon is clicked var $mywrapper = this.element.find(".mywrapper"); $mywrapper.find("#toggleSearch").click(function(e) { $mywrapper.find(".frogui_components_search").toggle(); e.stopPropagation(); }); 2. Calling the textsearch.search api and filling the dropdown-menu ul $mywrapper.find('.search input').keyup(function() { var s = $mywrapper.find('.search input').val(); if(s.length > 1) { Frog.Model .api( 'textsearch.search', { profile: 'student,staff', find: s, type: 'user', include_associations: true, exclude_sources: ['temporary'] } ).done(function(thisResponse) { if (thisResponse.status.code == 0) { $mywrapper.find("ul.typeahead.dropdown-menu").empty(); var rusers = thisResponse.data.user; if (rusers.length) { $.each(rusers, function(i,users) { $mywrapper.find("ul.typeahead.dropdown-menu").append('<li data-value="'+users.uuid+'"><a href="#"><span title="'+users.displayname+'">'+users.profile.name+': '+users.displayname+'</span></a></li>'); }); $mywrapper.find('.dropdown-menu').show(); } else { $mywrapper.find('.dropdown-menu').hide(); } } }); } }); 3. Re-setting the search box when the clear-search button is clicked $mywrapper.find("#btn-clear").click(function() { $mywrapper.find('.search input').val(''); }); 4. Hiding the dropdown-menu when it has lost focus $(this.body).click(function() { $mywrapper.find('.dropdown-menu').hide(); }); 5. Calling the getTimetable api when a user is selected from the drop-down menu and displaying their timetable and displayname in the widget title $mywrapper.find('ul.typeahead.dropdown-menu').on('click', 'li', function (e) { e.preventDefault(); $mywrapper.find('.search input').val($mywrapper.find("span").attr('title')); getTimetable($(this).data("value")); }); 6. Preventing the default behaviour of the return key (which wants to submit the form which would navigate us away from the page) $mywrapper.find('.search input').keypress(function(e) { if (e.which == 13) { e.preventDefault(); return false; } }); //this seems to be needed for IE to do anything right! $mywrapper.find('.search input').on('click', function(e) { e.stopPropagation(); }); That's it. I'm done. I'll post the entire code when i have had a chance to change everything suggested by @Chris.Smith. As for turning it into a FrogCode widget - sure, how hard could that be?! Especially if that means getting to use the FrogCode area of my FrogDrive that just appeared?!
×
×
  • Create New...