Best JavaScript code snippet using playwright-internal
TimeAxis.js
Source:TimeAxis.js
1/*2Ext Gantt Pro 4.2.73Copyright(c) 2009-2016 Bryntum AB4http://bryntum.com/contact5http://bryntum.com/license6*/7/**8@class Sch.data.TimeAxis9@extends Ext.data.JsonStore10A class representing the time axis of the scheduler. The scheduler timescale is based on the ticks generated by this class.11This is a pure "data" (model) representation of the time axis and has no UI elements.12The time axis can be {@link #continuous} or not. In continuous mode, each timespan starts where the previous ended, and in non-continuous mode13 there can be gaps between the ticks.14A non-continuous time axis can be used when want to filter out certain periods of time (like weekends) from the time axis.15To create a non-continuos time axis you have 2 options. First, you can create a time axis containing only the time spans of interest.16To do that, subclass this class and override the {@link #generateTicks} method. See the `timeaxis` example in the Ext Scheduler SDK for guidance.17The other alternative is to call the {@link #filterBy} method, passing a function to it which should return `false` if the time tick should be filtered out.18Calling {@link #clearFilter} will return you to a full time axis.19*/20Ext.define("Sch.data.TimeAxis", {21 extend : "Ext.data.JsonStore",22 requires : [23 'Sch.util.Date',24 // this "require" is needed for Sencha Touch25 'Sch.model.TimeAxisTick'26 ],27 model : 'Sch.model.TimeAxisTick',28 /**29 * @cfg {Boolean} continuous30 * Set to false if the timeline is not continuous, e.g. the next timespan does not start where the previous ended (for example skipping weekends etc).31 */32 continuous : true,33 originalContinuous : null,34 /**35 * @cfg {Boolean} autoAdjust36 * Automatically adjust the timespan when generating ticks with {@link #generateTicks} according to the `viewPreset` configuration. Setting this to false37 * may lead to shifting time/date of ticks.38 */39 autoAdjust : true,40 unit : null,41 increment : null,42 resolutionUnit : null,43 resolutionIncrement : null,44 weekStartDay : null,45 mainUnit : null,46 shiftUnit : null,47 shiftIncrement : 1,48 defaultSpan : 1,49 isConfigured : false,50 // in case of `autoAdjust : false`, the 1st and last ticks can be truncated, containing only part of the normal tick51 // these dates will contain adjusted start/end (like if the tick has not been truncated)52 adjustedStart : null,53 adjustedEnd : null,54 // the visible position in the first tick, can actually be > 1 because the adjustment is done by the `mainUnit`55 visibleTickStart : null,56 // the visible position in the first tick, is always ticks count - 1 < value <= ticks count, in case of autoAdjust, always = ticks count57 visibleTickEnd : null,58 // name of the current preset59 presetName : null,60 /**61 * @cfg {String} mode This option determines how timeaxis should be rounded.62 * When we round timeAxis for calendar we want to get minimum number of weeks that comprises desired month.63 * Options: ['plain', 'calendar']64 */65 mode : 'plain',66 /**67 * @cfg {Number} startTime Start time for calendar mode, used only with day/week presets.68 */69 startTime : 0,70 71 /**72 * @cfg {Number} endTime End time for calendar mode, used only with day/week presets.73 */74 endTime : 24,75 /**76 * @event beforereconfigure77 * Fires before the timeaxis is about to be reconfigured (e.g. new start/end date or unit/increment). Return false to abort the operation.78 * @param {Sch.data.TimeAxis} timeAxis The time axis instance79 * @param {Date} startDate The new time axis start date80 * @param {Date} endDate The new time axis end date81 */82 /**83 * @event endreconfigure84 * @private85 * Event that is triggered when we end reconfiguring and everything ui-related should be done86 */87 /**88 * @event reconfigure89 * Fires when the timeaxis has been reconfigured (e.g. new start/end date or unit/increment)90 * @param {Sch.data.TimeAxis} timeAxis The time axis instance91 */92 // private93 constructor : function(config) {94 var me = this;95 config = config || {};96 // For Sencha Touch, config system97 if (me.setModel) {98 me.setModel(me.model);99 }100 me.setMode(config.mode || me.mode);101 me.originalContinuous = me.continuous;102 me.callParent(arguments);103 me.on(Ext.versions.touch ? 'refresh' : 'datachanged', function() {104 me.fireEvent('reconfigure', me, false);105 });106 me.on('endreconfigure', function(me, suppressRefresh) {107 me.fireEvent('reconfigure', me, suppressRefresh);108 });109 if (config.viewPreset) {110 var preset = Sch.preset.Manager.getPreset(config.viewPreset);111 preset && me.consumeViewPreset(preset);112 }113 // not sure what me.start is but just in case I'm leaving previous condition114 if (config.start || me.start) {115 me.reconfigure(config);116 }117 },118 /**119 * Reconfigures the time axis based on the config object supplied and generates the new 'ticks'.120 * @param {Object} config121 * @param {Boolean} [suppressRefresh]122 * @private123 */124 reconfigure : function (config, suppressRefresh) {125 this.isConfigured = true;126 Ext.apply(this, config);127 var adjusted = this.getAdjustedDates(config.start, config.end, true);128 var normalized = this.getAdjustedDates(config.start, config.end);129 var start = normalized.start;130 var end = normalized.end;131 if (this.fireEvent('beforereconfigure', this, start, end) !== false) {132 this.fireEvent('beginreconfigure', this);133 var unit = this.unit;134 var increment = this.increment || 1;135 var ticks = this.generateTicks(start, end, unit, increment);136 // Suspending to be able to detect an invalid filter137 this.removeAll(true);138 this.suspendEvents();139 this.add(ticks);140 if (this.getCount() === 0) {141 Ext.Error.raise('Invalid time axis configuration or filter, please check your input data.');142 }143 this.resumeEvents();144 var DATE = Sch.util.Date;145 var count = ticks.length;146 if (this.isContinuous()) {147 this.adjustedStart = adjusted.start;148 this.adjustedEnd = this.getNext(count > 1 ? ticks[ count - 1 ].start : adjusted.start, unit, increment);149 } else {150 this.adjustedStart = this.getStart();151 this.adjustedEnd = this.getEnd();152 }153 // if visibleTickStart > 1 this means some tick is fully outside of the view - we are not interested in it and want to154 // drop it and adjust "adjustedStart" accordingly155 do {156 // TODO this has to use more sophisticated formula to take into account that months for example can be expressed in ms consistenly157 this.visibleTickStart = (this.getStart() - this.adjustedStart) / (DATE.getUnitDurationInMs(unit) * increment);158 if (this.visibleTickStart >= 1) this.adjustedStart = DATE.getNext(this.adjustedStart, unit, increment);159 } while (this.visibleTickStart >= 1);160 do {161 this.visibleTickEnd = count - (this.adjustedEnd - this.getEnd()) / (DATE.getUnitDurationInMs(unit) * increment);162 if (count - this.visibleTickEnd >= 1) this.adjustedEnd = DATE.getNext(this.adjustedEnd, unit, -1);163 } while (count - this.visibleTickEnd >= 1);164 this.fireEvent('endreconfigure', this, suppressRefresh);165 }166 },167 setMode : function (mode) {168 this.mode = mode;169 170 if (mode === 'calendar') {171 this.generateTicksValidatorFn = function (start) { 172 if (this.startTime > 0 || this.endTime < 24) {173 return (start.getHours() >= this.startTime && start.getHours() < this.endTime);174 } else {175 return true;176 }177 };178 } else {179 this.generateTicksValidatorFn = function () { return true; };180 }181 },182 /**183 * Changes the time axis timespan to the supplied start and end dates.184 * @param {Date} start The new start date185 * @param {Date} end The new end date186 */187 setTimeSpan : function (start, end) {188 var adjusted = this.getAdjustedDates(start, end);189 start = adjusted.start;190 end = adjusted.end;191 if (this.getStart() - start !== 0 || this.getEnd() - end !== 0) {192 this.reconfigure({193 start : start,194 end : end195 });196 }197 },198 /**199 * [Experimental] Filter the time axis by a function. The passed function will be called with each tick in time axis.200 * If the function returns true, the 'tick' is included otherwise it is filtered.201 * @param {Function} fn The function to be called, it will receive an object with start/end properties, and 'index' of the tick.202 * @param {Object} scope (optional) The scope (`this` reference) in which the function is executed.203 */204 filterBy : function(fn, scope) {205 this.continuous = false;206 scope = scope || this;207 this.clearFilter(true);208 // Suspending to be able to detect an invalid filter209 this.suspendEvents(true);210 this.filter([{211 filterFn : function(t, index) {212 return fn.call(scope, t.data, index);213 }214 }]);215 if (this.getCount() === 0) {216 this.clearFilter();217 this.resumeEvents();218 Ext.Error.raise('Invalid time axis filter - no ticks passed through the filter. Please check your filter method.');219 }220 this.resumeEvents();221 },222 /**223 * Returns `true` if the time axis is continuos (will return `false` when filtered)224 * @return {Boolean}225 */226 isContinuous : function() {227 var result = this.continuous && !this.isFiltered();228 if (this.mode === 'calendar') {229 result = result && this.startTime === 0 && this.endTime === 24;230 }231 return result;232 },233 /**234 * Clear the current filter of the time axis235 */236 clearFilter : function() {237 this.continuous = this.originalContinuous;238 this.callParent(arguments);239 },240 /**241 * Method generating the ticks for this time axis. Should return an array of ticks. Each tick is an object of the following structure:242 {243 start : ..., // start date244 end : ... // end date245 }246 *247 * Take notice, that this function either has to be called with `start`/`end` parameters, or create those variables.248 *249 * @param {Date} start The start date of the interval250 * @param {Date} end The end date of the interval251 * @param {String} unit The unit of the time axis252 * @param {Number} increment The increment for the unit specified.253 * @return {Array} ticks The ticks representing the time axis254 */255 generateTicks : function (start, end, unit, increment) {256 var ticks = [],257 intervalEnd,258 DATE = Sch.util.Date,259 dstDiff = 0;260 unit = unit || this.unit;261 increment = increment || this.increment;262 var adjusted = this.getAdjustedDates(start, end);263 start = adjusted.start;264 end = adjusted.end;265 while (start < end) {266 intervalEnd = this.getNext(start, unit, increment);267 if (!this.autoAdjust && intervalEnd > end) intervalEnd = end;268 // Handle hourly increments crossing DST boundaries to keep the timescale looking correct269 // Only do this for HOUR resolution currently, and only handle it once per tick generation.270 if (unit === DATE.HOUR && increment > 1 && ticks.length > 0 && dstDiff === 0) {271 var prev = ticks[ ticks.length - 1 ];272 dstDiff = ((prev.start.getHours() + increment) % 24) - prev.end.getHours();273 if (dstDiff !== 0) {274 // A DST boundary was crossed in previous tick, adjust this tick to keep timeaxis "symmetric".275 intervalEnd = DATE.add(intervalEnd, DATE.HOUR, dstDiff);276 }277 }278 this.generateTicksValidatorFn(start) && ticks.push({279 start : start,280 end : intervalEnd281 });282 283 start = intervalEnd;284 }285 return ticks;286 },287 getVisibleTickTimeSpan : function () {288 return this.isContinuous() ? this.visibleTickEnd - this.visibleTickStart : this.getCount();289 },290 getAdjustedDates : function (start, end, forceAdjust) {291 var DATE = Sch.util.Date;292 start = start || this.getStart();293 end = end || DATE.add(start, this.mainUnit, this.defaultSpan);294 if (this.mode === 'calendar') {295 // 'month' is tricky so we have to handle it separately296 if (this.shiftUnit === DATE.MONTH) {297 var startWeekEnd = DATE.add(start, DATE.WEEK, 1);298 var endWeekStart = DATE.add(end, DATE.WEEK, -1);299 // when this method is called from 'switchViewPreset' end date isn't provided, so we should just create one300 if (!end) {301 end = this.getNext(start, this.shiftUnit, 1);302 end = this.ceilDate(end, false, this.shiftUnit);303 end = this.ceilDate(end, false, this.mainUnit);304 }305 if (startWeekEnd.getMonth() !== start.getMonth() && endWeekStart.getMonth() !== end.getMonth()) {306 return {307 start : start,308 end : end309 };310 }311 }312 var adjustedStart, adjustedEnd, clone;313 // This code sets time span to 1 viewPreset's shiftUnit from the time axis start date314 adjustedStart = this.floorDate(start, false, this.shiftUnit, 1);315 adjustedStart = this.floorDate(adjustedStart, false, this.mainUnit, 1);316 // https://www.assembla.com/spaces/bryntum/tickets/2811317 // Disabled autoAdjust will allow to show any time span318 if (this.autoAdjust) {319 clone = this.getNext(start, this.shiftUnit, 1);320 adjustedEnd = this.ceilDate(clone, false, this.shiftUnit);321 adjustedEnd = this.ceilDate(adjustedEnd, false, this.mainUnit);322 } else {323 adjustedEnd = this.ceilDate(end, false, this.shiftUnit);324 adjustedEnd = this.ceilDate(adjustedEnd, false, this.mainUnit);325 }326 return {327 start : adjustedStart,328 end : adjustedEnd329 };330 } else {331 return this.autoAdjust || forceAdjust ? {332 start : this.floorDate(start, false, this.autoAdjust ? this.mainUnit : this.unit, 1),333 end : this.ceilDate(end, false, this.autoAdjust ? this.mainUnit : this.unit, 1)334 } : {335 start : start,336 end : end337 };338 }339 },340 /**341 * Gets a tick "coordinate" representing the date position on the time scale. Returns -1 if the date is not part of the time axis.342 * @param {Date} date the date343 * @return {Number} the tick position on the scale or -1 if the date is not part of the time axis344 */345 getTickFromDate : function (date) {346 var ticks = this.data.items;347 var lastTickIndex = ticks.length - 1;348 // quick bailout349 if (date.valueOf() < ticks[ 0 ].data.start.valueOf() || date.valueOf() > ticks[ lastTickIndex ].data.end.valueOf()) {350 return -1;351 }352 var tick, tickStart, tickEnd;353 if (this.isContinuous()) {354 if (date - ticks[ 0 ].data.start === 0) return this.visibleTickStart;355 if (date - ticks[ lastTickIndex ].data.end === 0) return this.visibleTickEnd;356 var adjustedStart = this.adjustedStart;357 var adjustedEnd = this.adjustedEnd;358 var tickIndex = Math.floor(ticks.length * (date - adjustedStart) / (adjustedEnd - adjustedStart));359 // for the date == adjustedEnd case360 if (tickIndex > lastTickIndex) tickIndex = lastTickIndex;361 tickStart = tickIndex === 0 ? adjustedStart : ticks[ tickIndex ].data.start;362 tickEnd = tickIndex == lastTickIndex ? adjustedEnd : ticks[ tickIndex ].data.end;363 tick = tickIndex + (date - tickStart) / (tickEnd - tickStart);364 // in case of `autoAdjust : false` the actual visible timespan starts not from 0 tick coordinate, but365 // from `visibleTickStart` coordinate, this check generally repeats the "quick bailout" check in the begining of the method,366 // but still367 if (tick < this.visibleTickStart || tick > this.visibleTickEnd) return -1;368 return tick;369 } else {370 for (var i = 0; i <= lastTickIndex; i++) {371 tickEnd = ticks[ i ].data.end;372 if (date <= tickEnd) {373 tickStart = ticks[ i ].data.start;374 // date < tickStart can occur in filtered case375 tick = i + (date > tickStart ? (date - tickStart) / (tickEnd - tickStart) : 0);376 return tick;377 }378 }379 }380 return -1;381 },382 /**383 * Gets the time represented by a tick "coordinate".384 * @param {Number} tick the tick "coordinate"385 * @param {String} roundingMethod The rounding method to use386 * @return {Date} The date to represented by the tick "coordinate", or null if invalid.387 */388 getDateFromTick : function (tick, roundingMethod) {389 if (tick === this.visibleTickEnd) return this.getEnd();390 var wholeTick = Math.floor(tick),391 fraction = tick - wholeTick,392 t = this.getAt(wholeTick);393 if (!t) return null;394 var tickData = t.data;395 var start = wholeTick === 0 ? this.adjustedStart : tickData.start;396 // if we've filtered timeaxis using filterBy, then we cannot trust to adjustedEnd property and should use tick end397 var end = (wholeTick == this.getCount() - 1) && this.isContinuous() ? this.adjustedEnd : tickData.end;398 var date = Sch.util.Date.add(start, Sch.util.Date.MILLI, fraction * (end - start));399 if (roundingMethod) {400 date = this[ roundingMethod + 'Date' ](date);401 }402 return date;403 },404 /**405 * Returns the ticks of the timeaxis in an array of objects with a "start" and "end" date.406 * @return {Object[]} the ticks on the scale407 */408 getTicks : function() {409 var ticks = [];410 this.each(function (r) { ticks.push(r.data); });411 return ticks;412 },413 /**414 * Method to get the current start date of the time axis415 * @return {Date} The start date416 */417 getStart : function() {418 var first = this.first();419 if (first) {420 return new Date(first.data.start);421 }422 return null;423 },424 /**425 * Method to get a the current end date of the time axis426 * @return {Date} The end date427 */428 getEnd : function() {429 var last = this.last();430 if (last) {431 return new Date(last.data.end);432 }433 return null;434 },435 // Floors a date and optionally snaps it to one of the following resolutions:436 // 1. 'resolutionUnit'. If param 'resolutionUnit' is passed, the date will simply be floored to this unit.437 // 2. If resolutionUnit is not passed: If date should be snapped relative to the timeaxis start date,438 // the resolutionUnit of the timeAxis will be used, or the timeAxis 'mainUnit' will be used to snap the date439 //440 // returns a copy of the original date441 // private442 floorDate : function(date, relativeToStart, resolutionUnit, incr) {443 relativeToStart = relativeToStart !== false;444 var dt = Ext.Date.clone(date),445 relativeTo = relativeToStart ? this.getStart() : null,446 increment = incr || this.resolutionIncrement,447 unit;448 if (resolutionUnit) {449 unit = resolutionUnit;450 } else {451 unit = relativeToStart ? this.resolutionUnit : this.mainUnit;452 }453 var DATE = Sch.util.Date;454 var snap = function (value, increment) { return Math.floor(value / increment) * increment; };455 switch (unit) {456 case DATE.MILLI:457 if (relativeToStart) {458 dt = DATE.add(relativeTo, DATE.MILLI, snap(DATE.getDurationInMilliseconds(relativeTo, dt), increment));459 }460 break;461 case DATE.SECOND:462 if (relativeToStart) {463 dt = DATE.add(relativeTo, DATE.MILLI, snap(DATE.getDurationInSeconds(relativeTo, dt), increment) * 1000);464 } else {465 dt.setMilliseconds(0);466 dt.setSeconds(snap(dt.getSeconds(), increment));467 }468 break;469 case DATE.MINUTE:470 if (relativeToStart) {471 dt = DATE.add(relativeTo, DATE.SECOND, snap(DATE.getDurationInMinutes(relativeTo, dt), increment) * 60);472 } else {473 dt.setMinutes(snap(dt.getMinutes(), increment));474 dt.setSeconds(0);475 dt.setMilliseconds(0);476 }477 break;478 case DATE.HOUR:479 if (relativeToStart) {480 dt = DATE.add(relativeTo, DATE.MINUTE, snap(DATE.getDurationInHours(this.getStart(), dt), increment) * 60);481 } else {482 dt.setMinutes(0);483 dt.setSeconds(0);484 dt.setMilliseconds(0);485 dt.setHours(snap(dt.getHours(), increment));486 }487 break;488 case DATE.DAY:489 if (relativeToStart) {490 dt = DATE.add(relativeTo, DATE.DAY, snap(DATE.getDurationInDays(relativeTo, dt), increment));491 } else {492 Sch.util.Date.clearTime(dt);493 // days are 1-based so need to make additional adjustments494 dt.setDate(snap(dt.getDate() - 1, increment) + 1);495 }496 break;497 case DATE.WEEK:498 var day = dt.getDay() || 7;499 var startDay = this.weekStartDay || 7;500 Sch.util.Date.clearTime(dt);501 dt = DATE.add(dt, DATE.DAY, day >= startDay ? startDay - day : -(7 - startDay + day));502 // Watch out for Brazil DST craziness (see test 028_timeaxis_dst.t.js)503 if (dt.getDay() !== startDay && dt.getHours() === 23) {504 dt = DATE.add(dt, DATE.HOUR, 1);505 }506 break;507 case DATE.MONTH:508 if (relativeToStart) {509 dt = DATE.add(relativeTo, DATE.MONTH, snap(DATE.getDurationInMonths(relativeTo, dt), increment));510 } else {511 Sch.util.Date.clearTime(dt);512 dt.setDate(1);513 dt.setMonth(snap(dt.getMonth(), increment));514 }515 break;516 case DATE.QUARTER:517 Sch.util.Date.clearTime(dt);518 dt.setDate(1);519 dt = DATE.add(dt, DATE.MONTH, - (dt.getMonth() % 3));520 break;521 case DATE.YEAR:522 if (relativeToStart) {523 dt = DATE.add(relativeTo, DATE.YEAR, snap(DATE.getDurationInYears(relativeTo, dt), increment));524 } else {525 // years are 1-based so need to make additional adjustments526 dt = new Date(snap(date.getFullYear() - 1, increment) + 1, 0, 1);527 }528 break;529 }530 return dt;531 },532 // Rounds the date to nearest unit increment533 // private534 roundDate : function(date, relativeTo) {535 var dt = Ext.Date.clone(date),536 increment = this.resolutionIncrement;537 relativeTo = relativeTo || this.getStart();538 switch(this.resolutionUnit) {539 case Sch.util.Date.MILLI:540 var milliseconds = Sch.util.Date.getDurationInMilliseconds(relativeTo, dt),541 snappedMilliseconds = Math.round(milliseconds / increment) * increment;542 dt = Sch.util.Date.add(relativeTo, Sch.util.Date.MILLI, snappedMilliseconds);543 break;544 case Sch.util.Date.SECOND:545 var seconds = Sch.util.Date.getDurationInSeconds(relativeTo, dt),546 snappedSeconds = Math.round(seconds / increment) * increment;547 dt = Sch.util.Date.add(relativeTo, Sch.util.Date.MILLI, snappedSeconds * 1000);548 break;549 case Sch.util.Date.MINUTE:550 var minutes = Sch.util.Date.getDurationInMinutes(relativeTo, dt),551 snappedMinutes = Math.round(minutes / increment) * increment;552 dt = Sch.util.Date.add(relativeTo, Sch.util.Date.SECOND, snappedMinutes * 60);553 break;554 case Sch.util.Date.HOUR:555 var nbrHours = Sch.util.Date.getDurationInHours(relativeTo, dt),556 snappedHours = Math.round(nbrHours / increment) * increment;557 dt = Sch.util.Date.add(relativeTo, Sch.util.Date.MINUTE, snappedHours * 60);558 break;559 case Sch.util.Date.DAY:560 var nbrDays = Sch.util.Date.getDurationInDays(relativeTo, dt),561 snappedDays = Math.round(nbrDays / increment) * increment;562 dt = Sch.util.Date.add(relativeTo, Sch.util.Date.DAY, snappedDays);563 break;564 case Sch.util.Date.WEEK:565 Sch.util.Date.clearTime(dt);566 var distanceToWeekStartDay = dt.getDay() - this.weekStartDay,567 toAdd;568 if (distanceToWeekStartDay < 0) {569 distanceToWeekStartDay = 7 + distanceToWeekStartDay;570 }571 if (Math.round(distanceToWeekStartDay/7) === 1) {572 toAdd = 7 - distanceToWeekStartDay;573 } else {574 toAdd = -distanceToWeekStartDay;575 }576 dt = Sch.util.Date.add(dt, Sch.util.Date.DAY, toAdd);577 break;578 case Sch.util.Date.MONTH:579 var nbrMonths = Sch.util.Date.getDurationInMonths(relativeTo, dt) + (dt.getDate() / Ext.Date.getDaysInMonth(dt)),580 snappedMonths = Math.round(nbrMonths / increment) * increment;581 dt = Sch.util.Date.add(relativeTo, Sch.util.Date.MONTH, snappedMonths);582 break;583 case Sch.util.Date.QUARTER:584 Sch.util.Date.clearTime(dt);585 dt.setDate(1);586 dt = Sch.util.Date.add(dt, Sch.util.Date.MONTH, 3 - (dt.getMonth() % 3));587 break;588 case Sch.util.Date.YEAR:589 var nbrYears = Sch.util.Date.getDurationInYears(relativeTo, dt),590 snappedYears = Math.round(nbrYears / increment) * increment;591 dt = Sch.util.Date.add(relativeTo, Sch.util.Date.YEAR, snappedYears);592 break;593 }594 return dt;595 },596 // private597 ceilDate : function(date, relativeToStart, resolutionUnit) {598 var dt = Ext.Date.clone(date);599 relativeToStart = relativeToStart !== false;600 var increment = relativeToStart ? this.resolutionIncrement : 1,601 doCall = false,602 unit;603 if (resolutionUnit){604 unit = resolutionUnit;605 } else {606 unit = relativeToStart ? this.resolutionUnit : this.mainUnit;607 }608 switch (unit) {609 case Sch.util.Date.HOUR:610 if (dt.getMinutes() > 0 || dt.getSeconds() > 0 || dt.getMilliseconds() > 0) {611 doCall = true;612 }613 break;614 case Sch.util.Date.DAY:615 if (dt.getHours() > 0 || dt.getMinutes() > 0 || dt.getSeconds() > 0 || dt.getMilliseconds() > 0) {616 doCall = true;617 }618 break;619 case Sch.util.Date.WEEK:620 Sch.util.Date.clearTime(dt);621 if (dt.getDay() !== this.weekStartDay || date.getTime() - dt.getTime() > 0) {622 doCall = true;623 }624 break;625 case Sch.util.Date.MONTH:626 Sch.util.Date.clearTime(dt);627 if (dt.getDate() !== 1 || date.getTime() - dt.getTime() > 0) {628 doCall = true;629 }630 break;631 case Sch.util.Date.QUARTER:632 Sch.util.Date.clearTime(dt);633 if (dt.getMonth() % 3 !== 0 || dt.getDate() !== 1 || date.getTime() - dt.getTime() > 0) {634 doCall = true;635 }636 break;637 case Sch.util.Date.YEAR:638 Sch.util.Date.clearTime(dt);639 if (dt.getMonth() !== 0 || dt.getDate() !== 1 || date.getTime() - dt.getTime() > 0) {640 doCall = true;641 }642 break;643 default:644 break;645 }646 if (doCall) {647 return this.getNext(dt, unit, increment);648 } else {649 return dt;650 }651 },652 // private653 getNext : function(date, unit, increment) {654 return Sch.util.Date.getNext(date, unit, increment, this.weekStartDay);655 },656 // private657 getResolution : function() {658 return {659 unit : this.resolutionUnit,660 increment : this.resolutionIncrement661 };662 },663 // private664 setResolution : function(unit, increment) {665 this.resolutionUnit = unit;666 this.resolutionIncrement = increment || 1;667 },668 /**669 * Moves the time axis by the passed amount and unit.670 * @param {Number} amount The number of units to jump671 * @param {String} unit The unit (Day, Week etc)672 */673 shift: function (amount, unit) {674 this.setTimeSpan(Sch.util.Date.add(this.getStart(), unit, amount), Sch.util.Date.add(this.getEnd(), unit, amount));675 },676 /**677 * Moves the time axis forward in time in units specified by the view preset `shiftUnit`, and by the amount specified by the `shiftIncrement`678 * config of the current view preset.679 * @param {Number} amount (optional) The number of units to jump forward680 */681 shiftNext: function (amount) {682 amount = amount || this.getShiftIncrement();683 var unit = this.getShiftUnit();684 this.setTimeSpan(Sch.util.Date.add(this.getStart(), unit, amount), Sch.util.Date.add(this.getEnd(), unit, amount));685 },686 /**687 * Moves the time axis backward in time in units specified by the view preset `shiftUnit`, and by the amount specified by the `shiftIncrement` config of the current view preset.688 * @param {Number} amount (optional) The number of units to jump backward689 */690 shiftPrevious: function (amount) {691 amount = -(amount || this.getShiftIncrement());692 var unit = this.getShiftUnit();693 this.setTimeSpan(Sch.util.Date.add(this.getStart(), unit, amount), Sch.util.Date.add(this.getEnd(), unit, amount));694 },695 getShiftUnit: function () {696 return this.shiftUnit || this.mainUnit;697 },698 // private699 getShiftIncrement: function () {700 return this.shiftIncrement || 1;701 },702 // private703 getUnit: function () {704 return this.unit;705 },706 // private707 getIncrement: function () {708 return this.increment;709 },710 711 // to keep rows and time axis in sync, we use this function to return ticks to generate rows.712 getRowTicks : function () {713 if (this.mode !== 'plain') {714 var start = this.getStart();715 var end = Sch.util.Date.add(start, this.headerConfig.middle.splitUnit, 1);716 var endIndex = this.findBy(function (record) {717 return record.getStartDate().getTime() >= end.getTime();718 });719 // if no such record was found - we are dealing with day view720 if (endIndex === -1) {721 return this.getRange();722 }723 return this.getRange(0, endIndex - 1);724 }725 },726 /**727 * Returns true if the passed date is inside the span of the current time axis.728 * @param {Date} date The date to query for729 * @return {Boolean} true if the date is part of the timeaxis730 */731 dateInAxis: function(date) {732 var result = Sch.util.Date.betweenLesser(date, this.getStart(), this.getEnd());733 // Date is between axis start/end and axis is not continuous - need to perform better lookup734 if (result && !this.isContinuous()) {735 var tickIndex = this.getTickFromDate(date);736 var tick = this.getAt(Math.floor(tickIndex));737 result = tick.getStartDate() <= date && tick.getEndDate() >= date;738 }739 return result;740 },741 /**742 * Returns true if the passed timespan is part of the current time axis (in whole or partially).743 * @param {Date} start The start date744 * @param {Date} end The end date745 * @return {boolean} true if the timespan is part of the timeaxis746 */747 timeSpanInAxis: function(start, end) {748 if (this.isContinuous()) {749 return Sch.util.Date.intersectSpans(start, end, this.getStart(), this.getEnd());750 } else {751 return (start < this.getStart() && end > this.getEnd()) ||752 this.getTickFromDate(start) !== this.getTickFromDate(end);753 }754 },755 // Accepts a Sch.model.Range model756 isRangeInAxis: function(range) {757 var start = range.getStartDate(),758 end = range.getEndDate();759 // only consider fully scheduled ranges760 if (!start || !end) return false;761 return this.timeSpanInAxis(start, end);762 },763 /**764 * Calls the supplied iterator function once per interval. The function will be called with three parameters, start date and end date and an index.765 * @protected766 * @param {String} unit The unit to use when iterating over the timespan767 * @param {Number} increment The increment to use when iterating over the timespan768 * @param {Function} iteratorFn The function to call769 * @param {Object} scope (optional) The "this" object to use for the function call770 */771 forEachAuxInterval : function (unit, increment, iteratorFn, scope) {772 scope = scope || this;773 var end = this.getEnd(),774 dt = this.getStart(),775 i = 0,776 intervalEnd;777 if (dt > end) throw 'Invalid time axis configuration';778 while (dt < end) {779 intervalEnd = Sch.util.Date.min(this.getNext(dt, unit, increment || 1), end);780 iteratorFn.call(scope, dt, intervalEnd, i);781 dt = intervalEnd;782 i++;783 }784 },785 consumeViewPreset : function (preset) {786 Ext.apply(this, {787 unit : preset.getBottomHeader().unit,788 increment : preset.getBottomHeader().increment || 1,789 resolutionUnit : preset.timeResolution.unit,790 resolutionIncrement : preset.timeResolution.increment,791 mainUnit : preset.getMainHeader().unit,792 shiftUnit : preset.shiftUnit,793 shiftIncrement : preset.shiftIncrement || 1,794 defaultSpan : preset.defaultSpan || 1,795 presetName : preset.name,796 // Calendar columns are updated upon 'datachanged' event on this object.797 // We have to pass headerConfig in order to render them correctly (timeAxisViewModel is incorrect in required time)798 headerConfig : preset.headerConfig799 });800 }...
ffNetworkManager.js
Source:ffNetworkManager.js
...64 if (response.evicted) throw new Error(`Response body for ${request.request.method()} ${request.request.url()} was evicted!`);65 return Buffer.from(response.base64body, 'base64');66 };67 const startTime = event.timing.startTime;68 function relativeToStart(time) {69 if (!time) return -1;70 return (time - startTime) / 1000;71 }72 const timing = {73 startTime: startTime / 1000,74 domainLookupStart: relativeToStart(event.timing.domainLookupStart),75 domainLookupEnd: relativeToStart(event.timing.domainLookupEnd),76 connectStart: relativeToStart(event.timing.connectStart),77 secureConnectionStart: relativeToStart(event.timing.secureConnectionStart),78 connectEnd: relativeToStart(event.timing.connectEnd),79 requestStart: relativeToStart(event.timing.requestStart),80 responseStart: relativeToStart(event.timing.responseStart)81 };82 const response = new network.Response(request.request, event.status, event.statusText, parseMultivalueHeaders(event.headers), timing, getResponseBody);83 if (event !== null && event !== void 0 && event.remoteIPAddress && typeof (event === null || event === void 0 ? void 0 : event.remotePort) === 'number') {84 response._serverAddrFinished({85 ipAddress: event.remoteIPAddress,86 port: event.remotePort87 });88 } else {89 response._serverAddrFinished();90 }91 response._securityDetailsFinished({92 protocol: event === null || event === void 0 ? void 0 : (_event$securityDetail = event.securityDetails) === null || _event$securityDetail === void 0 ? void 0 : _event$securityDetail.protocol,93 subjectName: event === null || event === void 0 ? void 0 : (_event$securityDetail2 = event.securityDetails) === null || _event$securityDetail2 === void 0 ? void 0 : _event$securityDetail2.subjectName,94 issuer: event === null || event === void 0 ? void 0 : (_event$securityDetail3 = event.securityDetails) === null || _event$securityDetail3 === void 0 ? void 0 : _event$securityDetail3.issuer,...
domElement.js
Source:domElement.js
1/* eslint-disable no-bitwise */2/* eslint-disable no-continue */3import Caret from './caret';4class DOMElement {5 /**6 * Creates a new DOMElement instance.7 * Parameters:8 * el: DOM Element9 */10 constructor(el) {11 this.el = el;12 this.isActive = false;13 }14 get active() {15 return this.isActive;16 }17 set active(active) {18 this.isActive = active;19 }20 /**21 * innerHTML gets the innerHTML of the DOM element.22 * Parameters:23 * content: string24 */25 get innerHTML() {26 return this.el.innerHTML;27 }28 /**29 * setInnerHTML sets the innerHTML of the DOM element.30 * Parameters:31 * content: string32 */33 setInnerHTML(content) {34 this.el.innerHTML = content;35 }36 /**37 * contains38 * Parameters:39 * content: string40 */41 contains(el) {42 return this.el.contains(el);43 }44 /**45 * getCaretPosition gets the caret position relative to the text in the DOM46 * element.47 * Returns: Caret48 */49 getCaretPosition() {50 let start = 0;51 let end = 0;52 const doc = this.el.ownerDocument || this.el.document;53 const win = doc.defaultView || doc.parentWindow;54 let sel;55 if (win.getSelection !== undefined) {56 sel = win.getSelection();57 if (sel.rangeCount > 0) {58 const range = win.getSelection().getRangeAt(0);59 const preCaretRange = range.cloneRange();60 preCaretRange.selectNodeContents(this.el);61 preCaretRange.setEnd(range.startContainer, range.startOffset);62 start = preCaretRange.toString().length;63 preCaretRange.selectNodeContents(this.el);64 preCaretRange.setEnd(range.endContainer, range.endOffset);65 end = preCaretRange.toString().length;66 // Account for newlines by counting the number of top-level divs67 // preceding and including the range's start container and end68 // container.69 const divs = this.getAllDivNodes();70 if (divs.length > 0) {71 divs.splice(0, 1); // The first div doesn't count as a new line72 }73 divs.forEach((child) => {74 const relativeToStart = range.startContainer.compareDocumentPosition(child);75 const relativeToEnd = range.endContainer.compareDocumentPosition(child);76 if (relativeToStart === 077 || relativeToStart & Node.DOCUMENT_POSITION_PRECEDING) {78 start += 1;79 }80 if (relativeToEnd === 081 || relativeToEnd & Node.DOCUMENT_POSITION_PRECEDING) {82 end += 1;83 }84 });85 }86 }87 return new Caret(start, end);88 }89 /**90 * getAllNodes gets all of the nodes within the DOM Element.91 * Returns: Node[]92 */93 getAllNodes() {94 const a = [];95 const walk = document.createTreeWalker(this.el, NodeFilter.SHOW_ALL, null, false);96 let n = walk.nextNode();97 while (n) {98 a.push(n);99 n = walk.nextNode();100 }101 return a;102 }103 /**104 * getAllDivNodes gets all of the <div> nodes within the DOM Element.105 * Returns: Node[]106 */107 getAllDivNodes() {108 const allNodes = this.getAllNodes();109 return allNodes.filter((node) => node.nodeName.toUpperCase() === 'DIV');110 }111 /**112 * getTextSize gets the total size of only the text nodes in the DOM Element.113 * Returns: int, total size of text nodes114 */115 getTextSize() {116 const range = document.createRange();117 range.selectNodeContents(this.el);118 const divs = this.getAllDivNodes();119 return range.toString().length + (divs.length > 0 ? divs.length - 1 : 0);120 }121 /**122 * getCaretData determines the node and offset of the given position within the123 * DOM Element.124 * Parameters:125 * position: int126 * Returns: object{node, offset}, where node is the Node that the position is127 * in and offset is the position within the element128 */129 getCaretData(position) {130 let node;131 let offset = position;132 const nodes = this.getAllNodes();133 const divs = this.getAllDivNodes();134 let divCount = 0;135 if (divs.length > 0) {136 offset += 1; // Account for the div on the first line137 }138 for (let n = 0; n < nodes.length; n += 1) {139 if (nodes[n].isEqualNode(divs[divCount])) {140 offset -= 1;141 divCount += 1;142 continue;143 }144 const nodeValue = nodes[n].nodeValue ? nodes[n].nodeValue : '';145 if (offset > nodeValue.length && nodes[n + 1]) {146 // remove amount from the position, go to next node147 offset -= nodeValue.length;148 } else {149 node = nodes[n];150 break;151 }152 }153 return { node, offset };154 }155 /**156 * setCaret sets the client's caret at a specified position in the DOM element.157 * Parameters:158 * position: Caret159 */160 setCaret(position) {161 const doc = this.el.ownerDocument || this.el.document;162 const win = doc.defaultView || doc.parentWindow;163 const sel = win.getSelection();164 const range = doc.createRange();165 const { start, end } = position;166 const startData = this.getCaretData(start);167 const endData = this.getCaretData(end);168 if (!startData.node) {169 startData.node = this.el;170 }171 if (!endData.node) {172 endData.node = this.el;173 }174 range.setStart(startData.node, startData.offset);175 if (startData.node === endData.node && startData.offset === endData.offset) {176 range.collapse(true);177 } else {178 range.setEnd(endData.node, endData.offset);179 }180 sel.removeAllRanges();181 sel.addRange(range);182 }183 /**184 * removeHighlight removes a "highlight" span from around text nodes.185 * Parameters:186 * highlight, DOM Element: the "highlight" span with children187 */188 removeHighlight(highlight) {189 const doc = this.el.ownerDocument || this.el.document;190 const highlightRange = doc.createRange();191 highlightRange.selectNodeContents(highlight);192 highlight.parentNode.insertBefore(highlightRange.extractContents(), highlight);193 highlight.parentNode.removeChild(highlight);194 }195 /**196 * removeAllHighlights removes all "highlight" spans from around text nodes197 * inside the DOM element.198 */199 removeAllHighlights() {200 const highlights = this.el.querySelectorAll('span.highlight');201 highlights.forEach((highlight) => {202 this.removeHighlight(highlight);203 });204 }205 /**206 * setActiveUserCaret modifies the DOM to display a representation of the207 * active user's caret.208 * Parameters:209 * activeUser: ActiveUser210 */211 setActiveUserCaret(activeUser) {212 const { id, caret: { start, end }, colour } = activeUser;213 const { parentNode } = this.el;214 let cursor = parentNode.querySelector(`#cursor-${id}`);215 if (!cursor) {216 cursor = document.createElement('span');217 cursor.setAttribute('id', `cursor-${id}`);218 cursor.setAttribute('class', 'cursor');219 cursor.setAttribute('style', `background-color: var(--${colour});`);220 } else {221 cursor = cursor.parentNode.removeChild(cursor);222 }223 const startData = this.getCaretData(start);224 if (!startData.node) {225 startData.node = this.el;226 }227 const range = document.createRange();228 range.setStart(startData.node, startData.offset);229 let startY = range.getBoundingClientRect().top;230 let startX = range.getBoundingClientRect().left;231 let outOfView = false;232 if (startData.node === this.el) {233 parentNode.style.position = 'relative';234 cursor.style.top = '1em';235 cursor.style.left = '1em';236 } else {237 if (startY === 0 && startX === 0) {238 startY = startData.node.getBoundingClientRect().top;239 startX = startData.node.getBoundingClientRect().left;240 }241 parentNode.style.position = 'static';242 cursor.style.top = `${startY}px`;243 cursor.style.left = `${startX}px`;244 const minY = parentNode.getBoundingClientRect().top;245 const cursorHeight = 1.25 * parseFloat(window.getComputedStyle(parentNode).getPropertyValue('font-size'));246 if (startY < minY) {247 if (startY + cursorHeight > minY) {248 cursor.style.top = `${minY}px`;249 cursor.style.height = `${cursorHeight - (minY - startY)}px`;250 } else {251 outOfView = true;252 }253 }254 }255 if (!outOfView) {256 parentNode.append(cursor);257 }258 let highlight = this.el.querySelector(`#highlight-${id}`);259 if (!highlight) {260 highlight = document.createElement('span');261 highlight.setAttribute('id', `highlight-${id}`);262 highlight.setAttribute('class', 'highlight');263 highlight.setAttribute('style', `background-color: var(--highlight-${colour});`);264 } else {265 this.removeHighlight(highlight);266 }267 if (start !== end) {268 const endData = this.getCaretData(end);269 if (!endData.node) {270 endData.node = this.el;271 }272 range.setEnd(endData.node, endData.offset);273 range.surroundContents(highlight);274 }275 }276 /**277 * removeActiveUserCaret removes the representation of the active user's caret278 * from the DOM.279 * Parameters:280 * id, int: the active user's id281 */282 removeActiveUserCaret(id) {283 const cursor = this.el.parentNode.querySelector(`#cursor-${id}`);284 if (cursor) {285 cursor.parentNode.removeChild(cursor);286 }287 const highlight = this.el.querySelector(`#highlight-${id}`);288 if (highlight) {289 this.removeHighlight(highlight);290 }291 }292}...
fullscreenSlider.js
Source:fullscreenSlider.js
1window.addEventListener('DOMContentLoaded', () => {2 const sections = Array.from(document.getElementsByClassName('section')); // All the sections of the homepage's slider3 const container = document.getElementById('container'); // The sections' container4 // Object with properties related to the fullscreen touch slider controler.5 const touchParams = {6 sections: sections, // Sections of the fullscreen touch slider.7 startPosition: 0, // Y-Axis position where the dragging began.8 previousPosition: 0, // Y-Axis position prior to the start of dragging.9 currentPosition: 0, // Current Y-Axis position, updated while dragging.10 relativeToStart: 0, // Difference in position from where dragging started.11 index: 0, // The current section showed on the viewport.12 canSlideUp: true, // True if I can slide into a next section.13 canSlideDown: true, // True if I can slide into a previous section.14 };15 adjustHeight(sections);16 anim();17 touchEvents(container, touchParams);18 window.addEventListener('resize', () => {19 adjustHeight(sections);20 adjustByIndex(container, touchParams);21 });22 // Handle scrolleable sections --------------------------------------23 const scrolleables = container.querySelectorAll('[scrolleable]');24 scrolleables.forEach((scrolleable) => {25 scrolleable.addEventListener('scroll', function () {26 checkScrollInScrolleable(this, container, touchParams);27 });28 });29 // Go to second section with the button30 const nextSectionBtn = document.querySelector('#nextSectionBtn');31 nextSectionBtn.addEventListener('click', () => {32 touchParams.index = 1;33 adjustByIndex(container, touchParams);34 touchParams.index = 1;35 });36});37/**38 * This function makes sure that the scroll of a scrolleable section is at some bound to be able to slide to other section.39 * @param {*} scrolleable the scrolleable section DOM element.40 * @param {*} container the sectoins' container.41 * @param {*} touchParams the Oject with properties related to the fullscreen touch slider controler.42 */43function checkScrollInScrolleable(scrolleable, container, touchParams) {44 touchParams.canSlideUp = false;45 touchParams.canSlideDown = false;46 if (47 scrolleable.scrollTop + scrolleable.getBoundingClientRect().bottom >=48 scrolleable.scrollHeight - 1049 ) {50 touchParams.canSlideDown = true;51 }52 if (scrolleable.scrollTop <= 10) {53 touchParams.canSlideUp = true;54 }55}56/**57 * Adjusts the height of the sections, html and body DOM elements to fill the full viewport58 * @param {*} sections59 */60function adjustHeight(sections) {61 let vh = window.innerHeight;62 document.querySelector('html').style.height = `${vh}px`;63 document.querySelector('body').style.height = `${vh}px`;64 sections.forEach((section) => {65 section.style.height = `${vh}px`;66 });67}68/**69 * Make the header's animation when the page has been loaded70 */71function anim() {72 const headerTitle = document.getElementById('headerTitle');73 const headerSubtitle = document.getElementById('headerSubtitle');74 const socialIcons = document.querySelectorAll('.socialIcon');75 const footprint = document.querySelector('#footprint');76 // Title fade in77 headerTitle.animate([{ opacity: '1' }], {78 easing: 'ease',79 duration: 2000,80 fill: 'forwards',81 });82 // Subtitle fade in83 headerSubtitle.animate([{ opacity: '1' }], {84 delay: 1500,85 duration: 2000,86 fill: 'forwards',87 });88 // Footprint loop rotation89 footprint.animate(90 [91 { transform: 'rotate(380deg)' },92 { transform: 'rotate(300deg)' },93 { transform: 'rotate(400deg)' },94 { transform: 'rotate(380deg)' },95 ],96 {97 duration: 1000,98 fill: 'none',99 iterations: Infinity,100 }101 );102 // Social media icons fade in103 for (let i = 0; i < socialIcons.length; ++i) {104 socialIcons[i].animate([{ transform: 'scale(1)' }], {105 easing: 'ease',106 delay: 350 * i,107 duration: 500,108 fill: 'forwards',109 });110 }111}112/**113 * Adds event handlers to all touch events114 */115function touchEvents(container, touchParams) {116 container.addEventListener(117 'touchstart',118 touchStartHanlder(container, touchParams)119 );120 container.addEventListener(121 'touchmove',122 touchMoveHandler(container, touchParams)123 );124 container.addEventListener(125 'touchend',126 touchEndHanlder(container, touchParams)127 );128 container.addEventListener(129 'touchcancel',130 touchEndHanlder(container, touchParams)131 );132}133function touchStartHanlder(container, touchParams) {134 return (e) => {135 touchParams.startPosition = e.touches[0].clientY;136 };137}138function touchMoveHandler(container, touchParams) {139 return (e) => {140 touchParams.relativeToStart =141 e.touches[0].clientY - touchParams.startPosition;142 if (Math.abs(touchParams.relativeToStart) < 150) {143 touchParams.currentPosition =144 touchParams.relativeToStart + touchParams.previousPosition;145 }146 if (touchParams.canSlideUp && touchParams.relativeToStart > 10) {147 container.style.transform = `translateY(${touchParams.currentPosition}px)`;148 } else if (149 touchParams.canSlideDown &&150 touchParams.relativeToStart < -10151 ) {152 container.style.transform = `translateY(${touchParams.currentPosition}px)`;153 }154 };155}156function touchEndHanlder(container, touchParams) {157 return (e) => {158 if (159 touchParams.relativeToStart > 100 &&160 touchParams.index > 0 &&161 touchParams.canSlideUp162 ) {163 touchParams.index--;164 touchParams.canSlideDown = true;165 touchParams.canSlideUp = true;166 } else if (167 touchParams.relativeToStart < -100 &&168 touchParams.index < touchParams.sections.length - 1 &&169 touchParams.canSlideDown170 ) {171 touchParams.index++;172 touchParams.canSlideDown = true;173 touchParams.canSlideUp = true;174 }175 adjustByIndex(container, touchParams);176 };177}178/**179 * Adjusts the position of the container depending on the index of the current section.180 * @param {*} container The section's container181 * @param {*} touchParams An object whose properties are variables related to the touch handler182 */183function adjustByIndex(container, touchParams) {184 container.style.transform = `translateY(${185 window.innerHeight * -touchParams.index186 }px)`;187 touchParams.relativeToStart = 0;188 touchParams.previousPosition = -touchParams.index * window.innerHeight;...
Using AI Code Generation
1const path = require('path');2const {chromium} = require('playwright');3(async () => {4 const browser = await chromium.launch();5 const page = await browser.newPage();6 await page.screenshot({ path: path.relativeToStart('test.png') });7 await browser.close();8})();9const path = require('path');10const {chromium} = require('playwright');11(async () => {12 const browser = await chromium.launch();13 const page = await browser.newPage();14 await page.screenshot({ path: path.relativeToStart('test.png') });15 await browser.close();16})();
Using AI Code Generation
1const { relativeToStart } = require('@playwright/test');2const { test } = require('@playwright/test');3test('test', async ({ page }) => {4 await page.goto(relativeToStart('index.html'));5});6const { relativeToStart } = require('@playwright/test');7console.log(relativeToStart('test.js'));
Using AI Code Generation
1const { relativeToStart } = require('playwright/lib/server/frames');2const { Frame } = require('playwright/lib/server/chromium/crPage');3const { Page } = require('playwright/lib/server/chromium/crPage');4const getFrame = (page, frameName) => {5 const target = page._browserContext._targets.find(target => target._page === page);6 const frame = target._page._frameManager._frames.find(frame => frame._name === frameName);7 return frame;8};9const getFrameElement = async (page, frameName, selector) => {10 const frame = getFrame(page, frameName);11 const element = await frame.$(selector);12 const [x, y] = await element.evaluate(element => [element.offsetLeft, element.offsetTop]);13 const [width, height] = await element.evaluate(element => [element.offsetWidth, element.offsetHeight]);14 const position = { x, y, width, height };15 const relativePosition = relativeToStart(frame, position);16 return { element, position: relativePosition };17};18const { test, expect } = require('@playwright/test');19test('Test', async ({ page }) => {20 const { position } = await getFrameElement(page, 'iframeResult', 'h1');21 await page.mouse.move(position.x + 10, position.y + 10);22 await page.mouse.click(position.x + 10, position.y + 10);23 await page.waitForTimeout(5000);24});25const getFrameElement = async (page, frameName, selector) => {26 const frame = getFrame(page, frameName);27 const element = await frame.$(selector);28 const [x, y] = await element.evaluate(element => [element.offsetLeft, element.offsetTop]);29 const [width, height] = await element.evaluate(element => [element.offsetWidth, element.offsetHeight]);30 const position = { x, y, width, height };
Using AI Code Generation
1const { relativeToStart } = require('playwright/lib/server/frames');2const { Frame } = require('playwright/lib/server/chromium/crPage');3const { ElementHandle } = require('playwright/lib/server/chromium/crElementHandle');4const frame = new Frame(null, null, null, null, null, null, null, null, null, null, null, null, null, null);5const elementHandle = new ElementHandle(null, null, null, null, null, null, null, null, null, null, null, null, null, null);6const result = relativeToStart(elementHandle, frame, 0, 0);7console.log(result);8const { relativeToStart } = require('playwright/lib/server/frames');9const { Frame } = require('playwright/lib/server/chromium/crPage');10const { ElementHandle } = require('playwright/lib/server/chromium/crElementHandle');11const frame = new Frame(null, null, null, null, null, null, null, null, null, null, null, null, null, null);12const elementHandle = new ElementHandle(null, null, null, null, null, null, null, null, null, null, null, null, null, null);13const result = relativeToStart(elementHandle, frame, 100, 100);14console.log(result);15const { relativeToStart } = require('playwright/lib/server/frames');16const { Frame } = require('playwright/lib/server/chromium/crPage');17const { ElementHandle } = require('playwright/lib/server/chromium/crElementHandle');18const frame = new Frame(null, null, null, null, null, null, null, null, null, null, null, null, null, null);
Using AI Code Generation
1const { test } = require('@playwright/test');2const path = require('path');3test('test', async ({ page }) => {4 const imagePath = path.relativeToStart('image.png');5 await page.screenshot({ path: imagePath });6});
Using AI Code Generation
1import { test as base, expect } from '@playwright/test';2import { relativeToStart } from '@playwright/test/lib/test/workerRunner';3const test = base.extend<{ relativePath: string }>({4 relativePath: async ({}, use) => {5 await use(relativeToStart(__filename));6 },7});8test('test', async ({ relativePath }) => {9 expect(relativePath).toBe('test.js');10});11test.describe('test', () => {12 test('test', async ({ relativePath }) => {13 expect(relativePath).toBe('test.js');14 });15});
Using AI Code Generation
1const { chromium } = require('playwright');2(async () => {3 const browser = await chromium.launch();4 const context = await browser.newContext();5 const page = await context.newPage();6 const elementToStart = await page.$('text="Element to start"');7 const elementToClick = await page.$('text="Element to click"');8 await elementToClick.click({ relativeToStart: elementToStart });9 await browser.close();10})();
LambdaTest’s Playwright tutorial will give you a broader idea about the Playwright automation framework, its unique features, and use cases with examples to exceed your understanding of Playwright testing. This tutorial will give A to Z guidance, from installing the Playwright framework to some best practices and advanced concepts.
Get 100 minutes of automation test minutes FREE!!