Results display properly
This commit is contained in:
parent
f8b18d4d6e
commit
b3af1fa8c4
2
amd/build/report-viewer-components.min.js
vendored
2
amd/build/report-viewer-components.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
amd/build/studyplan-report-components.min.js
vendored
2
amd/build/studyplan-report-components.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
amd/build/treestudyplan-components.min.js
vendored
2
amd/build/treestudyplan-components.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
3
amd/build/util/css-calc.min.js
vendored
Normal file
3
amd/build/util/css-calc.min.js
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
define("local_treestudyplan/util/css-calc",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.Units=_exports.UnitRegexpStr=_exports.UnitRegexpGM=_exports.UnitRegexp=_exports.Relative=_exports.Absolute=void 0,_exports.calc=calc,_exports.calcCtx=calcCtx,_exports.convert=convert,_exports.convertAllInStr=convertAllInStr;const Absolute={px:1,cm:96/2.54,mm:96/25.4,Q:96/101.6,in:96,pc:16,pt:96/72};_exports.Absolute=Absolute;const Relative={vh:function(){let count=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1,ctx=arguments.length>1?arguments[1]:void 0;return(ctx?ctx.viewportHeight:window.innerHeight)/100*count},vw:function(){let count=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1,ctx=arguments.length>1?arguments[1]:void 0;return(ctx?ctx.viewportWidth:window.innerWidth)/100*count},vmin:function(){let count=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1,ctx=arguments.length>1?arguments[1]:void 0;return(ctx?Math.min(ctx.viewportWidth,ctx.viewportHeight):Math.min(window.innerWidth,window.innerHeight))/100*count},vmax:function(){let count=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1,ctx=arguments.length>1?arguments[1]:void 0;return(ctx?Math.max(ctx.viewportWidth,ctx.viewportHeight):Math.max(window.innerWidth,window.innerHeight))/100*count},rem:function(){let count=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1,ctx=arguments.length>1?arguments[1]:void 0;return(ctx?ctx.htmlFontSize:parseFloat(window.getComputedStyle(document.querySelector("html")).fontSize))*count},"%w":function(){let count=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1,ctx=arguments.length>1?arguments[1]:void 0;return(ctx?ctx.width:document.body.clientWidth)/100*count},"%h":function(){let count=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1,ctx=arguments.length>1?arguments[1]:void 0;return(ctx?ctx.height:document.body.clientHeight)/100*count}};_exports.Relative=Relative;const Units={...Relative,...Absolute};_exports.Units=Units;const UnitRegexpStr=`(?:\\s|^)(\\d*(?:\\.\\d+)?)(${Object.keys(Units).join("|")})(?:\\s|$|\\n)`;_exports.UnitRegexpStr=UnitRegexpStr;const UnitRegexp=new RegExp(UnitRegexpStr);_exports.UnitRegexp=UnitRegexp;const UnitRegexpGM=new RegExp(UnitRegexpStr,"gm");function convert(count,fromUnits,toUnits){let ctx=arguments.length>3&&void 0!==arguments[3]?arguments[3]:calcCtx();const baseUnit=Units[fromUnits],basePx="function"==typeof baseUnit?baseUnit(count,ctx):baseUnit*count,dstUnit=Units[toUnits];return basePx/("function"==typeof dstUnit?dstUnit(1,ctx):dstUnit)}function convertAllInStr(expr,toUnits){let ctx=arguments.length>2&&void 0!==arguments[2]?arguments[2]:calcCtx();return expr.replace(UnitRegexpGM,((substr,count,unit)=>convert(parseFloat(count),unit,toUnits,ctx).toString()))}function calcCtx(el){if(el){const rect=el.getBoundingClientRect();return{width:rect.width,height:rect.height,viewportWidth:window.innerWidth,viewportHeight:window.innerHeight,htmlFontSize:parseFloat(window.getComputedStyle(document.querySelector("html")).fontSize)}}return{width:document.body.clientWidth,height:document.body.clientHeight,viewportWidth:window.innerWidth,viewportHeight:window.innerHeight,htmlFontSize:parseFloat(window.getComputedStyle(document.querySelector("html")).fontSize)}}function calc(expression,el_ctx,ctx){return void 0===el_ctx?ctx=calcCtx():el_ctx instanceof HTMLElement?ctx||(ctx=calcCtx(el_ctx)):ctx=el_ctx,eval(convertAllInStr(expression,"px",ctx))}_exports.UnitRegexpGM=UnitRegexpGM}));
|
||||
|
||||
//# sourceMappingURL=css-calc.min.js.map
|
1
amd/build/util/css-calc.min.js.map
Normal file
1
amd/build/util/css-calc.min.js.map
Normal file
File diff suppressed because one or more lines are too long
3
amd/build/util/fittext-vue.min.js
vendored
Normal file
3
amd/build/util/fittext-vue.min.js
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
define("local_treestudyplan/util/fittext-vue",["exports","./css-calc","./fitty","./textfit"],(function(_exports,_cssCalc,_fitty,_textfit){var obj;Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_fitty=(obj=_fitty)&&obj.__esModule?obj:{default:obj};var _default={install(Vue){Vue.component("fittext",{props:{maxsize:{type:String,default:"512px"},minsize:{type:String,default:"10px"},vertical:Boolean,singleline:Boolean,dynamic:Boolean},data:()=>({resizeObserver:null,mutationObserver:null}),computed:{rootStyle(){return this.vertical?"height: 100%;":"width: 100%;"}},methods:{},mounted(){(0,_fitty.default)(this.$refs.text,{minSize:(0,_cssCalc.calc)(this.minsize),maxSize:(0,_cssCalc.calc)(this.maxsize),vertical:this.vertical,multiline:!this.singleline})},unmounted(){this.mutationObserver&&this.mutationObserver.disconnect(),this.resizeObserver&&this.resizeObserver.disconnect()},template:"\n <div class='q-fittext' ref='container' :style=rootStyle\">\n <span :style=\"'display:block; white-space:'+ ((singleline)?'nowrap':'normal')+';'\" class='q-fittext-text' ref='text'><slot></slot>\n </span\n ></div>\n "})}};return _exports.default=_default,_exports.default}));
|
||||
|
||||
//# sourceMappingURL=fittext-vue.min.js.map
|
1
amd/build/util/fittext-vue.min.js.map
Normal file
1
amd/build/util/fittext-vue.min.js.map
Normal file
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"fittext-vue.min.js","sources":["../../src/util/fittext-vue.js"],"sourcesContent":["/*eslint no-unused-vars: warn */\n/*eslint max-len: [\"error\", { \"code\": 160 }] */\n/*eslint-disable no-trailing-spaces */\n/*eslint-env es6*/\n\nimport {calc} from \"./css-calc\";\nimport fitty from \"./fitty\";\nimport {textFit} from \"./textfit\";\n\nexport default {\n install(Vue/*,options*/){\n Vue.component('fittext',{\n props: {\n maxsize: {\n type: String,\n default: \"512px\",\n },\n minsize: {\n type: String,\n default: \"10px\",\n },\n vertical: Boolean,\n singleline: Boolean,\n dynamic: Boolean,\n },\n data() {\n return {\n resizeObserver: null,\n mutationObserver: null,\n };\n },\n computed: {\n rootStyle() {\n if (this.vertical) {\n return `height: 100%;`;\n } else {\n return `width: 100%;`;\n }\n }\n },\n methods: {\n },\n mounted() {\n const self = this;\n // If the content could change after initial presentation,\n // Use the fitty method. It is slightly worse on multiline horizontal text,\n // but better supports content that can change later on.\n fitty(self.$refs.text,\n {\n minSize: calc(self.minsize),\n maxSize: calc(self.maxsize),\n vertical: self.vertical,\n multiline: !self.singleline,\n });\n /*\n } else {\n // Since the method textFit uses does not do well with\n // content that is altered after the initial change, but it does to better\n // with vertically aligned text\n textFit(self.$refs.text,{\n multiLine: !self.singleline, // if true, textFit will not set white-space: no-wrap\n detectMultiLine: false, // disable to turn off automatic multi-line sensing\n minFontSize: calc(self.minsize),\n maxFontSize: calc(self.maxsize),\n reProcess: true, \n widthOnly: !self.vertical,\n });\n } */\n },\n unmounted() {\n if(this.mutationObserver) {\n this.mutationObserver.disconnect();\n }\n if(this.resizeObserver) {\n this.resizeObserver.disconnect();\n }\n },\n template: `\n <div class='q-fittext' ref='container' :style=rootStyle\">\n <span :style=\"'display:block; white-space:'+ ((singleline)?'nowrap':'normal')+';'\" class='q-fittext-text' ref='text'><slot></slot>\n </span\n ></div>\n `,\n });\n },\n};"],"names":["install","Vue","component","props","maxsize","type","String","default","minsize","vertical","Boolean","singleline","dynamic","data","resizeObserver","mutationObserver","computed","rootStyle","this","methods","mounted","$refs","text","minSize","maxSize","multiline","unmounted","disconnect","template"],"mappings":"qSASe,CACXA,QAAQC,KACJA,IAAIC,UAAU,UAAU,CACxBC,MAAO,CACHC,QAAS,CACLC,KAAMC,OACNC,QAAS,SAEbC,QAAS,CACLH,KAAMC,OACNC,QAAS,QAEbE,SAAUC,QACVC,WAAYD,QACZE,QAASF,SAEbG,KAAI,KACO,CACHC,eAAgB,KAChBC,iBAAkB,OAG1BC,SAAU,CACNC,mBACQC,KAAKT,SACG,gBAEA,iBAIpBU,QAAS,GAETC,6BACiBF,KAIFG,MAAMC,KACb,CACAC,SAAS,iBANAL,KAMUV,SACnBgB,SAAS,iBAPAN,KAOUd,SACnBK,SARSS,KAQMT,SACfgB,WATSP,KASQP,cAiBzBe,YACOR,KAAKH,uBACCA,iBAAiBY,aAEvBT,KAAKJ,qBACCA,eAAea,cAG5BC,SAAW"}
|
3
amd/build/util/fitty.min.js
vendored
Normal file
3
amd/build/util/fitty.min.js
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
define("local_treestudyplan/util/fitty",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0;var _default=(w=>{if(!w)return;const DrawState={IDLE:0,DIRTY_CONTENT:1,DIRTY_LAYOUT:2,DIRTY:3};let fitties=[],redrawFrame=null;const requestRedraw="requestAnimationFrame"in w?function(){let options=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{sync:!1};w.cancelAnimationFrame(redrawFrame);const redrawFn=()=>redraw(fitties.filter((f=>f.dirty&&f.active)));if(options.sync)return redrawFn();redrawFrame=w.requestAnimationFrame(redrawFn)}:()=>{},redrawAll=type=>options=>{fitties.forEach((f=>f.dirty=type)),requestRedraw(options)},redraw=fitties=>{fitties.filter((f=>!f.styleComputed)).forEach((f=>{f.styleComputed=computeStyle(f)})),fitties.filter(shouldPreStyle).forEach(applyStyle);const fittiesToRedraw=fitties.filter(shouldRedraw);fittiesToRedraw.forEach(calculateStyles),fittiesToRedraw.forEach((f=>{applyStyle(f),markAsClean(f)})),fittiesToRedraw.forEach(dispatchFitEvent)},markAsClean=f=>f.dirty=DrawState.IDLE,calculateStyles=f=>{f.vertical?(f.availableHeight=f.element.parentNode.clientHeight,f.currentHeight=f.element.scrollHeight,f.previousFontSize=f.currentFontSize,f.currentFontSize=Math.min(Math.max(f.minSize,f.availableHeight/f.currentHeight*f.previousFontSize),f.maxSize)):(f.availableWidth=f.element.parentNode.clientWidth,f.currentWidth=f.element.scrollWidth,f.previousFontSize=f.currentFontSize,f.currentFontSize=Math.min(Math.max(f.minSize,f.availableWidth/f.currentWidth*f.previousFontSize),f.maxSize)),f.whiteSpace=f.multiLine&&f.currentFontSize===f.minSize?"normal":"nowrap"},shouldRedraw=f=>f.vertical?f.dirty!==DrawState.DIRTY_LAYOUT||f.dirty===DrawState.DIRTY_LAYOUT&&f.element.parentNode.clientHeight!==f.availableHeight:f.dirty!==DrawState.DIRTY_LAYOUT||f.dirty===DrawState.DIRTY_LAYOUT&&f.element.parentNode.clientWidth!==f.availableWidth,computeStyle=f=>{const style=w.getComputedStyle(f.element,null);return f.currentFontSize=parseFloat(style.getPropertyValue("font-size")),f.display=style.getPropertyValue("display"),f.whiteSpace=style.getPropertyValue("white-space"),!0},shouldPreStyle=f=>{let preStyle=!1;return!f.preStyleTestCompleted&&(/inline-/.test(f.display)||(preStyle=!0,f.display="inline-block"),"nowrap"!==f.whiteSpace&&(preStyle=!0,f.whiteSpace="nowrap"),f.preStyleTestCompleted=!0,preStyle)},applyStyle=f=>{f.element.style.whiteSpace=f.whiteSpace,f.element.style.display=f.display,f.element.style.fontSize=f.currentFontSize+"px"},dispatchFitEvent=f=>{f.element.dispatchEvent(new CustomEvent("fit",{detail:{oldValue:f.previousFontSize,newValue:f.currentFontSize,scaleFactor:f.currentFontSize/f.previousFontSize}}))},fit=(f,type)=>options=>{f.dirty=type,f.active&&requestRedraw(options)},init=f=>{f.originalStyle={whiteSpace:f.element.style.whiteSpace,display:f.element.style.display,fontSize:f.element.style.fontSize},observeMutations(f),f.newbie=!0,f.dirty=!0,fitties.push(f)},destroy=f=>()=>{fitties=fitties.filter((_=>_.element!==f.element)),f.observeMutations&&f.observer.disconnect(),f.element.style.whiteSpace=f.originalStyle.whiteSpace,f.element.style.display=f.originalStyle.display,f.element.style.fontSize=f.originalStyle.fontSize},subscribe=f=>()=>{f.active||(f.active=!0,requestRedraw())},unsubscribe=f=>()=>f.active=!1,observeMutations=f=>{f.observeMutations&&(f.observer=new MutationObserver(fit(f,DrawState.DIRTY_CONTENT)),f.observer.observe(f.element,f.observeMutations))},defaultOptions={minSize:16,maxSize:512,multiLine:!0,vertical:!1,observeMutations:"MutationObserver"in w&&{subtree:!0,childList:!0,characterData:!0}};function fittyCreate(elements,options){const fittyOptions=Object.assign({},defaultOptions,options),publicFitties=elements.map((element=>{const f=Object.assign({},fittyOptions,{element:element,active:!0});return init(f),{element:element,fit:fit(f,DrawState.DIRTY),unfreeze:subscribe(f),freeze:unsubscribe(f),unsubscribe:destroy(f)}}));return requestRedraw(),publicFitties}function fitty(target){let options=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return"string"==typeof target?fittyCreate((nl=document.querySelectorAll(target),[].slice.call(nl)),options):fittyCreate([target],options)[0];var nl}let resizeDebounce=null;const onWindowResized=()=>{w.clearTimeout(resizeDebounce),resizeDebounce=w.setTimeout(redrawAll(DrawState.DIRTY_LAYOUT),fitty.observeWindowDelay)},events=["resize","orientationchange"];return Object.defineProperty(fitty,"observeWindow",{set:enabled=>{const method=(enabled?"add":"remove")+"EventListener";events.forEach((e=>{w[method](e,onWindowResized)}))}}),fitty.observeWindow=!0,fitty.observeWindowDelay=100,fitty.fitAll=redrawAll(DrawState.DIRTY),fitty})("undefined"==typeof window?null:window);return _exports.default=_default,_exports.default}));
|
||||
|
||||
//# sourceMappingURL=fitty.min.js.map
|
1
amd/build/util/fitty.min.js.map
Normal file
1
amd/build/util/fitty.min.js.map
Normal file
File diff suppressed because one or more lines are too long
3
amd/build/util/textfit.min.js
vendored
Normal file
3
amd/build/util/textfit.min.js
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
define("local_treestudyplan/util/textfit",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.textFit=function(els,options){options||(options={});var settings={};for(var key in defaultSettings)options.hasOwnProperty(key)?settings[key]=options[key]:settings[key]=defaultSettings[key];"function"==typeof els.toArray&&(els=els.toArray());var elType=Object.prototype.toString.call(els);"[object Array]"!==elType&&"[object NodeList]"!==elType&&"[object HTMLCollection]"!==elType&&(els=[els]);for(var i=0;i<els.length;i++)processItem(els[i],settings)};var defaultSettings={alignVert:!1,alignHoriz:!1,multiLine:!1,detectMultiLine:!0,minFontSize:6,maxFontSize:80,reProcess:!0,widthOnly:!1,alignVertWithFlexbox:!1};function processItem(el,settings){if(o=el,!("object"==typeof HTMLElement?o instanceof HTMLElement:o&&"object"==typeof o&&null!==o&&1===o.nodeType&&"string"==typeof o.nodeName)||!settings.reProcess&&el.getAttribute("textFitted"))return!1;var o,innerSpan,originalHeight,originalHTML,originalWidth,low,mid,high;if(settings.reProcess||el.setAttribute("textFitted",1),originalHTML=el.innerHTML,originalWidth=function(el){var style=window.getComputedStyle(el,null);return el.getBoundingClientRect().width-parseInt(style.getPropertyValue("padding-left"),10)-parseInt(style.getPropertyValue("padding-right"),10)}(el),originalHeight=function(el){var style=window.getComputedStyle(el,null);return el.getBoundingClientRect().height-parseInt(style.getPropertyValue("padding-top"),10)-parseInt(style.getPropertyValue("padding-bottom"),10)}(el),!originalWidth||!settings.widthOnly&&!originalHeight)throw settings.widthOnly?new Error("Set a static width on the target element "+el.outerHTML+" before using textFit!"):new Error("Set a static height and width on the target element "+el.outerHTML+" before using textFit!");-1===originalHTML.indexOf("textFitted")?((innerSpan=document.createElement("span")).className="textFitted",innerSpan.style.display="inline-block",innerSpan.innerHTML=originalHTML,el.innerHTML="",el.appendChild(innerSpan)):hasClass(innerSpan=el.querySelector("span.textFitted"),"textFitAlignVert")&&(innerSpan.className=innerSpan.className.replace("textFitAlignVert",""),innerSpan.style.height="",el.className.replace("textFitAlignVertFlex","")),settings.alignHoriz&&(el.style["text-align"]="center",innerSpan.style["text-align"]="center");var multiLine=settings.multiLine;settings.detectMultiLine&&!multiLine&&innerSpan.getBoundingClientRect().height>=2*parseInt(window.getComputedStyle(innerSpan)["font-size"],10)&&(multiLine=!0),multiLine||(el.style["white-space"]="nowrap"),low=settings.minFontSize,high=settings.maxFontSize;for(var size=low;low<=high;){mid=(high+low)/2,innerSpan.style.fontSize=mid+"px";var innerSpanBoundingClientRect=innerSpan.getBoundingClientRect();innerSpanBoundingClientRect.width<=originalWidth&&(settings.widthOnly||innerSpanBoundingClientRect.height<=originalHeight)?(size=mid,low=mid+1):high=mid-1}if(innerSpan.style.fontSize!=size+"px"&&(innerSpan.style.fontSize=size+"px"),settings.alignVert){!function(){if(document.getElementById("textFitStyleSheet"))return;var style=[".textFitAlignVert{","position: absolute;","top: 0; right: 0; bottom: 0; left: 0;","margin: auto;","display: flex;","justify-content: center;","flex-direction: column;","}",".textFitAlignVertFlex{","display: flex;","}",".textFitAlignVertFlex .textFitAlignVert{","position: static;","}"].join(""),css=document.createElement("style");css.type="text/css",css.id="textFitStyleSheet",css.innerHTML=style,document.body.appendChild(css)}();var height=innerSpan.scrollHeight;"static"===window.getComputedStyle(el).position&&(el.style.position="relative"),hasClass(innerSpan,"textFitAlignVert")||(innerSpan.className=innerSpan.className+" textFitAlignVert"),innerSpan.style.height=height+"px",settings.alignVertWithFlexbox&&!hasClass(el,"textFitAlignVertFlex")&&(el.className=el.className+" textFitAlignVertFlex")}}function hasClass(element,cls){return(" "+element.className+" ").indexOf(" "+cls+" ")>-1}}));
|
||||
|
||||
//# sourceMappingURL=textfit.min.js.map
|
1
amd/build/util/textfit.min.js.map
Normal file
1
amd/build/util/textfit.min.js.map
Normal file
File diff suppressed because one or more lines are too long
|
@ -489,7 +489,10 @@ export default {
|
|||
}
|
||||
}
|
||||
return startpageindex;
|
||||
}
|
||||
},
|
||||
wwwroot() {
|
||||
return Config.wwwroot;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
pageduration(page){
|
||||
|
@ -558,7 +561,7 @@ export default {
|
|||
|
||||
ItemEventBus.$emit('redrawLines', null);
|
||||
scrollCurrentIntoView(this.selectedpage.id);
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
// scrollCurrentIntoView(this.selectedpage.id);
|
||||
|
@ -624,7 +627,12 @@ export default {
|
|||
<div v-if="page.studylines.length > 0" class='r-studyplan-content'>
|
||||
<!-- First paint the headings-->
|
||||
<div class='r-studyplan-headings'
|
||||
><s-studyline-header-heading :identifier="Number(page.id)"></s-studyline-header-heading>
|
||||
><s-studyline-header-heading :identifier="Number(page.id)"
|
||||
><a v-if="selectedpage"
|
||||
:href="wwwroot+'//local/treestudyplan/studyplan-report.php?page='+selectedpage.id"
|
||||
|
||||
target='_blank'><i class='fa fa-file-text'></i></a
|
||||
></s-studyline-header-heading>
|
||||
<r-studyline-heading v-for="(line,lineindex) in page.studylines"
|
||||
:key="line.id"
|
||||
v-model="page.studylines[lineindex]"
|
||||
|
@ -643,7 +651,11 @@ export default {
|
|||
v-if="index > 0"
|
||||
v-model="page.perioddesc[index-1]"
|
||||
:identifier="Number(page.id)"
|
||||
></s-studyline-header-period>
|
||||
><a v-if="selectedpage"
|
||||
:href="wwwroot+'//local/treestudyplan/studyplan-report.php?page='+selectedpage.id
|
||||
+'&firstperiod='+index+'&lastperiod='+index"
|
||||
target='_blank'><i class='fa fa-file-text'></i></a
|
||||
></s-studyline-header-period>
|
||||
<div class="s-studyline-header-filter"></div>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import notification from 'core/notification';
|
|||
import Debugger from './util/debugger';
|
||||
import Config from 'core/config';
|
||||
import TSComponents from './treestudyplan-components';
|
||||
import FitTextVue from './util/fittext-vue';
|
||||
|
||||
|
||||
const debug = new Debugger("treestudyplan-viewer");
|
||||
|
@ -29,8 +30,8 @@ const LINE_GRAVITY = 1.3;
|
|||
function conditionHeaders(item) {
|
||||
const course = item.course;
|
||||
const list = [];
|
||||
if (course.completion) {
|
||||
for (const cmp of course.competencies) {
|
||||
if (course.competency) {
|
||||
for (const cmp of course.competency.competencies) {
|
||||
list.push({
|
||||
name: cmp.title,
|
||||
});
|
||||
|
@ -46,14 +47,12 @@ function conditionHeaders(item) {
|
|||
} else if(course.grades) {
|
||||
for(const g of course.grades) {
|
||||
if (g.selected) {
|
||||
debug.info("...included");
|
||||
list.push({
|
||||
name: g.name,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
debug.info("Returning list",list);
|
||||
return list;
|
||||
}
|
||||
|
||||
|
@ -64,8 +63,8 @@ function conditionHeaders(item) {
|
|||
function conditions(item) {
|
||||
const course = item.course;
|
||||
const list = [];
|
||||
if (course.completion) {
|
||||
for (const cmp of course.competencies) {
|
||||
if (course.competency) {
|
||||
for (const cmp of course.competency.competencies) {
|
||||
list.push(cmp);
|
||||
}
|
||||
} else if(course.completion) {
|
||||
|
@ -88,6 +87,7 @@ function conditions(item) {
|
|||
export default {
|
||||
install(Vue/*,options*/){
|
||||
Vue.use(TSComponents);
|
||||
Vue.use(FitTextVue);
|
||||
|
||||
let strings = load_strings({
|
||||
report: {
|
||||
|
@ -153,6 +153,7 @@ export default {
|
|||
immediate: true,
|
||||
handler (structure) {
|
||||
// (Re)build expansion info structure
|
||||
let firstperiod = true;
|
||||
for (const period of structure.periods) {
|
||||
const pid = period.period.id;
|
||||
if (!this.expansioninfo.periods[pid]) {
|
||||
|
@ -161,7 +162,7 @@ export default {
|
|||
this.expansioninfo.periods,
|
||||
pid,
|
||||
{
|
||||
expanded: false,
|
||||
expanded: (firstperiod?true:false),
|
||||
}
|
||||
);
|
||||
this.$set(
|
||||
|
@ -195,6 +196,7 @@ export default {
|
|||
}
|
||||
}
|
||||
}
|
||||
firstperiod = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -208,16 +210,16 @@ export default {
|
|||
for (const period of this.structure.periods) {
|
||||
const pid = period.period.id;
|
||||
if (!this.expansioninfo.periods[pid].expanded) {
|
||||
// This period is not expanded. Just one
|
||||
count += 1;
|
||||
// This period is not expanded. Make it 3 units wide
|
||||
count += 3;
|
||||
} else {
|
||||
for (const line of period.lines) {
|
||||
const lid = line.line.id;
|
||||
if (!this.expansioninfo.lines[pid][lid]) {
|
||||
if (!this.expansioninfo.lines[pid][lid].expanded) {
|
||||
count +=1;
|
||||
} else {
|
||||
for (const item of line.items) {
|
||||
if (!this.expansioninfo.items[item.id]) {
|
||||
if (!this.expansioninfo.items[item.id].expanded) {
|
||||
count += 1;
|
||||
} else {
|
||||
count += 1 + conditions(item).length;
|
||||
|
@ -290,7 +292,8 @@ export default {
|
|||
|
||||
},
|
||||
template: `
|
||||
<table class='q-studyplanreport'>
|
||||
<table class='q-studyplanreport'
|
||||
:style="'--resultColCount: '+resultColCount+';'">
|
||||
<q-header
|
||||
:sorting='sorting'
|
||||
:structure='structure'
|
||||
|
@ -338,7 +341,6 @@ export default {
|
|||
},
|
||||
colspanPeriod(period) {
|
||||
const pid = period.period.id;
|
||||
debug.info("Checking period expansion",period,this.expansion.periods);
|
||||
if (this.expansion.periods[pid].expanded) {
|
||||
let sum = 0;
|
||||
for (const l of period.lines) {
|
||||
|
@ -370,8 +372,26 @@ export default {
|
|||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
togglePeriod(period,val) {
|
||||
if ( val === undefined) {
|
||||
val = !(this.expansion.periods[period.id].expanded);
|
||||
}
|
||||
this.$emit('expansion','periods',period.id,val);
|
||||
},
|
||||
toggleLine(period,line,val) {
|
||||
if ( val === undefined) {
|
||||
val = !(this.expansion.lines[period.id][line.id].expanded);
|
||||
}
|
||||
this.$emit('expansion','lines',[period.id,line.id],val);
|
||||
},
|
||||
toggleItem(item,val) {
|
||||
if ( val === undefined) {
|
||||
val = !(this.expansion.items[item.id].expanded);
|
||||
}
|
||||
debug.info("Toggle item",item,val);
|
||||
this.$emit('expansion','items',item.id,val);
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
|
||||
|
@ -387,25 +407,29 @@ export default {
|
|||
<tr> <!-- period heading -->
|
||||
<th rowspan='4' class='q-studentname'><span>{{text.students}}</span></th>
|
||||
<th v-for="p in structure.periods"
|
||||
class='q-period-heading'
|
||||
:class="'q-period-heading '+ ((expansion.periods[p.period.id].expanded)?'expanded':'collapsed')"
|
||||
:colspan='colspanPeriod(p)'
|
||||
:rowspan='(expansion.periods[p.period.id].expanded)?1:4'
|
||||
><a v-if="expansion.periods[p.period.id].expanded"
|
||||
href='#' @click.prevent="$emit('expansion','periods',p.period.id,false);"
|
||||
><i class='fa fa-minus-square'></i></a
|
||||
><a v-else
|
||||
href='#' @click.prevent="$emit('expansion','periods',p.period.id,true);"
|
||||
><i class='fa fa-plus-square'></i></a
|
||||
> {{ p.period.fullname}}
|
||||
</th>
|
||||
><span class="q-wrap"><a href='#' @click.prevent="togglePeriod(p.period)"
|
||||
><i v-if="expansion.periods[p.period.id].expanded"
|
||||
class='q-chevron fa fa-chevron-down'></i
|
||||
><i v-else class='q-chevron fa fa-chevron-right'></i
|
||||
> {{ p.period.fullname}}</a></span
|
||||
></th>
|
||||
</tr>
|
||||
<tr> <!-- line heading -->
|
||||
<template v-for="p in structure.periods">
|
||||
<template v-if="expansion.periods[p.period.id].expanded">
|
||||
<th v-for="l in p.lines"
|
||||
class='q-line-heading'
|
||||
:class="'q-line-heading ' + ((expansion.lines[p.period.id][l.line.id].expanded)?'expanded':'collapsed')"
|
||||
:colspan="colspanLine(p,l)"
|
||||
><span v-html="l.line.shortname"></span
|
||||
:rowspan='(expansion.lines[p.period.id][l.line.id].expanded)?1:3'
|
||||
><span class="q-wrap"><fittext vertical maxsize="18pt"
|
||||
><span class='q-label'
|
||||
:title="l.line.shortname"
|
||||
v-html="l.line.shortname"
|
||||
></span
|
||||
></fittext></span
|
||||
></th>
|
||||
</template>
|
||||
</template>
|
||||
|
@ -419,13 +443,22 @@ export default {
|
|||
:class="'q-item-heading ' + ((expansion.items[item.id].expanded)?'expanded':'collapsed')"
|
||||
:colspan="colspanItem(item)"
|
||||
:rowspan='(expansion.items[item.id].expanded)?1:2'
|
||||
><a v-if="expansion.items[item.id].expanded"
|
||||
href='#' @click.prevent="$emit('expansion','items',item.id,false);"
|
||||
><i class='fa fa-minus-square'></i></a
|
||||
><a v-else
|
||||
href='#' @click.prevent="$emit('expansion','items',item.id,true);"
|
||||
><i class='fa fa-plus-square'></i></a
|
||||
> <span v-html="item.course.displayname"></span
|
||||
><span class="q-wrap"><a href='#'
|
||||
@click.prevent="toggleItem(item)"
|
||||
><i v-if="expansion.items[item.id].expanded"
|
||||
class='q-chevron fa fa-chevron-down'></i
|
||||
><i v-else
|
||||
class='q-chevron fa fa-chevron-right'></i
|
||||
></a
|
||||
> <a style="display: inline-block;" href='#'
|
||||
@click.prevent="toggleItem(item)"
|
||||
><fittext vertical maxsize="18pt" singleline
|
||||
><span class='q-label'
|
||||
:title="item.course.displayname"
|
||||
v-html="item.course.displayname"
|
||||
></span
|
||||
></fittext
|
||||
></a></span
|
||||
></th>
|
||||
</template>
|
||||
</template>
|
||||
|
@ -440,10 +473,13 @@ export default {
|
|||
<template v-for="item in l.items">
|
||||
<template v-if="expansion.items[item.id].expanded">
|
||||
<th class='q-condition-heading overall'
|
||||
><span>{{ text.overall }}</span></th>
|
||||
><span class='q-wrap'>{{ text.overall }}</span></th>
|
||||
<th v-for="c in conditions(item)"
|
||||
class='q-condition-heading'
|
||||
><span v-html="c.name"></span
|
||||
><span class="q-wrap"><fittext vertical maxsize="18pt"><span class='q-label'
|
||||
:title="c.name"
|
||||
v-html="c.name"></span
|
||||
></span></fittext
|
||||
></th>
|
||||
</template>
|
||||
</template>
|
||||
|
@ -673,9 +709,8 @@ export default {
|
|||
return (course.completion || course.competency || course.grades);
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
completion_icon(completion) {
|
||||
completion_icon() {
|
||||
const completion = this.condition_completion();
|
||||
switch(completion){
|
||||
default: // case "incomplete"
|
||||
return "circle-o";
|
||||
|
@ -693,24 +728,70 @@ export default {
|
|||
return "check-circle";
|
||||
}
|
||||
},
|
||||
condition_value() {
|
||||
const course = this.item.course;
|
||||
if (course.competency) {
|
||||
if (this.condition.grade) {
|
||||
// Return grade if possible.
|
||||
return this.condition.grade;
|
||||
}
|
||||
} else if(course.completion) {
|
||||
if (this.condition.grade) {
|
||||
// Return grade if possible.
|
||||
return this.condition.grade;
|
||||
}
|
||||
} else if(course.grades) {
|
||||
return this.condition.grade;
|
||||
}
|
||||
// Fallback to completion icon.
|
||||
const icon = this.completion_icon();
|
||||
return `<i class='fa fa-${icon}'></i>`;
|
||||
},
|
||||
condition_completion() {
|
||||
// Unify completion information
|
||||
const course = this.item.course;
|
||||
if (course.competency) {
|
||||
const competency = this.condition;
|
||||
if (competency.proficient && competency.courseproficient) {
|
||||
return "completed";
|
||||
} else if (competency.proficient) {
|
||||
return "completed";
|
||||
} else if (competency.proficient === false) {
|
||||
return "failed";
|
||||
} else if (competency.progress) {
|
||||
return "progress";
|
||||
} else {
|
||||
return "incomplete";
|
||||
}
|
||||
} else if(course.completion) {
|
||||
return this.condition.status;
|
||||
} else if(course.grades) {
|
||||
return this.condition.completion;
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
methods: {
|
||||
},
|
||||
// TODO: Show actual grades when relevant at all (don;t forget the grade point completion requirement)
|
||||
template: `
|
||||
<span class='q-conditionresult'>
|
||||
<template v-if="loading">
|
||||
<div class="spinner-border spinner-border-sm text-info" role="status"></div>
|
||||
</template>
|
||||
<template v-else-if='!item.course.enrolled'>
|
||||
<i v-b-popover.top
|
||||
class="fa fa-exclamation-triangle t-not-enrolled-alert"
|
||||
:title="text.student_not_tracked"></i>
|
||||
</template>
|
||||
<template v-else>
|
||||
<i v-b-popover.top
|
||||
:class="'fa fa-'+completion_icon(item.completion)+
|
||||
' r-completion-'+item.completion"
|
||||
:title="text['completion_'+item.completion]"></i>
|
||||
</template>
|
||||
<fittext maxsize="10pt" singleline dynamic>
|
||||
<template v-if="loading">
|
||||
<div class="spinner-border spinner-border-sm text-info" role="status"></div>
|
||||
</template>
|
||||
<template v-else-if='!item.course.enrolled'>
|
||||
<i class="fa fa-ellipsis-h"
|
||||
:title="text.student_not_tracked"></i>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span
|
||||
:class="'r-completion-'+condition_completion"
|
||||
:title="text['completion_'+condition_completion]"
|
||||
>{{condition_value}}</span
|
||||
>
|
||||
</template>
|
||||
</fittext>
|
||||
</span>
|
||||
`,
|
||||
});
|
||||
|
|
|
@ -210,7 +210,7 @@ export default {
|
|||
}
|
||||
},
|
||||
template: `
|
||||
<div class="s-studyline-header-heading" ref="main" :data-id="identifier"></div>
|
||||
<div class="s-studyline-header-heading" ref="main" :data-id="identifier"><slot></slot></div>
|
||||
`,
|
||||
});
|
||||
|
||||
|
|
198
amd/src/util/css-calc.js
Normal file
198
amd/src/util/css-calc.js
Normal file
|
@ -0,0 +1,198 @@
|
|||
/*eslint no-trailing-spaces: "off"*/
|
||||
/*eslint no-eval: "off"*/
|
||||
|
||||
/***********************************
|
||||
* Licence: MIT
|
||||
* (c) 2023 Morglod/jchnkl
|
||||
* converted from the typescript @ https://github.com/Morglod/csscalc/
|
||||
*/
|
||||
|
||||
// units -> pixels
|
||||
export const Absolute = {
|
||||
/** browser version of pixel */
|
||||
px: 1,
|
||||
/** One centimeter. 1cm = 96px/2.54 */
|
||||
cm: 96 / 2.54,
|
||||
/** One millimeter. 1mm = 1/10th of 1cm */
|
||||
mm: 96 / 25.4,
|
||||
/** One quarter of a millimeter. 1Q = 1/40th of 1cm */
|
||||
Q: 96 / 101.6,
|
||||
/** One inch. 1in = 2.54cm = 96px */
|
||||
in: 96,
|
||||
/** One pica. 1pc = 12pt = 1/6th of 1in */
|
||||
pc: 96 / 6,
|
||||
/** One point. 1pt = 1/72nd of 1in */
|
||||
pt: 96 / 72
|
||||
};
|
||||
|
||||
// units ->(calc context)-> pixels
|
||||
export const Relative = {
|
||||
/**
|
||||
* Equal to 1% of the height of the viewport
|
||||
* @param {number} count
|
||||
* @param {object} ctx
|
||||
*/
|
||||
vh: (count = 1, ctx) => {
|
||||
return ((ctx ? ctx.viewportHeight : window.innerHeight) / 100) * count;
|
||||
},
|
||||
/**
|
||||
* Equal to 1% of the width of the viewport
|
||||
* @param {number} count
|
||||
* @param {object} ctx
|
||||
*/
|
||||
vw: (count = 1, ctx) => {
|
||||
return ((ctx ? ctx.viewportWidth : window.innerWidth) / 100) * count;
|
||||
},
|
||||
/**
|
||||
* 1/100th of the smallest viewport side
|
||||
* @param {number} count
|
||||
* @param {object} ctx
|
||||
*/
|
||||
vmin: (count = 1, ctx) => {
|
||||
return (
|
||||
((ctx
|
||||
? Math.min(ctx.viewportWidth, ctx.viewportHeight)
|
||||
: Math.min(window.innerWidth, window.innerHeight)) /
|
||||
100) *
|
||||
count
|
||||
);
|
||||
},
|
||||
/**
|
||||
* 1/100th of the largest viewport side
|
||||
* @param {number} count
|
||||
* @param {object} ctx
|
||||
*/
|
||||
vmax: (count = 1, ctx) => {
|
||||
return (
|
||||
((ctx
|
||||
? Math.max(ctx.viewportWidth, ctx.viewportHeight)
|
||||
: Math.max(window.innerWidth, window.innerHeight)) /
|
||||
100) *
|
||||
count
|
||||
);
|
||||
},
|
||||
/**
|
||||
* Represents the font-size of <html> element
|
||||
* @param {number} count
|
||||
* @param {object} ctx
|
||||
*/
|
||||
rem: (count = 1, ctx) => {
|
||||
return (
|
||||
(ctx
|
||||
? ctx.htmlFontSize
|
||||
: parseFloat(
|
||||
window.getComputedStyle(document.querySelector("html")).fontSize
|
||||
)) * count
|
||||
);
|
||||
},
|
||||
/**
|
||||
* percent of width
|
||||
* @param {number} count
|
||||
* @param {object} ctx
|
||||
*/
|
||||
"%w": (count = 1, ctx) => {
|
||||
return ((ctx ? ctx.width : document.body.clientWidth) / 100) * count;
|
||||
},
|
||||
/**
|
||||
* percent of height
|
||||
* @param {number} count
|
||||
* @param {object} ctx
|
||||
*/
|
||||
"%h": (count = 1, ctx) => {
|
||||
return ((ctx ? ctx.height : document.body.clientHeight) / 100) * count;
|
||||
}
|
||||
};
|
||||
|
||||
export const Units = {
|
||||
...Relative,
|
||||
...Absolute
|
||||
};
|
||||
|
||||
export const UnitRegexpStr = `(?:\\s|^)(\\d*(?:\\.\\d+)?)(${Object.keys(
|
||||
Units
|
||||
).join("|")})(?:\\s|$|\\n)`;
|
||||
export const UnitRegexp = new RegExp(UnitRegexpStr);
|
||||
export const UnitRegexpGM = new RegExp(UnitRegexpStr, "gm");
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {*} count
|
||||
* @param {*} fromUnits
|
||||
* @param {*} toUnits
|
||||
* @param {*} ctx
|
||||
* @returns
|
||||
*/
|
||||
export function convert(count, fromUnits, toUnits, ctx = calcCtx()) {
|
||||
const baseUnit = Units[fromUnits];
|
||||
const basePx =
|
||||
typeof baseUnit === "function" ? baseUnit(count, ctx) : baseUnit * count;
|
||||
|
||||
const dstUnit = Units[toUnits];
|
||||
const dstBasePx = typeof dstUnit === "function" ? dstUnit(1, ctx) : dstUnit;
|
||||
|
||||
return basePx / dstBasePx;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {*} expr
|
||||
* @param {*} toUnits
|
||||
* @param {*} ctx
|
||||
* @returns
|
||||
*/
|
||||
export function convertAllInStr(expr, toUnits, ctx = calcCtx()) {
|
||||
return expr.replace(UnitRegexpGM, (substr, count, unit) => {
|
||||
return convert(parseFloat(count), unit, toUnits, ctx).toString();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {*} el
|
||||
* @returns
|
||||
*/
|
||||
export function calcCtx(el) {
|
||||
if (el) {
|
||||
const rect = el.getBoundingClientRect();
|
||||
|
||||
return {
|
||||
width: rect.width,
|
||||
height: rect.height,
|
||||
viewportWidth: window.innerWidth,
|
||||
viewportHeight: window.innerHeight,
|
||||
htmlFontSize: parseFloat(
|
||||
window.getComputedStyle(document.querySelector("html")).fontSize
|
||||
),
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
width: document.body.clientWidth,
|
||||
height: document.body.clientHeight,
|
||||
viewportWidth: window.innerWidth,
|
||||
viewportHeight: window.innerHeight,
|
||||
htmlFontSize: parseFloat(
|
||||
window.getComputedStyle(document.querySelector("html")).fontSize
|
||||
)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {*} expression
|
||||
* @param {*} el_ctx
|
||||
* @param {*} ctx
|
||||
* @returns
|
||||
*/
|
||||
export function calc(expression, el_ctx, ctx) {
|
||||
if (el_ctx === undefined) {ctx = calcCtx(); }
|
||||
else {
|
||||
if (el_ctx instanceof HTMLElement) {
|
||||
if (!ctx) {ctx = calcCtx(el_ctx); }
|
||||
} else {
|
||||
ctx = el_ctx;
|
||||
}
|
||||
}
|
||||
|
||||
return eval(convertAllInStr(expression, "px", ctx));
|
||||
}
|
86
amd/src/util/fittext-vue.js
Normal file
86
amd/src/util/fittext-vue.js
Normal file
|
@ -0,0 +1,86 @@
|
|||
/*eslint no-unused-vars: warn */
|
||||
/*eslint max-len: ["error", { "code": 160 }] */
|
||||
/*eslint-disable no-trailing-spaces */
|
||||
/*eslint-env es6*/
|
||||
|
||||
import {calc} from "./css-calc";
|
||||
import fitty from "./fitty";
|
||||
import {textFit} from "./textfit";
|
||||
|
||||
export default {
|
||||
install(Vue/*,options*/){
|
||||
Vue.component('fittext',{
|
||||
props: {
|
||||
maxsize: {
|
||||
type: String,
|
||||
default: "512px",
|
||||
},
|
||||
minsize: {
|
||||
type: String,
|
||||
default: "10px",
|
||||
},
|
||||
vertical: Boolean,
|
||||
singleline: Boolean,
|
||||
dynamic: Boolean,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
resizeObserver: null,
|
||||
mutationObserver: null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
rootStyle() {
|
||||
if (this.vertical) {
|
||||
return `height: 100%;`;
|
||||
} else {
|
||||
return `width: 100%;`;
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
},
|
||||
mounted() {
|
||||
const self = this;
|
||||
// If the content could change after initial presentation,
|
||||
// Use the fitty method. It is slightly worse on multiline horizontal text,
|
||||
// but better supports content that can change later on.
|
||||
fitty(self.$refs.text,
|
||||
{
|
||||
minSize: calc(self.minsize),
|
||||
maxSize: calc(self.maxsize),
|
||||
vertical: self.vertical,
|
||||
multiline: !self.singleline,
|
||||
});
|
||||
/*
|
||||
} else {
|
||||
// Since the method textFit uses does not do well with
|
||||
// content that is altered after the initial change, but it does to better
|
||||
// with vertically aligned text
|
||||
textFit(self.$refs.text,{
|
||||
multiLine: !self.singleline, // if true, textFit will not set white-space: no-wrap
|
||||
detectMultiLine: false, // disable to turn off automatic multi-line sensing
|
||||
minFontSize: calc(self.minsize),
|
||||
maxFontSize: calc(self.maxsize),
|
||||
reProcess: true,
|
||||
widthOnly: !self.vertical,
|
||||
});
|
||||
} */
|
||||
},
|
||||
unmounted() {
|
||||
if(this.mutationObserver) {
|
||||
this.mutationObserver.disconnect();
|
||||
}
|
||||
if(this.resizeObserver) {
|
||||
this.resizeObserver.disconnect();
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<div class='q-fittext' ref='container' :style=rootStyle">
|
||||
<span :style="'display:block; white-space:'+ ((singleline)?'nowrap':'normal')+';'" class='q-fittext-text' ref='text'><slot></slot>
|
||||
</span
|
||||
></div>
|
||||
`,
|
||||
});
|
||||
},
|
||||
};
|
369
amd/src/util/fitty.js
Normal file
369
amd/src/util/fitty.js
Normal file
|
@ -0,0 +1,369 @@
|
|||
/*eslint no-console: "off"*/
|
||||
/*
|
||||
Copyright (c) 2017-2021 Rik Schennink - All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies
|
||||
or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
export default ((w) => {
|
||||
// no window, early exit
|
||||
if (!w) { return; }
|
||||
|
||||
// node list to array helper method
|
||||
const toArray = (nl) => [].slice.call(nl);
|
||||
|
||||
// states
|
||||
const DrawState = {
|
||||
IDLE: 0,
|
||||
DIRTY_CONTENT: 1,
|
||||
DIRTY_LAYOUT: 2,
|
||||
DIRTY: 3,
|
||||
};
|
||||
|
||||
// all active fitty elements
|
||||
let fitties = [];
|
||||
|
||||
// group all redraw calls till next frame, we cancel each frame request when a new one comes in.
|
||||
// If no support for request animation frame, this is an empty function and supports for fitty stops.
|
||||
let redrawFrame = null;
|
||||
const requestRedraw =
|
||||
'requestAnimationFrame' in w
|
||||
? (options = { sync: false }) => {
|
||||
w.cancelAnimationFrame(redrawFrame);
|
||||
|
||||
const redrawFn = () => redraw(fitties.filter((f) => f.dirty && f.active));
|
||||
|
||||
if (options.sync) { return redrawFn(); }
|
||||
|
||||
redrawFrame = w.requestAnimationFrame(redrawFn);
|
||||
}
|
||||
: () => {};
|
||||
|
||||
// sets all fitties to dirty so they are redrawn on the next redraw loop, then calls redraw
|
||||
const redrawAll = (type) => (options) => {
|
||||
fitties.forEach((f) => (f.dirty = type));
|
||||
requestRedraw(options);
|
||||
};
|
||||
|
||||
// redraws fitties so they nicely fit their parent container
|
||||
const redraw = (fitties) => {
|
||||
// getting info from the DOM at this point should not trigger a reflow,
|
||||
// let's gather as much intel as possible before triggering a reflow
|
||||
|
||||
// check if styles of all fitties have been computed
|
||||
fitties
|
||||
.filter((f) => !f.styleComputed)
|
||||
.forEach((f) => {
|
||||
f.styleComputed = computeStyle(f);
|
||||
});
|
||||
|
||||
// restyle elements that require pre-styling, this triggers a reflow, please try to prevent by adding CSS rules (see docs)
|
||||
fitties.filter(shouldPreStyle).forEach(applyStyle);
|
||||
|
||||
// we now determine which fitties should be redrawn
|
||||
const fittiesToRedraw = fitties.filter(shouldRedraw);
|
||||
|
||||
// we calculate final styles for these fitties
|
||||
fittiesToRedraw.forEach(calculateStyles);
|
||||
|
||||
// now we apply the calculated styles from our previous loop
|
||||
fittiesToRedraw.forEach((f) => {
|
||||
applyStyle(f);
|
||||
markAsClean(f);
|
||||
});
|
||||
|
||||
// now we dispatch events for all restyled fitties
|
||||
fittiesToRedraw.forEach(dispatchFitEvent);
|
||||
};
|
||||
|
||||
const markAsClean = (f) => (f.dirty = DrawState.IDLE);
|
||||
|
||||
const calculateStyles = (f) => {
|
||||
if (f.vertical) {
|
||||
// get available width from parent node
|
||||
f.availableHeight = f.element.parentNode.clientHeight;
|
||||
|
||||
// the space our target element uses
|
||||
f.currentHeight = f.element.scrollHeight;
|
||||
|
||||
// remember current font size
|
||||
f.previousFontSize = f.currentFontSize;
|
||||
|
||||
// let's calculate the new font size
|
||||
f.currentFontSize = Math.min(
|
||||
Math.max(f.minSize, (f.availableHeight / f.currentHeight) * f.previousFontSize),
|
||||
f.maxSize
|
||||
);
|
||||
|
||||
} else {
|
||||
// get available width from parent node
|
||||
f.availableWidth = f.element.parentNode.clientWidth;
|
||||
|
||||
// the space our target element uses
|
||||
f.currentWidth = f.element.scrollWidth;
|
||||
|
||||
// remember current font size
|
||||
f.previousFontSize = f.currentFontSize;
|
||||
|
||||
// let's calculate the new font size
|
||||
f.currentFontSize = Math.min(
|
||||
Math.max(f.minSize, (f.availableWidth / f.currentWidth) * f.previousFontSize),
|
||||
f.maxSize
|
||||
);
|
||||
}
|
||||
// if allows wrapping, only wrap when at minimum font size (otherwise would break container)
|
||||
f.whiteSpace = f.multiLine && f.currentFontSize === f.minSize ? 'normal' : 'nowrap';
|
||||
};
|
||||
|
||||
// should always redraw if is not dirty layout, if is dirty layout, only redraw if size has changed
|
||||
const shouldRedraw = (f) => {
|
||||
if (f.vertical) {
|
||||
return f.dirty !== DrawState.DIRTY_LAYOUT ||
|
||||
(f.dirty === DrawState.DIRTY_LAYOUT &&
|
||||
f.element.parentNode.clientHeight !== f.availableHeight);
|
||||
} else {
|
||||
return f.dirty !== DrawState.DIRTY_LAYOUT ||
|
||||
(f.dirty === DrawState.DIRTY_LAYOUT &&
|
||||
f.element.parentNode.clientWidth !== f.availableWidth);
|
||||
}
|
||||
};
|
||||
// every fitty element is tested for invalid styles
|
||||
const computeStyle = (f) => {
|
||||
// get style properties
|
||||
const style = w.getComputedStyle(f.element, null);
|
||||
|
||||
// get current font size in pixels (if we already calculated it, use the calculated version)
|
||||
f.currentFontSize = parseFloat(style.getPropertyValue('font-size'));
|
||||
|
||||
// get display type and wrap mode
|
||||
f.display = style.getPropertyValue('display');
|
||||
f.whiteSpace = style.getPropertyValue('white-space');
|
||||
|
||||
// styles computed
|
||||
return true;
|
||||
};
|
||||
|
||||
// determines if this fitty requires initial styling, can be prevented by applying correct styles through CSS
|
||||
const shouldPreStyle = (f) => {
|
||||
let preStyle = false;
|
||||
|
||||
// if we already tested for prestyling we don't have to do it again
|
||||
if (f.preStyleTestCompleted) { return false; }
|
||||
|
||||
// should have an inline style, if not, apply
|
||||
if (!/inline-/.test(f.display)) {
|
||||
preStyle = true;
|
||||
f.display = 'inline-block';
|
||||
}
|
||||
|
||||
// to correctly calculate dimensions the element should have whiteSpace set to nowrap
|
||||
if (f.whiteSpace !== 'nowrap') {
|
||||
preStyle = true;
|
||||
f.whiteSpace = 'nowrap';
|
||||
}
|
||||
|
||||
// we don't have to do this twice
|
||||
f.preStyleTestCompleted = true;
|
||||
|
||||
return preStyle;
|
||||
};
|
||||
|
||||
// apply styles to single fitty
|
||||
const applyStyle = (f) => {
|
||||
f.element.style.whiteSpace = f.whiteSpace;
|
||||
f.element.style.display = f.display;
|
||||
f.element.style.fontSize = f.currentFontSize + 'px';
|
||||
};
|
||||
|
||||
// dispatch a fit event on a fitty
|
||||
const dispatchFitEvent = (f) => {
|
||||
f.element.dispatchEvent(
|
||||
new CustomEvent('fit', {
|
||||
detail: {
|
||||
oldValue: f.previousFontSize,
|
||||
newValue: f.currentFontSize,
|
||||
scaleFactor: f.currentFontSize / f.previousFontSize,
|
||||
},
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
// fit method, marks the fitty as dirty and requests a redraw (this will also redraw any other fitty marked as dirty)
|
||||
const fit = (f, type) => (options) => {
|
||||
f.dirty = type;
|
||||
if (!f.active) { return; }
|
||||
requestRedraw(options);
|
||||
};
|
||||
|
||||
const init = (f) => {
|
||||
// save some of the original CSS properties before we change them
|
||||
f.originalStyle = {
|
||||
whiteSpace: f.element.style.whiteSpace,
|
||||
display: f.element.style.display,
|
||||
fontSize: f.element.style.fontSize,
|
||||
};
|
||||
|
||||
// should we observe DOM mutations
|
||||
observeMutations(f);
|
||||
|
||||
// this is a new fitty so we need to validate if it's styles are in order
|
||||
f.newbie = true;
|
||||
|
||||
// because it's a new fitty it should also be dirty, we want it to redraw on the first loop
|
||||
f.dirty = true;
|
||||
|
||||
// we want to be able to update this fitty
|
||||
fitties.push(f);
|
||||
};
|
||||
|
||||
const destroy = (f) => () => {
|
||||
// remove from fitties array
|
||||
fitties = fitties.filter((_) => _.element !== f.element);
|
||||
|
||||
// stop observing DOM
|
||||
if (f.observeMutations) { f.observer.disconnect(); }
|
||||
|
||||
// reset the CSS properties we changes
|
||||
f.element.style.whiteSpace = f.originalStyle.whiteSpace;
|
||||
f.element.style.display = f.originalStyle.display;
|
||||
f.element.style.fontSize = f.originalStyle.fontSize;
|
||||
};
|
||||
|
||||
// add a new fitty, does not redraw said fitty
|
||||
const subscribe = (f) => () => {
|
||||
if (f.active) { return; }
|
||||
f.active = true;
|
||||
requestRedraw();
|
||||
};
|
||||
|
||||
// remove an existing fitty
|
||||
const unsubscribe = (f) => () => (f.active = false);
|
||||
|
||||
const observeMutations = (f) => {
|
||||
// no observing?
|
||||
if (!f.observeMutations) { return; }
|
||||
|
||||
// start observing mutations
|
||||
f.observer = new MutationObserver(fit(f, DrawState.DIRTY_CONTENT));
|
||||
|
||||
// start observing
|
||||
f.observer.observe(f.element, f.observeMutations);
|
||||
};
|
||||
|
||||
// default mutation observer settings
|
||||
const mutationObserverDefaultSetting = {
|
||||
subtree: true,
|
||||
childList: true,
|
||||
characterData: true,
|
||||
};
|
||||
|
||||
// default fitty options
|
||||
const defaultOptions = {
|
||||
minSize: 16,
|
||||
maxSize: 512,
|
||||
multiLine: true,
|
||||
vertical: false,
|
||||
observeMutations: 'MutationObserver' in w ? mutationObserverDefaultSetting : false,
|
||||
};
|
||||
|
||||
/**
|
||||
* array of elements in, fitty instances out
|
||||
* @param {Array} elements
|
||||
* @param {object} options
|
||||
*/
|
||||
function fittyCreate(elements, options) {
|
||||
// set options object
|
||||
const fittyOptions = Object.assign(
|
||||
{},
|
||||
|
||||
// expand default options
|
||||
defaultOptions,
|
||||
|
||||
// override with custom options
|
||||
options
|
||||
);
|
||||
|
||||
// create fitties
|
||||
const publicFitties = elements.map((element) => {
|
||||
// create fitty instance
|
||||
const f = Object.assign({}, fittyOptions, {
|
||||
// internal options for this fitty
|
||||
element,
|
||||
active: true,
|
||||
});
|
||||
|
||||
// initialise this fitty
|
||||
init(f);
|
||||
|
||||
// expose API
|
||||
return {
|
||||
element,
|
||||
fit: fit(f, DrawState.DIRTY),
|
||||
unfreeze: subscribe(f),
|
||||
freeze: unsubscribe(f),
|
||||
unsubscribe: destroy(f),
|
||||
};
|
||||
});
|
||||
|
||||
// call redraw on newly initiated fitties
|
||||
requestRedraw();
|
||||
|
||||
// expose fitties
|
||||
return publicFitties;
|
||||
}
|
||||
|
||||
/**
|
||||
* fitty creation function
|
||||
* @param {*} target
|
||||
* @param {*} options
|
||||
* @returns
|
||||
*/
|
||||
function fitty(target, options = {}) {
|
||||
// if target is a string
|
||||
return typeof target === 'string'
|
||||
? // treat it as a querySelector
|
||||
fittyCreate(toArray(document.querySelectorAll(target)), options)
|
||||
: // create single fitty
|
||||
fittyCreate([target], options)[0];
|
||||
}
|
||||
|
||||
// handles viewport changes, redraws all fitties, but only does so after a timeout
|
||||
let resizeDebounce = null;
|
||||
const onWindowResized = () => {
|
||||
w.clearTimeout(resizeDebounce);
|
||||
resizeDebounce = w.setTimeout(redrawAll(DrawState.DIRTY_LAYOUT), fitty.observeWindowDelay);
|
||||
};
|
||||
|
||||
// define observe window property, so when we set it to true or false events are automatically added and removed
|
||||
const events = ['resize', 'orientationchange'];
|
||||
Object.defineProperty(fitty, 'observeWindow', {
|
||||
set: (enabled) => {
|
||||
const method = `${enabled ? 'add' : 'remove'}EventListener`;
|
||||
events.forEach((e) => {
|
||||
w[method](e, onWindowResized);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
// fitty global properties (by setting observeWindow to true the events above get added)
|
||||
fitty.observeWindow = true;
|
||||
fitty.observeWindowDelay = 100;
|
||||
|
||||
// public fit all method, will force redraw no matter what
|
||||
fitty.fitAll = redrawAll(DrawState.DIRTY);
|
||||
|
||||
// export our fitty function, we don't want to keep it to our selves
|
||||
return fitty;
|
||||
})(typeof window === 'undefined' ? null : window);
|
251
amd/src/util/textfit.js
Normal file
251
amd/src/util/textfit.js
Normal file
|
@ -0,0 +1,251 @@
|
|||
/**
|
||||
* textFit v2.3.1
|
||||
* Previously known as jQuery.textFit
|
||||
* 11/2014 by STRML (strml.github.com)
|
||||
* MIT License
|
||||
*
|
||||
* To use: textFit(document.getElementById('target-div'), options);
|
||||
*
|
||||
* Will make the *text* content inside a container scale to fit the container
|
||||
* The container is required to have a set width and height
|
||||
* Uses binary search to fit text with minimal layout calls.
|
||||
* Version 2.0 does not use jQuery.
|
||||
*/
|
||||
var defaultSettings = {
|
||||
alignVert: false, // if true, textFit will align vertically using css tables
|
||||
alignHoriz: false, // if true, textFit will set text-align: center
|
||||
multiLine: false, // if true, textFit will not set white-space: no-wrap
|
||||
detectMultiLine: true, // disable to turn off automatic multi-line sensing
|
||||
minFontSize: 6,
|
||||
maxFontSize: 80,
|
||||
reProcess: true, // if true, textFit will re-process already-fit nodes. Set to 'false' for better performance
|
||||
widthOnly: false, // if true, textFit will fit text to element width, regardless of text height
|
||||
alignVertWithFlexbox: false, // if true, textFit will use flexbox for vertical alignment
|
||||
};
|
||||
|
||||
/**
|
||||
* Create new textFit element(S)
|
||||
* @param {*} els element or element list
|
||||
* @param {*} options Options (See default settings in textfit.js)
|
||||
*/
|
||||
export function textFit(els, options) {
|
||||
|
||||
if (!options) { options = {}; }
|
||||
|
||||
// Extend options.
|
||||
var settings = {};
|
||||
for(var key in defaultSettings){
|
||||
if(options.hasOwnProperty(key)){
|
||||
settings[key] = options[key];
|
||||
} else {
|
||||
settings[key] = defaultSettings[key];
|
||||
}
|
||||
}
|
||||
|
||||
// Convert jQuery objects into arrays
|
||||
if (typeof els.toArray === "function") {
|
||||
els = els.toArray();
|
||||
}
|
||||
|
||||
// Support passing a single el
|
||||
var elType = Object.prototype.toString.call(els);
|
||||
if (elType !== '[object Array]' && elType !== '[object NodeList]' &&
|
||||
elType !== '[object HTMLCollection]'){
|
||||
els = [els];
|
||||
}
|
||||
|
||||
// Process each el we've passed.
|
||||
for(var i = 0; i < els.length; i++){
|
||||
processItem(els[i], settings);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The meat. Given an el, make the text inside it fit its parent.
|
||||
* @param {DOMElement} el Child el.
|
||||
* @param {Object} settings Options for fit.
|
||||
*/
|
||||
function processItem(el, settings){
|
||||
if (!isElement(el) || (!settings.reProcess && el.getAttribute('textFitted'))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set textFitted attribute so we know this was processed.
|
||||
if(!settings.reProcess){
|
||||
el.setAttribute('textFitted', 1);
|
||||
}
|
||||
|
||||
var innerSpan, originalHeight, originalHTML, originalWidth;
|
||||
var low, mid, high;
|
||||
|
||||
// Get element data.
|
||||
originalHTML = el.innerHTML;
|
||||
originalWidth = innerWidth(el);
|
||||
originalHeight = innerHeight(el);
|
||||
|
||||
// Don't process if we can't find box dimensions
|
||||
if (!originalWidth || (!settings.widthOnly && !originalHeight)) {
|
||||
if(!settings.widthOnly) {
|
||||
throw new Error('Set a static height and width on the target element ' + el.outerHTML +
|
||||
' before using textFit!');
|
||||
} else {
|
||||
throw new Error('Set a static width on the target element ' + el.outerHTML +
|
||||
' before using textFit!');
|
||||
}
|
||||
}
|
||||
|
||||
// Add textFitted span inside this container.
|
||||
if (originalHTML.indexOf('textFitted') === -1) {
|
||||
innerSpan = document.createElement('span');
|
||||
innerSpan.className = 'textFitted';
|
||||
// Inline block ensure it takes on the size of its contents, even if they are enclosed
|
||||
// in other tags like <p>
|
||||
innerSpan.style['display'] = 'inline-block';
|
||||
innerSpan.innerHTML = originalHTML;
|
||||
el.innerHTML = '';
|
||||
el.appendChild(innerSpan);
|
||||
} else {
|
||||
// Reprocessing.
|
||||
innerSpan = el.querySelector('span.textFitted');
|
||||
// Remove vertical align if we're reprocessing.
|
||||
if (hasClass(innerSpan, 'textFitAlignVert')){
|
||||
innerSpan.className = innerSpan.className.replace('textFitAlignVert', '');
|
||||
innerSpan.style['height'] = '';
|
||||
el.className.replace('textFitAlignVertFlex', '');
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare & set alignment
|
||||
if (settings.alignHoriz) {
|
||||
el.style['text-align'] = 'center';
|
||||
innerSpan.style['text-align'] = 'center';
|
||||
}
|
||||
|
||||
// Check if this string is multiple lines
|
||||
// Not guaranteed to always work if you use wonky line-heights
|
||||
var multiLine = settings.multiLine;
|
||||
if (settings.detectMultiLine && !multiLine &&
|
||||
innerSpan.getBoundingClientRect().height >= parseInt(window.getComputedStyle(innerSpan)['font-size'], 10) * 2){
|
||||
multiLine = true;
|
||||
}
|
||||
|
||||
// If we're not treating this as a multiline string, don't let it wrap.
|
||||
if (!multiLine) {
|
||||
el.style['white-space'] = 'nowrap';
|
||||
}
|
||||
|
||||
low = settings.minFontSize;
|
||||
high = settings.maxFontSize;
|
||||
|
||||
// Binary search for highest best fit
|
||||
var size = low;
|
||||
while (low <= high) {
|
||||
mid = (high + low) / 2;
|
||||
innerSpan.style.fontSize = mid + 'px';
|
||||
var innerSpanBoundingClientRect = innerSpan.getBoundingClientRect();
|
||||
if (
|
||||
innerSpanBoundingClientRect.width <= originalWidth
|
||||
&& (settings.widthOnly || innerSpanBoundingClientRect.height <= originalHeight)
|
||||
) {
|
||||
size = mid;
|
||||
low = mid + 1;
|
||||
} else {
|
||||
high = mid - 1;
|
||||
}
|
||||
// await injection point
|
||||
}
|
||||
// found, updating font if differs:
|
||||
if( innerSpan.style.fontSize != size + 'px' ) { innerSpan.style.fontSize = size + 'px'; }
|
||||
|
||||
// Our height is finalized. If we are aligning vertically, set that up.
|
||||
if (settings.alignVert) {
|
||||
addStyleSheet();
|
||||
var height = innerSpan.scrollHeight;
|
||||
if (window.getComputedStyle(el)['position'] === "static"){
|
||||
el.style['position'] = 'relative';
|
||||
}
|
||||
if (!hasClass(innerSpan, "textFitAlignVert")){
|
||||
innerSpan.className = innerSpan.className + " textFitAlignVert";
|
||||
}
|
||||
innerSpan.style['height'] = height + "px";
|
||||
if (settings.alignVertWithFlexbox && !hasClass(el, "textFitAlignVertFlex")) {
|
||||
el.className = el.className + " textFitAlignVertFlex";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate height without padding.
|
||||
* @param {*} el
|
||||
* @returns
|
||||
*/
|
||||
function innerHeight(el){
|
||||
var style = window.getComputedStyle(el, null);
|
||||
return el.getBoundingClientRect().height -
|
||||
parseInt(style.getPropertyValue('padding-top'), 10) -
|
||||
parseInt(style.getPropertyValue('padding-bottom'), 10);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate width without padding.
|
||||
* @param {*} el
|
||||
* @returns
|
||||
*/
|
||||
function innerWidth(el){
|
||||
var style = window.getComputedStyle(el, null);
|
||||
return el.getBoundingClientRect().width -
|
||||
parseInt(style.getPropertyValue('padding-left'), 10) -
|
||||
parseInt(style.getPropertyValue('padding-right'), 10);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if it is a DOM element
|
||||
* @param {*} o
|
||||
* @returns
|
||||
*/
|
||||
function isElement(o){
|
||||
return (
|
||||
typeof HTMLElement === "object" ? o instanceof HTMLElement : //DOM2
|
||||
o && typeof o === "object" && o !== null && o.nodeType === 1 && typeof o.nodeName==="string"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if element has a specific class
|
||||
* @param {*} element
|
||||
* @param {*} cls
|
||||
* @returns
|
||||
*/
|
||||
function hasClass(element, cls) {
|
||||
return (' ' + element.className + ' ').indexOf(' ' + cls + ' ') > -1;
|
||||
}
|
||||
|
||||
// Better than a stylesheet dependency
|
||||
/**
|
||||
* Add stylesheet to the page for this
|
||||
* @returns
|
||||
*/
|
||||
function addStyleSheet() {
|
||||
if (document.getElementById("textFitStyleSheet")) { return; }
|
||||
var style = [
|
||||
".textFitAlignVert{",
|
||||
"position: absolute;",
|
||||
"top: 0; right: 0; bottom: 0; left: 0;",
|
||||
"margin: auto;",
|
||||
"display: flex;",
|
||||
"justify-content: center;",
|
||||
"flex-direction: column;",
|
||||
"}",
|
||||
".textFitAlignVertFlex{",
|
||||
"display: flex;",
|
||||
"}",
|
||||
".textFitAlignVertFlex .textFitAlignVert{",
|
||||
"position: static;",
|
||||
"}",].join("");
|
||||
|
||||
var css = document.createElement("style");
|
||||
css.type = "text/css";
|
||||
css.id = "textFitStyleSheet";
|
||||
css.innerHTML = style;
|
||||
document.body.appendChild(css);
|
||||
}
|
|
@ -276,7 +276,7 @@ class corecompletioninfo {
|
|||
See moodle/completion/criteria/completion_criteria_*.php::get_details() for the code that
|
||||
the code below is based on.
|
||||
*/
|
||||
|
||||
unset($title); // Clear title from previous iteration if it was set.
|
||||
if ($type == COMPLETION_CRITERIA_TYPE_SELF) {
|
||||
$details = [
|
||||
"type" => $criteria->get_title(),
|
||||
|
@ -314,6 +314,8 @@ class corecompletioninfo {
|
|||
} else {
|
||||
$details['criteria'] = $cm->get_formatted_name();
|
||||
}
|
||||
// Set title based on cm formatted name
|
||||
$title = $cm->get_formatted_name();
|
||||
// Build requirements.
|
||||
$details['requirement'] = array();
|
||||
|
||||
|
@ -344,14 +346,21 @@ class corecompletioninfo {
|
|||
"status" => "",
|
||||
];
|
||||
} else if ($type == COMPLETION_CRITERIA_TYPE_GRADE) {
|
||||
$displaytype = \grade_get_setting($this->course->id, 'displaytype', $CFG->grade_displaytype);
|
||||
$gradepass = $criteria->gradepass;
|
||||
// Find grade item for course result.
|
||||
$gi = new \grade_item(['courseid' => $this->course->id,'itemtype' => 'course']);
|
||||
$displaygrade = \grade_format_gradevalue($gradepass,$gi,true,$displaytype,1);
|
||||
$details = [
|
||||
"type" => get_string('coursegrade', 'completion'),
|
||||
"criteria" => get_string('graderequired', 'completion'),
|
||||
// TODO: convert to selected representation (letter, percentage, etc).
|
||||
"requirement" => get_string('graderequired', 'completion')
|
||||
.": ".format_float($criteria->gradepass, 1),
|
||||
.": ".$displaygrade,
|
||||
"status" => "",
|
||||
];
|
||||
$title = get_string('graderequired','completion').': '.$displaygrade;
|
||||
|
||||
} else if ($type == COMPLETION_CRITERIA_TYPE_ROLE) {
|
||||
$details = [
|
||||
"type" => get_string('manualcompletionby', 'completion'),
|
||||
|
@ -385,7 +394,7 @@ class corecompletioninfo {
|
|||
// Only add the items list if we actually have items...
|
||||
$cinfo["items"][] = [
|
||||
"id" => $criteria->id,
|
||||
"title" => $criteria->get_title_detailed(),
|
||||
"title" => isset($title)?$title:$criteria->get_title_detailed(),
|
||||
"details" => $details,
|
||||
"progress" => $scanner->model($studentlist),
|
||||
];
|
||||
|
@ -530,14 +539,14 @@ class corecompletioninfo {
|
|||
|
||||
} else if ($type == COMPLETION_CRITERIA_TYPE_GRADE) {
|
||||
// Make sure we provide the current course grade.
|
||||
$iinfo['grade'] = floatval($iinfo['details']['status']);
|
||||
if ($iinfo["grade"] > 0) {
|
||||
$iinfo["grade"] = format_float($iinfo["grade"], 1). "/".
|
||||
format_float(floatval($iinfo['details']['requirement']));
|
||||
$iinfo["status"] = $completion->is_complete() ? "complete-pass" : "complete-fail";
|
||||
if ($cinfo["status"] == "incomplete") {
|
||||
$cinfo["status"] = "progress";
|
||||
}
|
||||
$rawgrade = floatval($iinfo['details']['status']);
|
||||
$iinfo['grade'] = $this->format_course_grade($rawgrade);
|
||||
$rq = floatval($iinfo['details']['requirement']);
|
||||
$iinfo['details']['requirement'] = $this->format_course_grade($rq);
|
||||
;
|
||||
$iinfo["status"] = $completion->is_complete() ? "complete-pass" : "complete-fail";
|
||||
if ($cinfo["status"] == "incomplete") {
|
||||
$cinfo["status"] = "progress";
|
||||
}
|
||||
|
||||
if ($completion->is_complete()) {
|
||||
|
@ -590,22 +599,12 @@ class corecompletioninfo {
|
|||
if ($gi) {
|
||||
// Only the following types of grade yield a result.
|
||||
if (($gi->gradetype == GRADE_TYPE_VALUE || $gi->gradetype == GRADE_TYPE_SCALE)) {
|
||||
$scale = $gi->load_scale();
|
||||
|
||||
$grade = (object)$gi->get_final($userid); // Get the grade for the specified user.
|
||||
$result = new \stdClass;
|
||||
// Check if the final grade is available and numeric (safety check).
|
||||
if (!empty($grade) && !empty($grade->finalgrade) && is_numeric($grade->finalgrade)) {
|
||||
// Convert scale grades to corresponding scale name.
|
||||
if (isset($scale)) {
|
||||
// Get scale value.
|
||||
$result->grade = $scale->get_nearest_item($grade->finalgrade);
|
||||
} else {
|
||||
// Round final grade to 1 decimal point.
|
||||
$result->grade = round($grade->finalgrade, 1);
|
||||
}
|
||||
|
||||
$result->feedback = trim($grade->feedback);
|
||||
$result->grade = \grade_format_gradevalue($grade->finalgrade,$gi,true,null,1);
|
||||
$result->feedback = \trim($grade->feedback);
|
||||
$result->pending = (new gradingscanner($gi))->pending($userid);
|
||||
} else {
|
||||
$result->grade = "-"; // Activity is gradable, but user did not receive a grade yet.
|
||||
|
@ -624,34 +623,16 @@ class corecompletioninfo {
|
|||
* @param int $userid ID of user to retrieve grade for
|
||||
* @return stdClass|null object containing 'grade' and optional 'feedback' attribute
|
||||
*/
|
||||
private function get_course_grade($userid) {
|
||||
private function format_course_grade($grade) {
|
||||
// TODO: Display grade in the way described in the course setup (with letters if needed).
|
||||
$gi = grade_item::fetch(['itemtype' => 'course',
|
||||
'iteminstance' => $this->course->id,
|
||||
'courseid' => $this->course->id]);
|
||||
$gi = new \grade_item(['itemtype' => 'course',
|
||||
'courseid' => $this->course->id]);
|
||||
|
||||
if ($gi) {
|
||||
// Only the following types of grade yield a result.
|
||||
if (($gi->gradetype == GRADE_TYPE_VALUE || $gi->gradetype == GRADE_TYPE_SCALE)) {
|
||||
$scale = $gi->load_scale();
|
||||
$grade = $gi->get_final($userid); // Get the grade for the specified user.
|
||||
// Check if the final grade is available and numeric (safety check).
|
||||
if (!empty($grade) && !empty($grade->finalgrade) && is_numeric($grade->finalgrade)) {
|
||||
// Convert scale grades to corresponding scale name.
|
||||
if (isset($scale)) {
|
||||
// Get scale value.
|
||||
return $scale->get_nearest_item($grade->finalgrade);
|
||||
} else {
|
||||
// Round final grade to 1 decimal point.
|
||||
return round($grade->finalgrade, 1);
|
||||
}
|
||||
} else {
|
||||
return "-"; // User did not receive a grade yet for this course.
|
||||
}
|
||||
}
|
||||
return \grade_format_gradevalue($grade,$gi,true,null,1);
|
||||
}
|
||||
|
||||
return null; // Course cannot be graded (Shouldn't be happening, but still....).
|
||||
return "x"; // Course cannot be graded (Shouldn't be happening, but still....).
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -338,18 +338,8 @@ class gradeinfo {
|
|||
public function user_model($userid) {
|
||||
global $DB;
|
||||
$grade = $this->gradeitem->get_final($userid);
|
||||
// Convert scale grades to corresponding scale name.
|
||||
if (!empty($grade)) {
|
||||
if (!is_numeric($grade->finalgrade) && empty($grade->finalgrade)) {
|
||||
$finalgrade = "-";
|
||||
} else if (isset($this->scale)) {
|
||||
$finalgrade = $this->scale->get_nearest_item($grade->finalgrade);
|
||||
} else {
|
||||
$finalgrade = round($grade->finalgrade, 1);
|
||||
}
|
||||
} else {
|
||||
$finalgrade = "-";
|
||||
}
|
||||
// Format grade for proper display
|
||||
$finalgrade = \grade_format_gradevalue($grade->finalgrade,$this->gradeitem,true,null,1);
|
||||
|
||||
// Retrieve the aggregator and determine completion.
|
||||
if (!isset($this->studyitem)) {
|
||||
|
|
|
@ -121,6 +121,7 @@ class studyplanservice extends \external_api {
|
|||
$studyplan = studyplan::find_by_id($id);
|
||||
webservicehelper::require_capabilities([self::CAP_EDIT, self::CAP_VIEW], $studyplan->context());
|
||||
$model = $studyplan->editor_model();
|
||||
debug::dump($model);
|
||||
return $model;
|
||||
} else {
|
||||
return null;
|
||||
|
|
|
@ -1577,68 +1577,70 @@ body.path-local-treestudyplan .editmode-switch-form > * {
|
|||
|
||||
.path-local-treestudyplan {
|
||||
font: inherit;
|
||||
--border-color: var(--primary);
|
||||
--conditions-bgcolor: #e7e7e7;
|
||||
--courseresult-bgcolor: white;
|
||||
--studentinfo-bgcolor: white;
|
||||
}
|
||||
.path-local-treestudyplan table.studyplanreport {
|
||||
.path-local-treestudyplan table.q-studyplanreport {
|
||||
table-layout: fixed;
|
||||
width: calc(12rem + var(--resultColCount) * 4rem);
|
||||
}
|
||||
.path-local-treestudyplan .q-header,
|
||||
.path-local-treestudyplan .q-student-results {
|
||||
background-color: white;
|
||||
background-color: var(--courseresult-bgcolor);
|
||||
}
|
||||
.path-local-treestudyplan .q-header .q-period-heading,
|
||||
.path-local-treestudyplan .q-header .q-line-heading,
|
||||
.path-local-treestudyplan .q-header .q-item-heading,
|
||||
.path-local-treestudyplan .q-header .q-condition-heading,
|
||||
.path-local-treestudyplan .q-header .q-period-results,
|
||||
.path-local-treestudyplan .q-header .q-line-results,
|
||||
.path-local-treestudyplan .q-header .q-item-results,
|
||||
.path-local-treestudyplan .q-header .q-condition-results,
|
||||
.path-local-treestudyplan .q-student-results .q-period-heading,
|
||||
.path-local-treestudyplan .q-student-results .q-line-heading,
|
||||
.path-local-treestudyplan .q-student-results .q-item-heading,
|
||||
.path-local-treestudyplan .q-student-results .q-condition-heading,
|
||||
.path-local-treestudyplan .q-student-results .q-period-results,
|
||||
.path-local-treestudyplan .q-student-results .q-line-results,
|
||||
.path-local-treestudyplan .q-student-results .q-item-results,
|
||||
.path-local-treestudyplan .q-student-results .q-condition-results {
|
||||
border-right: 1px solid gray;
|
||||
}
|
||||
.path-local-treestudyplan .q-header .q-period-heading .q-header-title,
|
||||
.path-local-treestudyplan .q-header .q-line-heading .q-header-title,
|
||||
.path-local-treestudyplan .q-header .q-item-heading .q-header-title,
|
||||
.path-local-treestudyplan .q-header .q-condition-heading .q-header-title,
|
||||
.path-local-treestudyplan .q-header .q-period-results .q-header-title,
|
||||
.path-local-treestudyplan .q-header .q-line-results .q-header-title,
|
||||
.path-local-treestudyplan .q-header .q-item-results .q-header-title,
|
||||
.path-local-treestudyplan .q-header .q-condition-results .q-header-title,
|
||||
.path-local-treestudyplan .q-student-results .q-period-heading .q-header-title,
|
||||
.path-local-treestudyplan .q-student-results .q-line-heading .q-header-title,
|
||||
.path-local-treestudyplan .q-student-results .q-item-heading .q-header-title,
|
||||
.path-local-treestudyplan .q-student-results .q-condition-heading .q-header-title,
|
||||
.path-local-treestudyplan .q-student-results .q-period-results .q-header-title,
|
||||
.path-local-treestudyplan .q-student-results .q-line-results .q-header-title,
|
||||
.path-local-treestudyplan .q-student-results .q-item-results .q-header-title,
|
||||
.path-local-treestudyplan .q-student-results .q-condition-results .q-header-title {
|
||||
.path-local-treestudyplan .q-student-results .q-condition-heading {
|
||||
border-right: 1px solid var(--border-color);
|
||||
border-top: 1px solid var(--border-color);
|
||||
padding: 0.5rem;
|
||||
}
|
||||
.path-local-treestudyplan .q-header .q-period-heading,
|
||||
.path-local-treestudyplan .q-header .q-line-heading,
|
||||
.path-local-treestudyplan .q-header .q-item-heading,
|
||||
.path-local-treestudyplan .q-header .q-condition-heading.overall,
|
||||
.path-local-treestudyplan .q-header .q-result.overall,
|
||||
.path-local-treestudyplan .q-student-results .q-period-heading,
|
||||
.path-local-treestudyplan .q-student-results .q-line-heading,
|
||||
.path-local-treestudyplan .q-student-results .q-item-heading,
|
||||
.path-local-treestudyplan .q-student-results .q-condition-heading.overall,
|
||||
.path-local-treestudyplan .q-student-results .q-result.overall {
|
||||
background-color: var(--courseresult-bgcolor);
|
||||
}
|
||||
.path-local-treestudyplan .q-header .q-period-heading.collapsed,
|
||||
.path-local-treestudyplan .q-student-results .q-period-heading.collapsed {
|
||||
width: 12rem;
|
||||
}
|
||||
.path-local-treestudyplan .q-header .q-result,
|
||||
.path-local-treestudyplan .q-student-results .q-result {
|
||||
height: 2rem;
|
||||
padding-top: 0.25rem;
|
||||
}
|
||||
.path-local-treestudyplan .q-header,
|
||||
.path-local-treestudyplan .q-student-results {
|
||||
/*.q-line-heading > .q-header-title,*/
|
||||
}
|
||||
.path-local-treestudyplan .q-header .q-item-heading.collapsed,
|
||||
.path-local-treestudyplan .q-header .q-line-heading,
|
||||
.path-local-treestudyplan .q-header .q-item-heading,
|
||||
.path-local-treestudyplan .q-header .q-condition-heading,
|
||||
.path-local-treestudyplan .q-student-results .q-item-heading.collapsed,
|
||||
.path-local-treestudyplan .q-student-results .q-line-heading,
|
||||
.path-local-treestudyplan .q-student-results .q-item-heading,
|
||||
.path-local-treestudyplan .q-student-results .q-condition-heading {
|
||||
width: 2rem;
|
||||
writing-mode: vertical-lr;
|
||||
writing-mode: vertical-rl;
|
||||
text-orientation: sideways;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.path-local-treestudyplan .q-header .q-line-heading .q-chevron,
|
||||
.path-local-treestudyplan .q-header .q-item-heading .q-chevron,
|
||||
.path-local-treestudyplan .q-header .q-condition-heading .q-chevron,
|
||||
.path-local-treestudyplan .q-student-results .q-line-heading .q-chevron,
|
||||
.path-local-treestudyplan .q-student-results .q-item-heading .q-chevron,
|
||||
.path-local-treestudyplan .q-student-results .q-condition-heading .q-chevron {
|
||||
text-orientation: initial;
|
||||
writing-mode: horizontal-tb;
|
||||
}
|
||||
.path-local-treestudyplan .q-header .q-period-heading,
|
||||
.path-local-treestudyplan .q-header .q-line-heading,
|
||||
|
@ -1650,41 +1652,56 @@ body.path-local-treestudyplan .editmode-switch-form > * {
|
|||
.path-local-treestudyplan .q-student-results .q-condition-heading {
|
||||
vertical-align: top;
|
||||
}
|
||||
.path-local-treestudyplan .q-header .q-line-heading,
|
||||
.path-local-treestudyplan .q-student-results .q-line-heading {
|
||||
height: fit-content;
|
||||
.path-local-treestudyplan .q-header .q-line-heading > span.q-wrap,
|
||||
.path-local-treestudyplan .q-student-results .q-line-heading > span.q-wrap {
|
||||
display: inline-block;
|
||||
height: 7rem;
|
||||
}
|
||||
.path-local-treestudyplan .q-header .q-item-heading,
|
||||
.path-local-treestudyplan .q-student-results .q-item-heading {
|
||||
height: 6rem;
|
||||
.path-local-treestudyplan .q-header .q-item-heading > span.q-wrap,
|
||||
.path-local-treestudyplan .q-student-results .q-item-heading > span.q-wrap {
|
||||
display: inline-block;
|
||||
height: 7rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.path-local-treestudyplan .q-header .q-condition-heading,
|
||||
.path-local-treestudyplan .q-student-results .q-condition-heading {
|
||||
text-align: center;
|
||||
text-align: left;
|
||||
background: var(--conditions-bgcolor);
|
||||
}
|
||||
.path-local-treestudyplan .q-header .q-condition-heading span,
|
||||
.path-local-treestudyplan .q-student-results .q-condition-heading span {
|
||||
height: 8rem;
|
||||
white-space: nowrap;
|
||||
.path-local-treestudyplan .q-header .q-condition-heading > span.q-wrap,
|
||||
.path-local-treestudyplan .q-student-results .q-condition-heading > span.q-wrap {
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
height: 8rem;
|
||||
}
|
||||
.path-local-treestudyplan .q-result {
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
border-right: 1px solid gray;
|
||||
border-right: 1px solid var(--border-color);
|
||||
width: 4rem;
|
||||
padding-left: 0.25rem;
|
||||
padding-right: 0.25rem;
|
||||
background-color: var(--conditions-bgcolor);
|
||||
}
|
||||
.path-local-treestudyplan .q-result.overall,
|
||||
.path-local-treestudyplan .q-result.collapsed {
|
||||
background-color: var(--courseresult-bgcolor);
|
||||
}
|
||||
.path-local-treestudyplan .q-studentname {
|
||||
padding: 0.5em;
|
||||
border-right: 2px solid grey;
|
||||
width: 20rem;
|
||||
border-right: 2px solid var(--border-color);
|
||||
width: 12rem;
|
||||
background-color: var(--studentinfo-bgcolor);
|
||||
}
|
||||
.path-local-treestudyplan .q-courseresult i.fa,
|
||||
.path-local-treestudyplan .q-conditionresult i.fa {
|
||||
font-size: 21px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.path-local-treestudyplan .q-conditionresult {
|
||||
font-size: 1.2rem;
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.path-local-treestudyplan .b-modal-justify-footer-between .modal-footer,
|
||||
.features-treestudyplan .b-modal-justify-footer-between .modal-footer {
|
||||
|
|
|
@ -1,42 +1,49 @@
|
|||
.path-local-treestudyplan {
|
||||
font: inherit;
|
||||
--border-color: var(--primary);
|
||||
--conditions-bgcolor: #e7e7e7;
|
||||
--courseresult-bgcolor: white;
|
||||
--studentinfo-bgcolor: white;
|
||||
|
||||
table.studyplanreport {
|
||||
table.q-studyplanreport {
|
||||
table-layout: fixed;
|
||||
width: calc(12rem + (var(--resultColCount) * 4rem));
|
||||
}
|
||||
|
||||
.q-header, .q-student-results {
|
||||
background-color: white;
|
||||
background-color: var(--courseresult-bgcolor);
|
||||
|
||||
.q-period-heading, .q-line-heading, .q-item-heading, .q-condition-heading,
|
||||
.q-period-results, .q-line-results, .q-item-results, .q-condition-results
|
||||
.q-period-heading, .q-line-heading, .q-item-heading, .q-condition-heading
|
||||
{
|
||||
border-right: 1px solid var(--border-color);
|
||||
border-top: 1px solid var(--border-color);
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
border-right: 1px solid gray;
|
||||
|
||||
.q-header-title {
|
||||
padding: 0.5rem;
|
||||
|
||||
}
|
||||
.q-period-heading, .q-line-heading, .q-item-heading,
|
||||
.q-condition-heading.overall, .q-result.overall {
|
||||
background-color: var(--courseresult-bgcolor);
|
||||
}
|
||||
|
||||
.q-period-heading.collapsed {
|
||||
width:12rem;
|
||||
}
|
||||
|
||||
.q-result {
|
||||
height: 2rem;
|
||||
padding-top: 0.25rem;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.q-header, .q-student-results {
|
||||
/*.q-line-heading > .q-header-title,*/
|
||||
.q-item-heading.collapsed,
|
||||
|
||||
.q-line-heading,
|
||||
.q-item-heading,
|
||||
.q-condition-heading {
|
||||
width: 2rem;
|
||||
writing-mode: vertical-lr;
|
||||
writing-mode: vertical-rl;
|
||||
text-orientation: sideways;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
.q-chevron {
|
||||
text-orientation: initial;
|
||||
writing-mode: horizontal-tb;
|
||||
}
|
||||
}
|
||||
|
||||
.q-period-heading,
|
||||
|
@ -46,22 +53,22 @@
|
|||
vertical-align: top;
|
||||
}
|
||||
|
||||
.q-line-heading {
|
||||
height: fit-content;
|
||||
.q-line-heading > span.q-wrap{
|
||||
display:inline-block;
|
||||
height: 7rem;
|
||||
}
|
||||
.q-item-heading {
|
||||
height: 6rem;
|
||||
.q-item-heading > span.q-wrap{
|
||||
display:inline-block;
|
||||
height: 7rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.q-condition-heading {
|
||||
text-align: center;
|
||||
span {
|
||||
> span.q-wrap {
|
||||
display:inline-block;
|
||||
height: 8rem;
|
||||
white-space: nowrap;
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
text-align: left;
|
||||
background: var(--conditions-bgcolor);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -69,13 +76,21 @@
|
|||
.q-result {
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
border-right: 1px solid gray;
|
||||
border-right: 1px solid var(--border-color);
|
||||
width: 4rem;
|
||||
padding-left: 0.25rem;
|
||||
padding-right: 0.25rem;
|
||||
background-color: var(--conditions-bgcolor);
|
||||
&.overall, &.collapsed {
|
||||
background-color: var(--courseresult-bgcolor);
|
||||
}
|
||||
}
|
||||
|
||||
.q-studentname {
|
||||
padding: 0.5em;
|
||||
border-right: 2px solid grey;
|
||||
width: 20rem;
|
||||
border-right: 2px solid var(--border-color);
|
||||
width: 12rem;
|
||||
background-color: var(--studentinfo-bgcolor);
|
||||
}
|
||||
|
||||
.q-courseresult,
|
||||
|
@ -86,4 +101,11 @@
|
|||
}
|
||||
}
|
||||
|
||||
.q-conditionresult{
|
||||
|
||||
font-size: 1.2rem;
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
}
|
125
styles.css
125
styles.css
|
@ -1577,68 +1577,70 @@ body.path-local-treestudyplan .editmode-switch-form > * {
|
|||
|
||||
.path-local-treestudyplan {
|
||||
font: inherit;
|
||||
--border-color: var(--primary);
|
||||
--conditions-bgcolor: #e7e7e7;
|
||||
--courseresult-bgcolor: white;
|
||||
--studentinfo-bgcolor: white;
|
||||
}
|
||||
.path-local-treestudyplan table.studyplanreport {
|
||||
.path-local-treestudyplan table.q-studyplanreport {
|
||||
table-layout: fixed;
|
||||
width: calc(12rem + var(--resultColCount) * 4rem);
|
||||
}
|
||||
.path-local-treestudyplan .q-header,
|
||||
.path-local-treestudyplan .q-student-results {
|
||||
background-color: white;
|
||||
background-color: var(--courseresult-bgcolor);
|
||||
}
|
||||
.path-local-treestudyplan .q-header .q-period-heading,
|
||||
.path-local-treestudyplan .q-header .q-line-heading,
|
||||
.path-local-treestudyplan .q-header .q-item-heading,
|
||||
.path-local-treestudyplan .q-header .q-condition-heading,
|
||||
.path-local-treestudyplan .q-header .q-period-results,
|
||||
.path-local-treestudyplan .q-header .q-line-results,
|
||||
.path-local-treestudyplan .q-header .q-item-results,
|
||||
.path-local-treestudyplan .q-header .q-condition-results,
|
||||
.path-local-treestudyplan .q-student-results .q-period-heading,
|
||||
.path-local-treestudyplan .q-student-results .q-line-heading,
|
||||
.path-local-treestudyplan .q-student-results .q-item-heading,
|
||||
.path-local-treestudyplan .q-student-results .q-condition-heading,
|
||||
.path-local-treestudyplan .q-student-results .q-period-results,
|
||||
.path-local-treestudyplan .q-student-results .q-line-results,
|
||||
.path-local-treestudyplan .q-student-results .q-item-results,
|
||||
.path-local-treestudyplan .q-student-results .q-condition-results {
|
||||
border-right: 1px solid gray;
|
||||
}
|
||||
.path-local-treestudyplan .q-header .q-period-heading .q-header-title,
|
||||
.path-local-treestudyplan .q-header .q-line-heading .q-header-title,
|
||||
.path-local-treestudyplan .q-header .q-item-heading .q-header-title,
|
||||
.path-local-treestudyplan .q-header .q-condition-heading .q-header-title,
|
||||
.path-local-treestudyplan .q-header .q-period-results .q-header-title,
|
||||
.path-local-treestudyplan .q-header .q-line-results .q-header-title,
|
||||
.path-local-treestudyplan .q-header .q-item-results .q-header-title,
|
||||
.path-local-treestudyplan .q-header .q-condition-results .q-header-title,
|
||||
.path-local-treestudyplan .q-student-results .q-period-heading .q-header-title,
|
||||
.path-local-treestudyplan .q-student-results .q-line-heading .q-header-title,
|
||||
.path-local-treestudyplan .q-student-results .q-item-heading .q-header-title,
|
||||
.path-local-treestudyplan .q-student-results .q-condition-heading .q-header-title,
|
||||
.path-local-treestudyplan .q-student-results .q-period-results .q-header-title,
|
||||
.path-local-treestudyplan .q-student-results .q-line-results .q-header-title,
|
||||
.path-local-treestudyplan .q-student-results .q-item-results .q-header-title,
|
||||
.path-local-treestudyplan .q-student-results .q-condition-results .q-header-title {
|
||||
.path-local-treestudyplan .q-student-results .q-condition-heading {
|
||||
border-right: 1px solid var(--border-color);
|
||||
border-top: 1px solid var(--border-color);
|
||||
padding: 0.5rem;
|
||||
}
|
||||
.path-local-treestudyplan .q-header .q-period-heading,
|
||||
.path-local-treestudyplan .q-header .q-line-heading,
|
||||
.path-local-treestudyplan .q-header .q-item-heading,
|
||||
.path-local-treestudyplan .q-header .q-condition-heading.overall,
|
||||
.path-local-treestudyplan .q-header .q-result.overall,
|
||||
.path-local-treestudyplan .q-student-results .q-period-heading,
|
||||
.path-local-treestudyplan .q-student-results .q-line-heading,
|
||||
.path-local-treestudyplan .q-student-results .q-item-heading,
|
||||
.path-local-treestudyplan .q-student-results .q-condition-heading.overall,
|
||||
.path-local-treestudyplan .q-student-results .q-result.overall {
|
||||
background-color: var(--courseresult-bgcolor);
|
||||
}
|
||||
.path-local-treestudyplan .q-header .q-period-heading.collapsed,
|
||||
.path-local-treestudyplan .q-student-results .q-period-heading.collapsed {
|
||||
width: 12rem;
|
||||
}
|
||||
.path-local-treestudyplan .q-header .q-result,
|
||||
.path-local-treestudyplan .q-student-results .q-result {
|
||||
height: 2rem;
|
||||
padding-top: 0.25rem;
|
||||
}
|
||||
.path-local-treestudyplan .q-header,
|
||||
.path-local-treestudyplan .q-student-results {
|
||||
/*.q-line-heading > .q-header-title,*/
|
||||
}
|
||||
.path-local-treestudyplan .q-header .q-item-heading.collapsed,
|
||||
.path-local-treestudyplan .q-header .q-line-heading,
|
||||
.path-local-treestudyplan .q-header .q-item-heading,
|
||||
.path-local-treestudyplan .q-header .q-condition-heading,
|
||||
.path-local-treestudyplan .q-student-results .q-item-heading.collapsed,
|
||||
.path-local-treestudyplan .q-student-results .q-line-heading,
|
||||
.path-local-treestudyplan .q-student-results .q-item-heading,
|
||||
.path-local-treestudyplan .q-student-results .q-condition-heading {
|
||||
width: 2rem;
|
||||
writing-mode: vertical-lr;
|
||||
writing-mode: vertical-rl;
|
||||
text-orientation: sideways;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.path-local-treestudyplan .q-header .q-line-heading .q-chevron,
|
||||
.path-local-treestudyplan .q-header .q-item-heading .q-chevron,
|
||||
.path-local-treestudyplan .q-header .q-condition-heading .q-chevron,
|
||||
.path-local-treestudyplan .q-student-results .q-line-heading .q-chevron,
|
||||
.path-local-treestudyplan .q-student-results .q-item-heading .q-chevron,
|
||||
.path-local-treestudyplan .q-student-results .q-condition-heading .q-chevron {
|
||||
text-orientation: initial;
|
||||
writing-mode: horizontal-tb;
|
||||
}
|
||||
.path-local-treestudyplan .q-header .q-period-heading,
|
||||
.path-local-treestudyplan .q-header .q-line-heading,
|
||||
|
@ -1650,41 +1652,56 @@ body.path-local-treestudyplan .editmode-switch-form > * {
|
|||
.path-local-treestudyplan .q-student-results .q-condition-heading {
|
||||
vertical-align: top;
|
||||
}
|
||||
.path-local-treestudyplan .q-header .q-line-heading,
|
||||
.path-local-treestudyplan .q-student-results .q-line-heading {
|
||||
height: fit-content;
|
||||
.path-local-treestudyplan .q-header .q-line-heading > span.q-wrap,
|
||||
.path-local-treestudyplan .q-student-results .q-line-heading > span.q-wrap {
|
||||
display: inline-block;
|
||||
height: 7rem;
|
||||
}
|
||||
.path-local-treestudyplan .q-header .q-item-heading,
|
||||
.path-local-treestudyplan .q-student-results .q-item-heading {
|
||||
height: 6rem;
|
||||
.path-local-treestudyplan .q-header .q-item-heading > span.q-wrap,
|
||||
.path-local-treestudyplan .q-student-results .q-item-heading > span.q-wrap {
|
||||
display: inline-block;
|
||||
height: 7rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.path-local-treestudyplan .q-header .q-condition-heading,
|
||||
.path-local-treestudyplan .q-student-results .q-condition-heading {
|
||||
text-align: center;
|
||||
text-align: left;
|
||||
background: var(--conditions-bgcolor);
|
||||
}
|
||||
.path-local-treestudyplan .q-header .q-condition-heading span,
|
||||
.path-local-treestudyplan .q-student-results .q-condition-heading span {
|
||||
height: 8rem;
|
||||
white-space: nowrap;
|
||||
.path-local-treestudyplan .q-header .q-condition-heading > span.q-wrap,
|
||||
.path-local-treestudyplan .q-student-results .q-condition-heading > span.q-wrap {
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
height: 8rem;
|
||||
}
|
||||
.path-local-treestudyplan .q-result {
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
border-right: 1px solid gray;
|
||||
border-right: 1px solid var(--border-color);
|
||||
width: 4rem;
|
||||
padding-left: 0.25rem;
|
||||
padding-right: 0.25rem;
|
||||
background-color: var(--conditions-bgcolor);
|
||||
}
|
||||
.path-local-treestudyplan .q-result.overall,
|
||||
.path-local-treestudyplan .q-result.collapsed {
|
||||
background-color: var(--courseresult-bgcolor);
|
||||
}
|
||||
.path-local-treestudyplan .q-studentname {
|
||||
padding: 0.5em;
|
||||
border-right: 2px solid grey;
|
||||
width: 20rem;
|
||||
border-right: 2px solid var(--border-color);
|
||||
width: 12rem;
|
||||
background-color: var(--studentinfo-bgcolor);
|
||||
}
|
||||
.path-local-treestudyplan .q-courseresult i.fa,
|
||||
.path-local-treestudyplan .q-conditionresult i.fa {
|
||||
font-size: 21px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.path-local-treestudyplan .q-conditionresult {
|
||||
font-size: 1.2rem;
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.path-local-treestudyplan .b-modal-justify-footer-between .modal-footer,
|
||||
.features-treestudyplan .b-modal-justify-footer-between .modal-footer {
|
||||
|
|
Loading…
Reference in New Issue
Block a user