mirror of
https://github.com/compiler-explorer/compiler-explorer.git
synced 2025-12-27 07:04:04 -05:00
Migrate to Bootstrap 5 (#7582)
This PR completes the migration from Bootstrap 4 to Bootstrap 5.3.5 following the plan outlined in [docs/Bootstrap5Migration.md](https://github.com/compiler-explorer/compiler-explorer/blob/mg/bootstrap5/docs/Bootstrap5Migration.md). ## Migration Process We followed a phased approach as documented in the migration plan: 1. **Phase 1: Dependency Updates and Basic Setup** - Updated Bootstrap from 4.6.2 to 5.3.5 - Added @popperjs/core dependency (replacing Popper.js) - Updated Tom Select theme from bootstrap4 to bootstrap5 2. **Phase 2: Global CSS Class Migration** - Updated directional utility classes (ml/mr → ms/me) - Updated floating utility classes (float-left/right → float-start/end) - Updated text alignment classes (text-left/right → text-start/end) 3. **Phase 3: HTML Attribute Updates** - Updated data attributes to use Bootstrap 5 prefixes (data-bs-toggle, data-bs-target, etc.) - Fixed tab navigation issues 4. **Phase 4: JavaScript API Compatibility Layer** - Created bootstrap-utils.ts compatibility layer - Updated component initialization for modals, dropdowns, popovers, etc. 5. **Phase 5: Component Migration** - Updated and tested specific components (modals, dropdowns, toasts, etc.) - Fixed styling issues in cards and button groups 6. **Phase 6: Form System Updates** - Updated form control classes to Bootstrap 5 standards - Updated checkbox/radio markup patterns - Simplified input groups 7. **Phase 7: Navbar Structure Updates** - Updated navbar structure with container-fluid - Fixed responsive behavior 8. **Phase 8: SCSS Variables and Theming** - Added custom CSS fixes for navbar alignment - Verified theme compatibility 9. **Phase 9: Accessibility Improvements** - Updated sr-only to visually-hidden - Added proper ARIA attributes - Enhanced screen reader support ## Key Changes - No more jQuery dependency in Bootstrap 5 - New prefix for data attributes (data-bs-*) - Improved accessibility with ARIA attributes - Updated positioning classes (start/end instead of left/right) - Simplified input group structure ## Test Plan 1. **Navigation Testing** - Verify all dropdown menus open and close properly - Test mobile menu responsiveness - Check tab navigation in settings dialog 2. **Component Testing** - Verify all modals open and close correctly (settings, share, load/save) - Test tooltips and popovers - Check form controls in different dialogs 3. **Layout Testing** - Test responsiveness on different screen sizes - Verify proper alignment of elements - Check dark mode compatibility 4. **Specific Features to Test** - Compiler selection and options - Share dialog functionality - Settings dialog - Tree view (IDE mode) - Font selection dropdown 5. **Browser Testing** - Test in Chrome, Firefox, Safari - Test in mobile browsers ## Note on Further Improvements After this migration is stable, we could consider Phase 12: removing jQuery dependency entirely, as Bootstrap 5 no longer requires it. This would be a separate effort. --------- Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
2
.idea/watcherTasks.xml
generated
2
.idea/watcherTasks.xml
generated
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectTasksOptions" suppressed-tasks="Less;Babel;Pug/Jade" />
|
||||
<component name="ProjectTasksOptions" suppressed-tasks="Less;Babel;Pug/Jade;SCSS" />
|
||||
</project>
|
||||
62
CLAUDE.md
Normal file
62
CLAUDE.md
Normal file
@@ -0,0 +1,62 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Build & Test Commands
|
||||
- Build: `npm run webpack`, `npm start`
|
||||
- Dev Mode: `make dev`, `make gpu-dev`
|
||||
- Lint: `npm run lint` (auto-fix), `npm run lint-check` (check only)
|
||||
- Type Check: `npm run ts-check`
|
||||
- Test: `npm run test` (all), `npm run test-min` (minimal)
|
||||
- Test Single File: `npm run test -- --run base-compiler-tests.ts`
|
||||
- Test Specific Pattern: `npm run test -- -t "should handle execution failures"`
|
||||
- Cypress Tests: `npm run cypress`
|
||||
- Pre-commit Check: `make pre-commit` or `npm run check`
|
||||
|
||||
## Important Workflow Requirements
|
||||
- ALWAYS run `npm run lint` before any git operations (`git add`, `git commit`, etc.)
|
||||
- The linter will automatically fix formatting issues, so this must be run before committing
|
||||
- Failing to run the linter may result in style issues and commit failures
|
||||
|
||||
## Style Guidelines
|
||||
- TypeScript: Strict typing, no implicit any, no unused locals
|
||||
- Formatting: 4-space indentation, 120 char line width, single quotes
|
||||
- No semicolon omission, prefer const/let over var
|
||||
- Client-side: TypeScript transpiled to ES5 JavaScript. This process requires import of `blah.js` even though `blah.ts` is the actual filename
|
||||
- ALWAYS place imports at the top of files, never inside functions or methods, unless absolutely necessary (and confirm before proposing)
|
||||
- Use Underscore.js for utility functions
|
||||
- Write tests for new server-side components
|
||||
- Where appropriate suggest follow-up improvements to code to improve code quality, and DRY up where feasible
|
||||
- Documentation is in `docs/` directory; update where necessary, in particular if anything about the RESTful API changes
|
||||
- Don't add comments above code that's clearly self-documenting. For example, don't put comments like this:
|
||||
```
|
||||
// Initialises the thing
|
||||
initialiseThing();
|
||||
```
|
||||
|
||||
## Testing Guidelines
|
||||
- Use Vitest for unit tests (compatible with Jest syntax)
|
||||
- Tests are in the `/test` directory, typically named like the source files they test
|
||||
- Use spy functions with `vi.spyOn()` for mocking dependencies
|
||||
- Test structure follows describe/it pattern with descriptive test names
|
||||
- Separate tests with clear section headers using comments for readability
|
||||
- Consider cross-platform compatibility (especially Windows path handling)
|
||||
- For complex files, organize tests by functionality rather than by method
|
||||
- Use `beforeEach`/`afterEach` to set up and clean up test environment
|
||||
- Remember to restore mocks with `vi.restoreAllMocks()` after tests
|
||||
- Test both success and error cases
|
||||
- Coverage is available with `npm test:coverage`
|
||||
- For Windows-specific path issues, either:
|
||||
- Skip tests with `if (process.platform === 'win32') return;`
|
||||
- Write platform-specific assertions
|
||||
- Use path-agnostic checks
|
||||
|
||||
## Compiler Testing Specifics
|
||||
- Mock filesystem operations when testing file I/O
|
||||
- Use `makeFakeCompilerInfo()` for creating test compiler configurations
|
||||
- Use `makeCompilationEnvironment()` to create test environments
|
||||
- Mock `exec` calls for testing compilation and execution
|
||||
- For BaseCompiler, use the test utils from `/test/utils.js`
|
||||
- Test specific combinations of compiler capabilities
|
||||
- Focus tests on behavior, not implementation details
|
||||
- Use platform-agnostic assertions where possible
|
||||
@@ -89,6 +89,8 @@ and shorter startup times.
|
||||
|
||||
You can also use `npm run dev` to run if `make dev` doesn't work on your machine.
|
||||
|
||||
When making UI changes, we recommend following the [UI Testing Checklist](docs/TestingTheUi.md) to ensure all components work correctly.
|
||||
|
||||
Some languages need extra tools to demangle them, e.g. `rust`, `d`, or `haskell`. Such tools are kept separately in the
|
||||
[tools repo](https://github.com/compiler-explorer/compiler-explorer-tools).
|
||||
|
||||
|
||||
387
docs/Bootstrap5Migration.md
Normal file
387
docs/Bootstrap5Migration.md
Normal file
@@ -0,0 +1,387 @@
|
||||
# Bootstrap 5 Migration Plan
|
||||
|
||||
This document outlines the step-by-step process for migrating Compiler Explorer from Bootstrap 4 to Bootstrap 5.3.5. The
|
||||
migration will be completed incrementally to allow for testing between steps.
|
||||
|
||||
## Migration Strategy
|
||||
|
||||
We'll break down the migration into smaller, testable chunks rather than making all changes at once. This approach
|
||||
allows for:
|
||||
|
||||
- Easier identification of issues
|
||||
- Progressive testing by project maintainers
|
||||
- Minimizing disruption to the codebase
|
||||
|
||||
**Progress tracking will be maintained in this document.**
|
||||
|
||||
## Phases & Current Progress
|
||||
|
||||
### Phase 1: Dependency Updates and Basic Setup ✅
|
||||
|
||||
- [x] Update package.json with Bootstrap 5.3.5
|
||||
- [x] Add @popperjs/core dependency (replacing Popper.js)
|
||||
- [x] Update Tom Select theme from bootstrap4 to bootstrap5
|
||||
- [x] Update main import statements where Bootstrap is initialized
|
||||
- [x] Update webpack configuration if needed for Bootstrap 5 compatibility
|
||||
- [x] Verify the application still builds and runs with basic functionality
|
||||
|
||||
#### Notes for Human Testers (Phase 1)
|
||||
|
||||
- At this phase, the application will have console errors related to Bootstrap component initialization
|
||||
- Tom Select dropdowns (like compiler picker) may have styling differences with the new bootstrap5 theme
|
||||
- Initial page load should still work, but dropdown functionality will be broken
|
||||
- Modal dialogs like Settings and Sharing may not function correctly
|
||||
- The primary layout and basic display of panes should still function
|
||||
|
||||
### Phase 2: Global CSS Class Migration ✅
|
||||
|
||||
- [x] Update directional utility classes (ml/mr → ms/me)
|
||||
- [x] Search and replace in .pug templates
|
||||
- [x] Search and replace in .scss files
|
||||
- [x] Search and replace in JavaScript/TypeScript files that generate HTML
|
||||
- [x] Update floating utility classes (float-left/right → float-start/end)
|
||||
- [x] Update text alignment classes (text-left/right → text-start/end)
|
||||
- [x] Update other renamed classes (badge-pill → rounded-pill, etc.)
|
||||
- [x] Test and verify styling changes
|
||||
|
||||
#### Notes for Human Testers (Phase 2)
|
||||
|
||||
- Look for proper spacing and margin alignment in the UI
|
||||
- Specific components to check:
|
||||
- Compiler output area: Check the spacing in compiler.pug (short-compiler-name, compile-info spans)
|
||||
- Navbar spacing: The navbar items should maintain proper spacing (ms/me instead of ml/mr)
|
||||
- Code editor components: Check the button and icon alignment in codeEditor.pug
|
||||
- Tree view components: The tree.pug file had utility class changes
|
||||
- Alert messages (widgets/alert.ts): Check that toast messages appear with correct alignment
|
||||
- Compiler picker (compiler-picker.ts and compiler-picker-popup.ts): Check dropdown spacing
|
||||
- Rounded badge display in menu-policies.pug (now using rounded-pill instead of badge-pill)
|
||||
- The float-end class replaces float-right in the index.pug file's copy buttons
|
||||
- Any LTR/RTL layout impacts should be especially checked for correct directionality
|
||||
|
||||
### Phase 3: HTML Attribute Updates ✅
|
||||
|
||||
- [x] Update data attributes across the codebase
|
||||
- [x] data-toggle → data-bs-toggle
|
||||
- [x] data-target → data-bs-target
|
||||
- [x] data-dismiss → data-bs-dismiss
|
||||
- [x] data-ride → data-bs-ride (not used in codebase)
|
||||
- [x] data-spy → data-bs-spy (not used in codebase)
|
||||
- [x] Other data attributes as needed
|
||||
- [x] Test components to ensure they function correctly with new attributes
|
||||
|
||||
#### Notes for Human Testers (Phase 3)
|
||||
|
||||
- This phase should restore basic functionality of several Bootstrap components
|
||||
- Specific components to check:
|
||||
- Dropdowns: All dropdown menus throughout the application should open/close properly
|
||||
- Modal dialogs: Settings, Sharing, and other modal dialogs should open/close correctly
|
||||
- Tooltips: Hover tooltips (using data-bs-toggle="tooltip") should display properly
|
||||
- Popovers: Any popovers used in the UI should function correctly
|
||||
- Collapse components: Any collapsible sections should toggle properly
|
||||
- Tabs: Any tabbed interfaces should switch between tabs correctly
|
||||
- Watch for console errors related to Bootstrap component initialization
|
||||
- Some JavaScript component initialization may still be broken until Phase 4 is completed
|
||||
|
||||
### Phase 4: JavaScript API Compatibility Layer ✅
|
||||
|
||||
- [x] Create a temporary Bootstrap compatibility utility module to abstract component initialization
|
||||
- [x] Implement a hybrid approach with `bootstrap-utils.ts` as a compatibility layer
|
||||
- [x] Mark clearly as temporary code to be removed after migration is complete
|
||||
- [x] Define methods for each component type (Modal, Dropdown, Toast, etc.)
|
||||
- [x] Update component initialization in key files:
|
||||
- [x] widgets/alert.ts (modals and toasts)
|
||||
- [x] sharing.ts (modals, tooltips, and dropdowns)
|
||||
- [x] compiler-picker-popup.ts (modals)
|
||||
- [x] load-save.ts (modals)
|
||||
- [x] Other files with Bootstrap component initialization:
|
||||
- [x] **Modal Initialization**:
|
||||
- [x] widgets/site-templates-widget.ts
|
||||
- [x] widgets/runtime-tools.ts
|
||||
- [x] widgets/compiler-overrides.ts
|
||||
- [x] widgets/timing-info-widget.ts
|
||||
- [x] widgets/history-widget.ts
|
||||
- [x] widgets/libs-widget.ts
|
||||
- [x] main.ts
|
||||
- [x] **Dropdown Handling**:
|
||||
- [x] panes/tree.ts
|
||||
- [x] panes/compiler.ts
|
||||
- [x] panes/editor.ts
|
||||
- [x] **Popover Handling**:
|
||||
- [x] main.ts
|
||||
- [x] widgets/compiler-version-info.ts
|
||||
- [x] panes/executor.ts
|
||||
- [x] panes/conformance-view.ts
|
||||
- [x] panes/cfg-view.ts
|
||||
- [x] Test the compatibility layer with basic components
|
||||
|
||||
#### Notes for Human Testers (Phase 4)
|
||||
|
||||
- This is one of the most critical phases as it involves creating a compatibility layer for the JavaScript API
|
||||
- A new utility file will be created for component initialization that abstracts Bootstrap 5's new approach
|
||||
- Key differences to watch for:
|
||||
- Modal initialization and events: Bootstrap 5 uses a completely different event system
|
||||
- Dropdown initialization: Works with data attributes but requires `data-bs-toggle` instead of `data-toggle`
|
||||
- Toast components: The API has changed significantly
|
||||
- Popover/Tooltip initialization: API changes but still support data attributes with proper prefixes
|
||||
- Components to thoroughly test:
|
||||
- Alert dialogs (widgets/alert.ts): Check all types of alerts (info, warning, error)
|
||||
- Sharing functionality (sharing.ts): The share modal should work properly
|
||||
- Compiler picker popup (compiler-picker-popup.ts): Should display and function correctly
|
||||
- All dropdown menus: Should open and close properly
|
||||
- All tooltips and popovers: Should display correctly on hover/click
|
||||
- Watch for event handling issues where Bootstrap 4 events no longer exist or are renamed
|
||||
|
||||
### Phase 5: Component Migration (By Component Type) ✅
|
||||
|
||||
#### Modal Component Migration
|
||||
|
||||
- [x] Update modal implementation in alert.ts
|
||||
- [x] Update modal usage in compiler-picker-popup.ts
|
||||
- [x] Update modal handling in load-save.ts
|
||||
- [x] Update modal event handling in sharing.ts
|
||||
- [x] Test modal functionality thoroughly
|
||||
|
||||
#### Dropdown Component Migration
|
||||
|
||||
- [x] Update dropdown handling in sharing.ts
|
||||
- [x] Update dropdown usage in compiler.ts, editor.ts, etc.
|
||||
- [x] Test dropdown functionality thoroughly
|
||||
|
||||
#### Toast/Alert Component Migration
|
||||
|
||||
- [x] Update toast implementation in alert.ts
|
||||
- [x] Update toast styling in explorer.scss
|
||||
- [x] Test toast notifications and alerts
|
||||
|
||||
#### Popover/Tooltip Migration
|
||||
|
||||
- [x] Update tooltip initialization in sharing.ts
|
||||
- [x] Update popover usage in compiler.ts, executor.ts, editor.ts, etc.
|
||||
- [x] Test popover and tooltip functionality thoroughly
|
||||
|
||||
#### Card Component Updates
|
||||
|
||||
- [x] Review card usage and update to Bootstrap 5 standards
|
||||
- [x] ~~Replace any card-deck implementations with grid system~~ (Not needed - card-deck not used in codebase)
|
||||
- [x] Test card layouts, especially tab navigation within cards
|
||||
|
||||
#### Collapse Component Updates
|
||||
|
||||
- [x] ~~Update any collapse component implementations~~ (Not needed - minimal collapse usage in codebase)
|
||||
- [x] Test collapse functionality (limited to navbar hamburger menu on mobile)
|
||||
|
||||
#### Button Group Updates
|
||||
|
||||
- [x] Review button group implementations
|
||||
- [x] Update to Bootstrap 5 standards (no changes needed - Bootstrap 5 maintains same button group classes)
|
||||
- [x] Test button group functionality in toolbars and dropdown menus
|
||||
|
||||
### Phase 6: Form System Updates ✅
|
||||
|
||||
- [x] Update form control classes to Bootstrap 5 standards
|
||||
- [x] Update input group markup and classes
|
||||
- [x] Update checkbox/radio markup to Bootstrap 5 standards
|
||||
- [x] Update form validation classes and markup
|
||||
- [x] ~~Consider implementing floating labels where appropriate (new in Bootstrap 5)~~ (Not needed for existing form
|
||||
usage)
|
||||
- [x] Test form functionality and appearance
|
||||
|
||||
### Phase 7: Navbar Structure Updates ✅
|
||||
|
||||
- [x] Update navbar structure in templates to match Bootstrap 5 requirements
|
||||
- [x] Review custom navbar styling in explorer.scss
|
||||
- [x] Test responsive behavior of navbar
|
||||
- [x] Ensure mobile menu functionality works correctly
|
||||
- [x] ~~Consider implementing offcanvas for mobile navigation (new in Bootstrap 5)~~ (Standard navbar collapse is
|
||||
sufficient for current needs)
|
||||
|
||||
### Phase 8: SCSS Variables and Theming ✅
|
||||
|
||||
- [x] Review any custom SCSS that extends Bootstrap functionality
|
||||
- [x] Update any custom themes to use Bootstrap 5 variables
|
||||
- [x] Check z-index variable changes in Bootstrap 5
|
||||
- [x] Add navbar container padding fix for proper alignment
|
||||
- [x] Test theme switching functionality
|
||||
|
||||
### Phase 9: Accessibility Improvements ✅
|
||||
|
||||
- [x] Review ARIA attributes in custom component implementations
|
||||
- [x] Leverage Bootstrap 5's improved accessibility features
|
||||
- [x] Add ARIA labels and live regions for dynamic content
|
||||
- [x] Enhance form controls with proper accessibility attributes
|
||||
- [ ] ~~Test with screen readers and keyboard navigation~~ (left for future work)
|
||||
- [ ] ~~Ensure color contrast meets accessibility guidelines~~ (left for future work)
|
||||
|
||||
### Phase 10: Final Testing and Refinement ✅
|
||||
|
||||
- [x] ~~Comprehensive testing across different viewports~~ cursory testing with a few viewports
|
||||
- [x] Cross-browser testing (at least; looked in FireFox and we're good)
|
||||
- [x] Fix any styling issues or inconsistencies
|
||||
- [x] ~~Performance testing (Bootstrap 5 should be more performant)~~ (don't care; site is fine)
|
||||
- [x] Ensure no regressions in functionality
|
||||
|
||||
## Key Learnings From Implementation
|
||||
|
||||
These insights were gathered during the migration process and may be helpful for future reference:
|
||||
|
||||
- **Data Attributes Still Work Without JavaScript Initialization**: Despite some documentation suggesting otherwise,
|
||||
Bootstrap 5 components with data attributes (like tabs) still work without explicit JavaScript initialization. The key
|
||||
is using the correct `data-bs-*` prefix.
|
||||
- **Close Button Implementation Completely Changed**: Bootstrap 4 used `.close` class with a `×` entity inside a
|
||||
span, while Bootstrap 5 uses `.btn-close` class with a background image and no inner content.
|
||||
- **Tab Navigation Issues**: The tab navigation problems were fixed by simply updating data attributes, not by adding
|
||||
JavaScript initialization.
|
||||
- **jQuery Plugin Methods Removal**: jQuery methods like `.popover()` and `.dropdown('toggle')` need to be replaced with
|
||||
code that uses the Bootstrap 5 API through a compatibility layer. Always use `BootstrapUtils` helper methods rather
|
||||
than direct jQuery plugin calls.
|
||||
- **Grid and Form Class Renaming**: Bootstrap 5 renamed several core classes, such as changing `.form-row` to `.row`.
|
||||
This can cause subtle template selector issues in code that relies on these class names.
|
||||
- **Don't Mix Data Attributes and JavaScript Modal Creation**: When creating modals via JavaScript (e.g., for
|
||||
dynamically loaded content), don't include `data-bs-toggle="modal"` on the trigger element unless you also add a
|
||||
matching `data-bs-target` attribute pointing to a valid modal element.
|
||||
- **Modal Events Changed Significantly**: Bootstrap 5 modal events need to be attached directly to the native DOM
|
||||
element rather than jQuery objects, and the event parameter type is different. For proper typing, import the `Modal`
|
||||
type from bootstrap and use `Modal.Event` type.
|
||||
- **jQuery Event Binding vs Native DOM Events**: Bootstrap 5 requires native DOM event binding instead of jQuery's
|
||||
`.on()` method. Replace `$(selector).on('shown.bs.modal', handler)` with
|
||||
`domElement.addEventListener('shown.bs.modal', handler)`. This is particularly important for modal events like '
|
||||
shown.bs.modal'.
|
||||
- **Tooltip API Changed**: The global `window.bootstrap.Tooltip` reference no longer exists. Import the `Tooltip` class
|
||||
directly from bootstrap instead.
|
||||
- **Input Group Structure Simplified**: Bootstrap 5 removed the need for `.input-group-prepend` and
|
||||
`.input-group-append` wrapper divs. Buttons and other controls can now be direct children of the `.input-group`
|
||||
container. This simplifies the markup but requires template updates.
|
||||
- **TomSelect Widget Integration**: Bootstrap 5's switch from CSS triangles to SVG background images for dropdowns
|
||||
caused issues with TomSelect. Adding back custom CSS for dropdown arrows was necessary to maintain correct appearance.
|
||||
- **Btn-block Removed**: Bootstrap 5 removed the `.btn-block` class. Instead, the recommended approach is to wrap
|
||||
buttons in a container with `.d-grid` and use standard `.btn` classes. This affects any full-width buttons in the
|
||||
application.
|
||||
- **Element Selection for Components**: When working with Bootstrap 5 components, prefer passing CSS selectors to
|
||||
`BootstrapUtils` methods rather than jQuery objects, as this provides more consistent behavior.
|
||||
|
||||
## Fixed Issues & Completed Work
|
||||
|
||||
### UI Layout & Display Issues
|
||||
|
||||
- [x] Font dropdown styling fixed
|
||||
- [x] Templates view proportions fixed (min-width added to columns and modal)
|
||||
- [x] Dialog appearance fixed (updated close buttons to use `.btn-close`)
|
||||
- [x] Dropdown positioning fixed (updated to `.dropdown-menu-end`)
|
||||
- [x] TomSelect dropdown arrows fixed (custom CSS implementation)
|
||||
- [x] IDE mode border styling improved (temporarily with `.list-group-flush`)
|
||||
- [x] Sponsors window styling fixed (replaced `.btn-block` with `.d-grid` approach)
|
||||
- [x] The X to close the community/alert notes is harder to see in dark mode than before (fixed: added
|
||||
`filter: invert(100%)` to make btn-close buttons visible in dark themes)
|
||||
- [x] TomSelect dropdowns for compilers are excessively long (both in executor view and normal view) (fixed manually)
|
||||
- [x] Default text/placeholder text is too dark, making it hard to read (especially "Compiler options") (fixed manually)
|
||||
- [x] Dropdown in the library menu has changed color (fixed: updated `.custom-select` to `.form-select` in theme files)
|
||||
- [x] ~~Layout has changed slightly in the library menu~~ (decided it looks better now)
|
||||
- [x] The "popout" on the TomSelect compiler dropdown is misaligned (fixed: updated styling for TomSelect components)
|
||||
- [x] Compiler combobox rounding overlaps left border by 1 pixel (fixed: overrode CSS variables to reset Bootstrap 5's
|
||||
negative margin)
|
||||
- [x] Diff view - changing left/right side compiler/window turns combobox to a white background (fixed: removed
|
||||
form-select class to avoid transparent background)
|
||||
- [x] The popular arguments dropdown at the right of the options isn't properly aligned (fixed: updated dropdown styling
|
||||
in compiler.pug)
|
||||
- [x] Long compiler names wrap instead of widening the dropdown (fixed: improved styling for TomSelect dropdowns)
|
||||
|
||||
### Navigation & Functional Issues
|
||||
|
||||
- [x] Tab navigation fixed (updated data attributes to `data-bs-toggle="tab"`)
|
||||
- [x] Share dialog functionality fixed (proper Bootstrap 5 modal initialization)
|
||||
- [x] Sponsors modal error fixed (removed conflicting data attributes)
|
||||
- [x] Share dropdown tooltip conflict fixed (moved tooltip to parent element)
|
||||
- [x] History view is broken (empty when clicking radio buttons) (fixed: updated modal event binding from jQuery's
|
||||
`.on('shown.bs.modal')` to native DOM `addEventListener('shown.bs.modal')`)
|
||||
- [x] Conformance view's "add compiler" functionality is broken (fixed: template selector was looking for `.form-row`
|
||||
which changed to `.row` in Bootstrap 5)
|
||||
- [x] Need to check for more instances of old Bootstrap v4 code patterns (fixed: replaced `dropdown('toggle')` in
|
||||
main.ts with `BootstrapUtils.getDropdownInstance()` and `.toggle()`)
|
||||
- [x] Runtime tools window is broken - doesn't save settings anymore (fixed: updated modal hide event handling with
|
||||
setElementEventHandler)
|
||||
- [x] Emulation functionality is broken due to modal issues (fixed: replaced direct .modal() calls with
|
||||
BootstrapUtils.showModal)
|
||||
|
||||
### Code Structure Improvements
|
||||
|
||||
- [x] Custom classes in runtime tools selection (`.custom-runtimetool`) and overrides selection (`.custom-override`) -
|
||||
removed as they were superfluous
|
||||
- [x] `.form-row` still used in theme files (dark-theme.scss, one-dark-theme.scss, pink-theme.scss) - replaced with
|
||||
standard `.row`
|
||||
- [x] Border directional properties in explorer.scss updated for better RTL support - added `border-inline-start` and
|
||||
border radius logical properties with appropriate fallbacks for older browsers
|
||||
- [x] Input group structures verified - all instances of the deprecated `.input-group-prepend` and `.input-group-append`
|
||||
have already been updated to use Bootstrap 5's simplified approach
|
||||
- [x] Toast header close button styling verified - explorer.scss already uses `.btn-close` consistently for toast
|
||||
components
|
||||
- [x] Event handlers verified - history-widget.ts and sharing.ts are correctly using native DOM addEventListener methods
|
||||
with the appropriate Bootstrap 5 event names
|
||||
|
||||
## Future Work
|
||||
|
||||
### Phase 11: Documentation Update
|
||||
|
||||
- [ ] Update any documentation that references Bootstrap components
|
||||
- [ ] Document custom component implementations
|
||||
- [ ] Note any deprecated features or changes in functionality
|
||||
|
||||
### Phase 12: Optional jQuery Removal and Cleanup
|
||||
|
||||
- [ ] Create a plan for jQuery removal (if desired)
|
||||
- [ ] Identify non-Bootstrap jQuery usage that would need refactoring
|
||||
- [ ] Remove the temporary `bootstrap-utils.ts` compatibility layer
|
||||
- [ ] Replace all uses with direct Bootstrap 5 API calls
|
||||
- [ ] Document the native Bootstrap 5 API for future reference
|
||||
- [ ] Investigate and fix modal accessibility warnings
|
||||
- [ ] Address the warning: "Blocked aria-hidden on an element because its descendant retained focus"
|
||||
- [ ] Update modal template markup to leverage Bootstrap 5.3's built-in support for the `inert` attribute
|
||||
- [ ] Ensure proper focus management in modals for improved accessibility
|
||||
|
||||
### Additional Pending Issues
|
||||
|
||||
- [ ] Check Sentry for additional errors on the beta site
|
||||
- [ ] Investigate the "focus" selected check boxes in the settings view. They're very light when focused, in particular
|
||||
in pink theme. I couldn't work out how to fix this, but it seemed minor.
|
||||
- [ ] The "pop out" div that's attached to the compiler picker doesn't work on the conformance view: this was broken
|
||||
before. Essentially the z-order means it's drawn behind the lower conformance compilers and `z-index` can't fix it.
|
||||
Needs a rethink of how this is done.
|
||||
- [ ] File tracking issues for anything on this list we don't complete.
|
||||
|
||||
## Final Testing Checklist
|
||||
|
||||
Before considering the Bootstrap 5 migration complete, a comprehensive UI testing checklist was created and used to
|
||||
verify functionality. This checklist has been completed with all tests passing. The tests cover all major UI components
|
||||
that could be affected by the Bootstrap migration.
|
||||
|
||||
The checklist included:
|
||||
|
||||
- Modal dialogs (Settings, Share, Load/Save, etc.)
|
||||
- Dropdown components (navigation, compiler options, TomSelect)
|
||||
- Toast/Alert components
|
||||
- Popovers and tooltips
|
||||
- Card, button group, and form components
|
||||
- Specialized views (Conformance, Tree, Visualization)
|
||||
- Responsive behavior
|
||||
|
||||
A permanent version of this UI testing checklist has been created as a separate document and can be used for testing
|
||||
future UI changes or upgrades: [UI Testing Checklist](TestingTheUi.md)
|
||||
|
||||
## Notes for Implementation
|
||||
|
||||
1. **Make minimal changes** in each step to allow for easier testing and troubleshooting
|
||||
2. **Test thoroughly** after each phase before moving to the next
|
||||
3. **Document issues** encountered during migration for future reference
|
||||
4. **Focus on accessibility** to ensure the site remains accessible throughout changes
|
||||
5. **Maintain browser compatibility** with all currently supported browsers
|
||||
6. **Consider performance implications** of the changes
|
||||
7. **NEVER mark any issue as fixed in this document** until you have explicit confirmation from the reviewer that the
|
||||
issue is completely resolved
|
||||
8. **NEVER commit changes** until you have explicit confirmation that the fix works correctly
|
||||
|
||||
## Technical References
|
||||
|
||||
- [Bootstrap 5 Migration Guide](https://getbootstrap.com/docs/5.0/migration/)
|
||||
- [Bootstrap 5 Components Documentation](https://getbootstrap.com/docs/5.3/components/)
|
||||
- [Bootstrap 5 Utilities Documentation](https://getbootstrap.com/docs/5.3/utilities/)
|
||||
- [Bootstrap 5 Forms Documentation](https://getbootstrap.com/docs/5.3/forms/overview/)
|
||||
- [Popper v2 Documentation](https://popper.js.org/docs/v2/)
|
||||
240
docs/TestingTheUi.md
Normal file
240
docs/TestingTheUi.md
Normal file
@@ -0,0 +1,240 @@
|
||||
# UI Testing Checklist for Compiler Explorer
|
||||
|
||||
This document provides a checklist for testing the Compiler Explorer UI components. Use this checklist for
|
||||
major UI changes, framework updates, or when implementing significant new features.
|
||||
|
||||
## Modal Components
|
||||
|
||||
### Settings Modal
|
||||
|
||||
- Open and close using the "Settings" option in the "More" dropdown
|
||||
- Test tab navigation between all tab sections (Colouring, Site behaviour, etc.)
|
||||
- Verify form controls within settings (checkboxes, selects, inputs)
|
||||
- Check that the close button works
|
||||
- Verify proper modal appearance/styling in both light and dark themes
|
||||
|
||||
### Share Modal
|
||||
|
||||
- Open and close using the "Share" button
|
||||
- Verify the URL is generated correctly
|
||||
- Test the copy button
|
||||
- Check that social sharing buttons display correctly
|
||||
- Verify proper styling in both light and dark themes
|
||||
- Test "Copied to clipboard" tooltip functionality
|
||||
|
||||
### Load/Save Modal
|
||||
|
||||
- Open and close using "Save" or "Load" options
|
||||
- Test tab navigation between sections (Examples, Browser-local storage, etc.)
|
||||
- Verify save functionality to browser storage
|
||||
- Test loading from browser storage
|
||||
- Check proper styling/layout in both light and dark themes
|
||||
|
||||
### Compiler Picker Modal
|
||||
|
||||
- Open using the popout button next to a compiler selector
|
||||
- Test filter functionality (architecture, compiler type, search)
|
||||
- Verify compiler selection works
|
||||
- Check proper styling in both light and dark themes
|
||||
|
||||
### Other Modals
|
||||
|
||||
- Test confirmation dialogs (alert.ts)
|
||||
- Test library selection modal
|
||||
- Test compiler overrides modal
|
||||
- Test runtime tools modal
|
||||
- Test templates modal
|
||||
- Verify proper styling in both light and dark themes
|
||||
|
||||
## Dropdown Components
|
||||
|
||||
### Main Navigation Dropdowns
|
||||
|
||||
- Test "More" dropdown menu (all items work and have proper styling)
|
||||
- Test "Other" dropdown menu (all items work and have proper styling)
|
||||
- Verify dropdowns are properly positioned (not clipped)
|
||||
- Test on different screen sizes to ensure responsive behavior
|
||||
|
||||
### Compiler Option Dropdowns
|
||||
|
||||
- Test filter dropdowns in compiler pane
|
||||
- Test "Add new..." dropdown
|
||||
- Test "Add tool..." dropdown
|
||||
- Test popular arguments dropdown
|
||||
- Verify proper positioning, especially for dropdowns at the right edge of the screen
|
||||
|
||||
### Editor Dropdowns
|
||||
|
||||
- Test language selector dropdown
|
||||
- Test font size dropdown
|
||||
- Verify proper styling and positioning
|
||||
|
||||
### TomSelect Dropdowns
|
||||
|
||||
- Test compiler selectors
|
||||
- Test library version selectors
|
||||
- Verify dropdown arrows appear correctly
|
||||
- Verify dropdown items are styled correctly
|
||||
|
||||
## Toast/Alert Components
|
||||
|
||||
### Alert Notifications
|
||||
|
||||
- Trigger various notifications (info, warning, error)
|
||||
- Verify proper styling
|
||||
- Test auto-dismiss functionality
|
||||
- Check that close button works
|
||||
- Test stacking behavior of multiple notifications
|
||||
|
||||
### Alert Dialogs
|
||||
|
||||
- Test info/warning/error alert dialogs (using the Alert class)
|
||||
- Verify proper styling and positioning
|
||||
- Check button functionality within dialogs
|
||||
|
||||
## Popover/Tooltip Components
|
||||
|
||||
### Tooltips
|
||||
|
||||
- Hover over various buttons with tooltips (toolbar buttons, share button, etc.)
|
||||
- Verify tooltip text appears correctly
|
||||
- Check tooltip positioning (above/below/left/right of trigger)
|
||||
- Verify proper styling in both light and dark themes
|
||||
|
||||
### Popovers
|
||||
|
||||
- Trigger popovers on compiler info
|
||||
- Check popover content displays correctly
|
||||
- Verify popover positioning
|
||||
- Test dismissal by clicking outside
|
||||
- Verify proper styling in both light and dark themes
|
||||
|
||||
## Card Components
|
||||
|
||||
- Check card styling in modals (Settings, Load/Save, etc.)
|
||||
- Verify tab navigation within card headers
|
||||
- Test card body content layout
|
||||
- Check responsive behavior on different screen sizes
|
||||
|
||||
## Button Group Components
|
||||
|
||||
### Toolbar Button Groups
|
||||
|
||||
- Test button groups in compiler pane toolbar
|
||||
- Test button groups in editor pane toolbar
|
||||
- Verify proper alignment and styling
|
||||
- Check dropdown buttons within button groups
|
||||
|
||||
### Other Button Groups
|
||||
|
||||
- Test font size button group
|
||||
- Test bottom bar button groups
|
||||
- Verify proper styling in both light and dark themes
|
||||
|
||||
## Collapse Components
|
||||
|
||||
- Test mobile view hamburger menu
|
||||
- Verify menu expands/collapses correctly
|
||||
- Check that all menu items are accessible in collapsed mode
|
||||
|
||||
## Specialized Views
|
||||
|
||||
### Conformance View
|
||||
|
||||
- Test compiler selectors and options
|
||||
- Verify results display correctly
|
||||
- Test the "add compiler" functionality
|
||||
- Verify that compilers can be added and removed
|
||||
- Check that conformance testing works end-to-end
|
||||
|
||||
### Tree View (IDE Mode)
|
||||
|
||||
- Check tree structure and file display
|
||||
- Test right-click menus and dropdowns
|
||||
- Verify file manipulation controls
|
||||
|
||||
### Visualization Components
|
||||
|
||||
- Test CFG view rendering and controls
|
||||
- Check opt pipeline viewer
|
||||
- Verify AST view
|
||||
|
||||
### Sponsor Window
|
||||
|
||||
- Check sponsor list display
|
||||
- Verify modal dialog appearance and functionality
|
||||
|
||||
## Form Components
|
||||
|
||||
- Verify form control styling (inputs, selects, checkboxes)
|
||||
- Test input groups with buttons
|
||||
- Check validation states
|
||||
|
||||
## Responsive Behavior
|
||||
|
||||
- Test at various viewport sizes
|
||||
- Verify mobile menu functionality
|
||||
- Check input group stacking behavior
|
||||
|
||||
## Runtime Tool Integration
|
||||
|
||||
### Runtime Tools
|
||||
|
||||
- Open the runtime tools window from compiler pane
|
||||
- Change settings and click outside the modal to close
|
||||
- Verify settings are properly saved
|
||||
- Test with multiple runtime tool options
|
||||
- Verify event handling properly handles modal opening/closing
|
||||
|
||||
### Emulation Features
|
||||
|
||||
- Test BBC emulation by clicking emulator links
|
||||
- Check Z80 emulation features (e.g. https://godbolt.org/z/qnE7jhnvc)
|
||||
- Verify emulator modals open properly
|
||||
- Test interaction between emulator windows and the main interface
|
||||
|
||||
## Diff View
|
||||
|
||||
- Test changing compilers in both left and right panes
|
||||
- Verify backgrounds remain themed correctly in dark mode
|
||||
- Check that the diff view layout is correct (no excessive height)
|
||||
- Confirm that input groups and buttons are properly sized
|
||||
- Test different diff view types (Assembly, Compiler output, etc.)
|
||||
|
||||
## TomSelect and Input Components
|
||||
|
||||
### Compiler Selection Dropdowns
|
||||
|
||||
- Verify long compiler names display properly without excessive wrapping
|
||||
- Check that dropdowns expand to fit compiler names rather than wrapping text
|
||||
- Test the flex-grow behavior of dropdown elements
|
||||
- Check the alignment of the popout button on all dropdowns
|
||||
- Verify border colors in dark themes are appropriate
|
||||
|
||||
### Placeholder Text
|
||||
|
||||
- Check visibility and contrast of placeholder text in all input fields
|
||||
- Specifically test "Compiler options" field visibility
|
||||
- Verify that all placeholder text is readable in both light and dark themes
|
||||
|
||||
## Library Components
|
||||
|
||||
### Library Menu
|
||||
|
||||
- Check dropdown colors and layout
|
||||
- Verify all library functionality works correctly
|
||||
- Test adding and removing libraries
|
||||
- Check library version selection
|
||||
|
||||
## History View
|
||||
|
||||
- Verify the history view populates correctly when clicking radio buttons
|
||||
- Test all history functions (load, delete, etc.)
|
||||
|
||||
## General Testing
|
||||
|
||||
- Check pixel-perfect alignment of elements (compare with live site)
|
||||
- Test all components for unexpected behavioral differences
|
||||
- Verify theme switching works correctly for all components
|
||||
- Test cross-browser compatibility (at least Firefox and Chrome)
|
||||
- Check accessibility features (tab navigation, screen reader support)
|
||||
@@ -92,7 +92,7 @@ async function generateScreenshot(url: string, output_path: string, settings, wi
|
||||
}, settings);
|
||||
await page.goto(url);
|
||||
//await sleep(2000);
|
||||
//await page.click(".modal.show button.btn.btn-outline-primary[data-dismiss=modal]");
|
||||
//await page.click(".modal.show button.btn.btn-outline-primary[data-bs-dismiss=modal]");
|
||||
//await sleep(5000);
|
||||
//await page.click("#simplecook .btn.btn-primary.btn-sm.cook-do-consent");
|
||||
await page.evaluate(() => {
|
||||
|
||||
25
package-lock.json
generated
25
package-lock.json
generated
@@ -18,11 +18,12 @@
|
||||
"@flatten-js/interval-tree": "^1.1.3",
|
||||
"@fortawesome/fontawesome-free": "^6.7.2",
|
||||
"@orchidjs/sifter": "^1.1.0",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"@sentry/browser": "^7.120.3",
|
||||
"@sentry/node": "^7.120.3",
|
||||
"@types/semver": "^7.7.0",
|
||||
"big-integer": "^1.6.52",
|
||||
"bootstrap": "^4.6.2",
|
||||
"bootstrap": "^5.3.5",
|
||||
"buffer": "^6.0.3",
|
||||
"chart.js": "^4.4.9",
|
||||
"clipboard": "^2.0.11",
|
||||
@@ -48,7 +49,6 @@
|
||||
"nopt": "^8.1.0",
|
||||
"p-queue": "^8.1.0",
|
||||
"path-browserify": "^1.0.1",
|
||||
"popper.js": "^1.16.1",
|
||||
"profanities": "^3.0.1",
|
||||
"prom-client": "^15.1.3",
|
||||
"pug": "^3.0.3",
|
||||
@@ -3135,7 +3135,6 @@
|
||||
"version": "2.11.8",
|
||||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
|
||||
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
@@ -5773,9 +5772,9 @@
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/bootstrap": {
|
||||
"version": "4.6.2",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.6.2.tgz",
|
||||
"integrity": "sha512-51Bbp/Uxr9aTuy6ca/8FbFloBUJZLHwnhTcnjIeRn2suQWsWzcuJhGjKDB5eppVte/8oCdOL3VuwxvZDUggwGQ==",
|
||||
"version": "5.3.5",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.5.tgz",
|
||||
"integrity": "sha512-ct1CHKtiobRimyGzmsSldEtM03E8fcEX4Tb3dGXz1V8faRwM50+vfHwTzOxB3IlKO7m+9vTH3s/3C6T2EAPeTA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
@@ -5788,8 +5787,7 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"jquery": "1.9.1 - 3",
|
||||
"popper.js": "^1.16.1"
|
||||
"@popperjs/core": "^2.11.8"
|
||||
}
|
||||
},
|
||||
"node_modules/bowser": {
|
||||
@@ -10767,17 +10765,6 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/popper.js": {
|
||||
"version": "1.16.1",
|
||||
"resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz",
|
||||
"integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==",
|
||||
"deprecated": "You can find the new Popper v2 at @popperjs/core, this package is dedicated to the legacy v1",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/popperjs"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.5.3",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz",
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
"@sentry/node": "^7.120.3",
|
||||
"@types/semver": "^7.7.0",
|
||||
"big-integer": "^1.6.52",
|
||||
"bootstrap": "^4.6.2",
|
||||
"bootstrap": "^5.3.5",
|
||||
"buffer": "^6.0.3",
|
||||
"chart.js": "^4.4.9",
|
||||
"clipboard": "^2.0.11",
|
||||
@@ -57,7 +57,7 @@
|
||||
"nopt": "^8.1.0",
|
||||
"p-queue": "^8.1.0",
|
||||
"path-browserify": "^1.0.1",
|
||||
"popper.js": "^1.16.1",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"profanities": "^3.0.1",
|
||||
"prom-client": "^15.1.3",
|
||||
"pug": "^3.0.3",
|
||||
|
||||
471
static/bootstrap-utils.ts
Normal file
471
static/bootstrap-utils.ts
Normal file
@@ -0,0 +1,471 @@
|
||||
// Copyright (c) 2025, Compiler Explorer Authors
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
/**
|
||||
* TEMPORARY COMPATIBILITY LAYER
|
||||
*
|
||||
* This module provides utilities to help transition from Bootstrap 4's jQuery-based API
|
||||
* to Bootstrap 5's vanilla JavaScript API. This is intended as a temporary solution
|
||||
* during the migration from Bootstrap 4 to 5 and should be removed once the migration
|
||||
* is complete.
|
||||
*
|
||||
* The goal is to minimize changes throughout the codebase by centralizing the Bootstrap
|
||||
* API changes in this file, while still allowing for gradual migration to direct API calls.
|
||||
*
|
||||
* @deprecated This module should be removed after the Bootstrap 5 migration is complete.
|
||||
*/
|
||||
|
||||
import $ from 'jquery';
|
||||
|
||||
import 'bootstrap';
|
||||
import {Collapse, Dropdown, Modal, Popover, Tab, Toast, Tooltip} from 'bootstrap';
|
||||
|
||||
// Private event listener tracking map
|
||||
const eventListenerMap = new WeakMap<HTMLElement, Map<string, EventListener>>();
|
||||
|
||||
/**
|
||||
* Helper method to get an HTMLElement from various input types
|
||||
* @param elementOrSelector Element, jQuery object, or selector
|
||||
* @returns HTMLElement or null
|
||||
*/
|
||||
function getElement(elementOrSelector: string | HTMLElement | JQuery): HTMLElement | null {
|
||||
if (!elementOrSelector) return null;
|
||||
|
||||
if (typeof elementOrSelector === 'string') {
|
||||
return document.querySelector(elementOrSelector as string);
|
||||
}
|
||||
|
||||
if (elementOrSelector instanceof HTMLElement) {
|
||||
return elementOrSelector;
|
||||
}
|
||||
|
||||
if (elementOrSelector instanceof $) {
|
||||
return (elementOrSelector as JQuery)[0] as HTMLElement;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Private helper that sets an event handler on a single DOM element
|
||||
* Handles the removal of existing handlers and tracking of the new one
|
||||
*
|
||||
* @param domElement The DOM element to attach the event to
|
||||
* @param eventName The event name (e.g., 'hidden.bs.modal', 'shown.bs.modal', 'click', etc.)
|
||||
* @param handler The event handler function
|
||||
*/
|
||||
function setDomElementEventHandler(domElement: HTMLElement, eventName: string, handler: (event: Event) => void): void {
|
||||
// Initialize nested map structure if needed
|
||||
if (!eventListenerMap.has(domElement)) {
|
||||
eventListenerMap.set(domElement, new Map());
|
||||
}
|
||||
|
||||
const elementEvents = eventListenerMap.get(domElement)!;
|
||||
|
||||
// Remove existing handler if present
|
||||
if (elementEvents.has(eventName)) {
|
||||
const oldHandler = elementEvents.get(eventName)!;
|
||||
domElement.removeEventListener(eventName, oldHandler);
|
||||
}
|
||||
|
||||
// Store and add new handler
|
||||
elementEvents.set(eventName, handler);
|
||||
domElement.addEventListener(eventName, handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers an event handler on element(s), removing any previous handler for the same event
|
||||
* Similar to jQuery's off().on() pattern
|
||||
* Works with both single elements and jQuery collections with multiple elements
|
||||
*
|
||||
* @param element The element(s) or jQuery object to attach the event to
|
||||
* @param eventName The event name (e.g., 'hidden.bs.modal', 'shown.bs.modal', 'click', etc.)
|
||||
* @param handler The event handler function
|
||||
*/
|
||||
export function setElementEventHandler(
|
||||
element: JQuery<HTMLElement> | HTMLElement,
|
||||
eventName: string,
|
||||
handler: (event: Event) => void,
|
||||
): void {
|
||||
// If jQuery object with potentially multiple elements
|
||||
if (!(element instanceof HTMLElement)) {
|
||||
// Loop through all elements in the jQuery collection
|
||||
element.each((_index, domElement) => {
|
||||
setDomElementEventHandler(domElement, eventName, handler);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise it's a single DOM element
|
||||
setDomElementEventHandler(element, eventName, handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a modal
|
||||
* @param elementOrSelector Element or selector for the modal
|
||||
* @param options Modal options
|
||||
* @returns Modal instance
|
||||
* @throws Error if the element cannot be found
|
||||
*/
|
||||
export function initModal(elementOrSelector: string | HTMLElement | JQuery, options?: Partial<Modal.Options>): Modal {
|
||||
const element = getElement(elementOrSelector);
|
||||
if (!element) throw new Error(`Failed to find element for modal: ${elementOrSelector}`);
|
||||
|
||||
return new Modal(element, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a modal if the element exists, returning null otherwise
|
||||
* @param elementOrSelector Element or selector for the modal
|
||||
* @param options Modal options
|
||||
* @returns Modal instance or null if the element cannot be found
|
||||
*/
|
||||
export function initModalIfExists(
|
||||
elementOrSelector: string | HTMLElement | JQuery,
|
||||
options?: Partial<Modal.Options>,
|
||||
): Modal | null {
|
||||
const element = getElement(elementOrSelector);
|
||||
if (!element) return null;
|
||||
|
||||
return new Modal(element, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an existing modal instance for an element
|
||||
* @param elementOrSelector Element or selector for the modal
|
||||
* @returns Existing modal instance or null if not found
|
||||
*/
|
||||
export function getModalInstance(elementOrSelector: string | HTMLElement | JQuery): Modal | null {
|
||||
const element = getElement(elementOrSelector);
|
||||
if (!element) return null;
|
||||
|
||||
return Modal.getInstance(element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a modal
|
||||
* @param elementOrSelector Element or selector for the modal
|
||||
* @param relatedTarget Optional related target element
|
||||
*/
|
||||
export function showModal(elementOrSelector: string | HTMLElement | JQuery, relatedTarget?: HTMLElement): void {
|
||||
const element = getElement(elementOrSelector);
|
||||
if (!element) return;
|
||||
|
||||
const modal = Modal.getInstance(element) || new Modal(element);
|
||||
modal.show(relatedTarget);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide a modal
|
||||
* @param elementOrSelector Element or selector for the modal
|
||||
*/
|
||||
export function hideModal(elementOrSelector: string | HTMLElement | JQuery): void {
|
||||
const element = getElement(elementOrSelector);
|
||||
if (!element) return;
|
||||
|
||||
const modal = Modal.getInstance(element);
|
||||
if (modal) modal.hide();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a toast
|
||||
* @param elementOrSelector Element or selector for the toast
|
||||
* @param options Toast options
|
||||
* @returns Toast instance
|
||||
*/
|
||||
export function initToast(elementOrSelector: string | HTMLElement | JQuery, options?: Partial<Toast.Options>): Toast {
|
||||
const element = getElement(elementOrSelector);
|
||||
if (!element) throw new Error(`Failed to find element for toast: ${elementOrSelector}`);
|
||||
|
||||
return new Toast(element, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a toast if the element exists
|
||||
* @param elementOrSelector Element or selector for the toast
|
||||
* @param options Toast options
|
||||
* @returns Toast instance or null if element doesn't exist
|
||||
*/
|
||||
export function initToastIfExists(
|
||||
elementOrSelector: string | HTMLElement | JQuery,
|
||||
options?: Partial<Toast.Options>,
|
||||
): Toast | null {
|
||||
const element = getElement(elementOrSelector);
|
||||
if (!element) return null;
|
||||
|
||||
return new Toast(element, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a toast
|
||||
* @param elementOrSelector Element or selector for the toast
|
||||
*/
|
||||
export function showToast(elementOrSelector: string | HTMLElement | JQuery): void {
|
||||
const element = getElement(elementOrSelector);
|
||||
if (!element) return;
|
||||
|
||||
const toast = Toast.getInstance(element) || new Toast(element);
|
||||
toast.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide a toast
|
||||
* @param elementOrSelector Element or selector for the toast
|
||||
*/
|
||||
export function hideToast(elementOrSelector: string | HTMLElement | JQuery): void {
|
||||
const element = getElement(elementOrSelector);
|
||||
if (!element) return;
|
||||
|
||||
const toast = Toast.getInstance(element);
|
||||
if (toast) toast.hide();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a dropdown
|
||||
* @param elementOrSelector Element or selector for the dropdown
|
||||
* @param options Dropdown options
|
||||
* @returns Dropdown instance
|
||||
* @throws Error if the element cannot be found
|
||||
*/
|
||||
export function initDropdown(
|
||||
elementOrSelector: string | HTMLElement | JQuery,
|
||||
options?: Partial<Dropdown.Options>,
|
||||
): Dropdown {
|
||||
const element = getElement(elementOrSelector);
|
||||
if (!element) throw new Error(`Failed to find element for dropdown: ${elementOrSelector}`);
|
||||
|
||||
return new Dropdown(element, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a dropdown if the element exists, returning null otherwise
|
||||
* @param elementOrSelector Element or selector for the dropdown
|
||||
* @param options Dropdown options
|
||||
* @returns Dropdown instance or null if the element cannot be found
|
||||
*/
|
||||
export function initDropdownIfExists(
|
||||
elementOrSelector: string | HTMLElement | JQuery,
|
||||
options?: Partial<Dropdown.Options>,
|
||||
): Dropdown | null {
|
||||
const element = getElement(elementOrSelector);
|
||||
if (!element) return null;
|
||||
|
||||
return new Dropdown(element, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an existing dropdown instance for an element
|
||||
* @param elementOrSelector Element or selector for the dropdown
|
||||
* @returns Existing dropdown instance or null if not found
|
||||
*/
|
||||
export function getDropdownInstance(elementOrSelector: string | HTMLElement | JQuery): Dropdown | null {
|
||||
const element = getElement(elementOrSelector);
|
||||
if (!element) return null;
|
||||
|
||||
return Dropdown.getInstance(element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a dropdown
|
||||
* @param elementOrSelector Element or selector for the dropdown
|
||||
*/
|
||||
export function showDropdown(elementOrSelector: string | HTMLElement | JQuery): void {
|
||||
const element = getElement(elementOrSelector);
|
||||
if (!element) return;
|
||||
|
||||
const dropdown = Dropdown.getInstance(element) || new Dropdown(element);
|
||||
dropdown.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide a dropdown
|
||||
* @param elementOrSelector Element or selector for the dropdown
|
||||
*/
|
||||
export function hideDropdown(elementOrSelector: string | HTMLElement | JQuery): void {
|
||||
const element = getElement(elementOrSelector);
|
||||
if (!element) return;
|
||||
|
||||
const dropdown = Dropdown.getInstance(element);
|
||||
if (dropdown) dropdown.hide();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a tooltip
|
||||
* @param elementOrSelector Element or selector for the tooltip
|
||||
* @param options Tooltip options
|
||||
* @returns Tooltip instance
|
||||
*/
|
||||
export function initTooltip(
|
||||
elementOrSelector: string | HTMLElement | JQuery,
|
||||
options?: Partial<Tooltip.Options>,
|
||||
): Tooltip {
|
||||
const element = getElement(elementOrSelector);
|
||||
if (!element) throw new Error(`Failed to find element for tooltip: ${elementOrSelector}`);
|
||||
|
||||
return new Tooltip(element, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a tooltip if the element exists
|
||||
* @param elementOrSelector Element or selector for the tooltip
|
||||
* @param options Tooltip options
|
||||
* @returns Tooltip instance or null if element doesn't exist
|
||||
*/
|
||||
export function initTooltipIfExists(
|
||||
elementOrSelector: string | HTMLElement | JQuery,
|
||||
options?: Partial<Tooltip.Options>,
|
||||
): Tooltip | null {
|
||||
const element = getElement(elementOrSelector);
|
||||
if (!element) return null;
|
||||
|
||||
return new Tooltip(element, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a popover
|
||||
* @param elementOrSelector Element or selector for the popover
|
||||
* @param options Popover options
|
||||
* @returns Popover instance
|
||||
* @throws Error if the element cannot be found
|
||||
*/
|
||||
export function initPopover(
|
||||
elementOrSelector: string | HTMLElement | JQuery,
|
||||
options?: Partial<Popover.Options>,
|
||||
): Popover {
|
||||
const element = getElement(elementOrSelector);
|
||||
if (!element) throw new Error(`Failed to find element for popover: ${elementOrSelector}`);
|
||||
|
||||
return new Popover(element, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a popover if the element exists, returning null otherwise
|
||||
* @param elementOrSelector Element or selector for the popover
|
||||
* @param options Popover options
|
||||
* @returns Popover instance or null if the element cannot be found
|
||||
*/
|
||||
export function initPopoverIfExists(
|
||||
elementOrSelector: string | HTMLElement | JQuery,
|
||||
options?: Partial<Popover.Options>,
|
||||
): Popover | null {
|
||||
const element = getElement(elementOrSelector);
|
||||
if (!element) return null;
|
||||
|
||||
return new Popover(element, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an existing popover instance for an element
|
||||
* @param elementOrSelector Element or selector for the popover
|
||||
* @returns Existing popover instance or null if not found
|
||||
*/
|
||||
export function getPopoverInstance(elementOrSelector: string | HTMLElement | JQuery): Popover | null {
|
||||
const element = getElement(elementOrSelector);
|
||||
if (!element) return null;
|
||||
|
||||
return Popover.getInstance(element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a tab
|
||||
* @param elementOrSelector Element or selector for the tab
|
||||
* @returns Tab instance
|
||||
*/
|
||||
export function initTab(elementOrSelector: string | HTMLElement | JQuery): Tab {
|
||||
const element = getElement(elementOrSelector);
|
||||
if (!element) throw new Error(`Failed to find element for tab: ${elementOrSelector}`);
|
||||
|
||||
return new Tab(element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a tab if the element exists
|
||||
* @param elementOrSelector Element or selector for the tab
|
||||
* @returns Tab instance or null if element doesn't exist
|
||||
*/
|
||||
export function initTabIfExists(elementOrSelector: string | HTMLElement | JQuery): Tab | null {
|
||||
const element = getElement(elementOrSelector);
|
||||
if (!element) return null;
|
||||
|
||||
return new Tab(element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a collapse
|
||||
* @param elementOrSelector Element or selector for the collapse
|
||||
* @param options Collapse options
|
||||
* @returns Collapse instance
|
||||
*/
|
||||
export function initCollapse(
|
||||
elementOrSelector: string | HTMLElement | JQuery,
|
||||
options?: Partial<Collapse.Options>,
|
||||
): Collapse {
|
||||
const element = getElement(elementOrSelector);
|
||||
if (!element) throw new Error(`Failed to find element for collapse: ${elementOrSelector}`);
|
||||
|
||||
return new Collapse(element, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a collapse if the element exists
|
||||
* @param elementOrSelector Element or selector for the collapse
|
||||
* @param options Collapse options
|
||||
* @returns Collapse instance or null if element doesn't exist
|
||||
*/
|
||||
export function initCollapseIfExists(
|
||||
elementOrSelector: string | HTMLElement | JQuery,
|
||||
options?: Partial<Collapse.Options>,
|
||||
): Collapse | null {
|
||||
const element = getElement(elementOrSelector);
|
||||
if (!element) return null;
|
||||
|
||||
return new Collapse(element, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide an existing popover if it exists
|
||||
* @param elementOrSelector Element or selector for the popover
|
||||
*/
|
||||
export function hidePopover(elementOrSelector: string | HTMLElement | JQuery): void {
|
||||
const popover = getPopoverInstance(elementOrSelector);
|
||||
if (popover) popover.hide();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show an existing popover if it exists
|
||||
* @param elementOrSelector Element or selector for the popover
|
||||
*/
|
||||
export function showPopover(elementOrSelector: string | HTMLElement | JQuery): void {
|
||||
const popover = getPopoverInstance(elementOrSelector);
|
||||
if (popover) popover.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show an existing modal if it exists (uses existing instance only)
|
||||
* @param elementOrSelector Element or selector for the modal
|
||||
*/
|
||||
export function showModalIfExists(elementOrSelector: string | HTMLElement | JQuery): void {
|
||||
const modal = getModalInstance(elementOrSelector);
|
||||
if (modal) modal.show();
|
||||
}
|
||||
@@ -28,7 +28,7 @@ import {SentryCapture, SetupSentry, setSentryLayout} from './sentry.js';
|
||||
SetupSentry();
|
||||
|
||||
import 'whatwg-fetch';
|
||||
import 'popper.js';
|
||||
import '@popperjs/core';
|
||||
import 'bootstrap';
|
||||
|
||||
import $ from 'jquery';
|
||||
@@ -62,6 +62,7 @@ import {ComponentConfig, EmptyCompilerState, StateWithId, StateWithLanguage} fro
|
||||
import {CompilerExplorerOptions} from './global.js';
|
||||
|
||||
import * as utils from '../shared/common-utils.js';
|
||||
import * as BootstrapUtils from './bootstrap-utils.js';
|
||||
import {ParseFiltersAndOutputOptions} from './features/filters.interfaces.js';
|
||||
import {localStorage, sessionThenLocalStorage} from './local.js';
|
||||
import {Printerinator} from './print-view.js';
|
||||
@@ -79,7 +80,7 @@ if (!window.PRODUCTION && !options.embedded) {
|
||||
//css
|
||||
require('bootstrap/dist/css/bootstrap.min.css');
|
||||
require('golden-layout/src/css/goldenlayout-base.css');
|
||||
require('tom-select/dist/css/tom-select.bootstrap4.css');
|
||||
require('tom-select/dist/css/tom-select.bootstrap5.css');
|
||||
require('./styles/colours.scss');
|
||||
require('./styles/explorer.scss');
|
||||
|
||||
@@ -225,7 +226,7 @@ function setupButtons(options: CompilerExplorerOptions, hub: Hub) {
|
||||
window.location.reload();
|
||||
});
|
||||
|
||||
$('#history').modal();
|
||||
BootstrapUtils.showModal('#history');
|
||||
});
|
||||
|
||||
$('#ui-apply-default-font-scale').on('click', () => {
|
||||
@@ -530,7 +531,7 @@ function initShortlinkInfoButton() {
|
||||
buttonText.html('');
|
||||
|
||||
const button = $('.shortlinkInfo');
|
||||
button.popover({
|
||||
BootstrapUtils.initPopover(button, {
|
||||
html: true,
|
||||
title: 'Link created',
|
||||
content: formatISODate(dt, true),
|
||||
@@ -677,11 +678,13 @@ function start() {
|
||||
setupButtons(options, hub);
|
||||
}
|
||||
|
||||
const addDropdown = $('#addDropdown');
|
||||
|
||||
function setupAdd<C>(thing: JQuery, func: () => ComponentConfig<C>) {
|
||||
(layout.createDragSource(thing, func as any) as any)._dragListener.on('dragStart', () => {
|
||||
addDropdown.dropdown('toggle');
|
||||
const addDropdown = unwrap(
|
||||
BootstrapUtils.getDropdownInstance('#addDropdown'),
|
||||
'Dropdown instance not found for #addDropdown',
|
||||
);
|
||||
addDropdown.toggle();
|
||||
});
|
||||
|
||||
thing.on('click', () => {
|
||||
|
||||
@@ -30,7 +30,7 @@ function ensureShownMessage(message: string, motdNode: JQuery) {
|
||||
motdNode.find('.content').html(message);
|
||||
motdNode.removeClass('d-none');
|
||||
motdNode
|
||||
.find('.close')
|
||||
.find('.btn-close')
|
||||
.on('click', () => {
|
||||
motdNode.addClass('d-none');
|
||||
})
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
// This jQuery import needs to be here, because noscript.ts is a different entrypoint than the rest of the code.
|
||||
// See webpack.config.esm.ts -> entry for more details.
|
||||
import $ from 'jquery';
|
||||
import '@popperjs/core';
|
||||
import 'bootstrap';
|
||||
import 'popper.js';
|
||||
|
||||
import {Toggles} from './widgets/toggles.js';
|
||||
import './styles/noscript.scss';
|
||||
|
||||
@@ -26,6 +26,7 @@ import * as fileSaver from 'file-saver';
|
||||
import $ from 'jquery';
|
||||
import * as monaco from 'monaco-editor';
|
||||
import _ from 'underscore';
|
||||
import * as BootstrapUtils from '../bootstrap-utils.js';
|
||||
import {Pane} from './pane.js';
|
||||
|
||||
import {Container} from 'golden-layout';
|
||||
@@ -281,7 +282,9 @@ export class Cfg extends Pane<CfgState> {
|
||||
if (this.tooltipOpen) {
|
||||
if (!e.target.classList.contains('fold') && $(e.target).parents('.popover.in').length === 0) {
|
||||
this.tooltipOpen = false;
|
||||
$('.fold').popover('hide');
|
||||
$('.fold').each((_, element) => {
|
||||
BootstrapUtils.hidePopover(element);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -389,9 +392,10 @@ export class Cfg extends Pane<CfgState> {
|
||||
}" aria-describedby="wtf">⋯</span>`;
|
||||
}
|
||||
div.innerHTML = lines.join('<br/>');
|
||||
for (const fold of div.getElementsByClassName('fold')) {
|
||||
$(fold)
|
||||
.popover({
|
||||
for (const foldElement of div.getElementsByClassName('fold')) {
|
||||
const fold = foldElement as HTMLElement;
|
||||
|
||||
BootstrapUtils.initPopover(fold, {
|
||||
content: unwrap(fold.getAttribute('data-extra')),
|
||||
html: true,
|
||||
placement: 'top',
|
||||
@@ -401,11 +405,12 @@ export class Cfg extends Pane<CfgState> {
|
||||
'<h3 class="popover-header"></h3>' +
|
||||
'<div class="popover-body"></div>' +
|
||||
'</div>',
|
||||
})
|
||||
.on('show.bs.popover', () => {
|
||||
});
|
||||
|
||||
BootstrapUtils.setElementEventHandler(fold, 'show.bs.popover', () => {
|
||||
this.tooltipOpen = true;
|
||||
})
|
||||
.on('hide.bs.popover', () => {
|
||||
});
|
||||
BootstrapUtils.setElementEventHandler(fold, 'hide.bs.popover', () => {
|
||||
this.tooltipOpen = false;
|
||||
});
|
||||
}
|
||||
@@ -500,7 +505,11 @@ export class Cfg extends Pane<CfgState> {
|
||||
// Display the cfg for the specified function if it exists
|
||||
// This function sets this.state.selectedFunction if the input is non-null and valid
|
||||
async selectFunction(name: string | null) {
|
||||
$('.fold').popover('dispose');
|
||||
$('.fold').each((_, element) => {
|
||||
const popover = BootstrapUtils.getPopoverInstance(element);
|
||||
if (popover) popover.dispose();
|
||||
// We need to dispose here, not just hide
|
||||
});
|
||||
this.blockContainer.innerHTML = '';
|
||||
this.svg.innerHTML = '';
|
||||
this.estimatedPNGSize.innerHTML = '';
|
||||
@@ -669,7 +678,9 @@ export class Cfg extends Pane<CfgState> {
|
||||
const topBarHeight = utils.updateAndCalcTopBarHeight(this.domRoot, this.topBar, this.hideable);
|
||||
this.graphContainer.style.width = `${unwrap(this.domRoot.width())}px`;
|
||||
this.graphContainer.style.height = `${unwrap(this.domRoot.height()) - topBarHeight}px`;
|
||||
$('.fold').popover('hide');
|
||||
$('.fold').each((_, element) => {
|
||||
BootstrapUtils.hidePopover(element);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ import {
|
||||
import {CompilerInfo} from '../../types/compiler.interfaces.js';
|
||||
import {ResultLine} from '../../types/resultline/resultline.interfaces.js';
|
||||
import {getAssemblyDocumentation} from '../api/api.js';
|
||||
import * as BootstrapUtils from '../bootstrap-utils.js';
|
||||
import * as codeLensHandler from '../codelens-handler.js';
|
||||
import * as colour from '../colour.js';
|
||||
import {OptPipelineBackendOptions} from '../compilation/opt-pipeline-output.interfaces.js';
|
||||
@@ -678,7 +679,7 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
|
||||
|
||||
const newPaneDropdown = this.domRoot.find('.new-pane-dropdown');
|
||||
const hidePaneAdder = () => {
|
||||
newPaneDropdown.dropdown('hide');
|
||||
BootstrapUtils.hideDropdown(newPaneDropdown);
|
||||
};
|
||||
|
||||
// Note that the .d.ts file lies in more than 1 way!
|
||||
@@ -729,7 +730,7 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
|
||||
.createDragSource(this.flagsButton, createFlagsView as any)
|
||||
|
||||
// @ts-ignore
|
||||
._dragListener.on('dragStart', () => popularArgumentsMenu.dropdown('hide'));
|
||||
._dragListener.on('dragStart', () => BootstrapUtils.hideDropdown(popularArgumentsMenu));
|
||||
|
||||
this.flagsButton.on('click', () => {
|
||||
const insertPoint =
|
||||
@@ -1868,7 +1869,7 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
|
||||
dismissTime: 10000,
|
||||
onBeforeShow: elem => {
|
||||
elem.find('#miracle_emulink').on('click', () => {
|
||||
dialog.modal();
|
||||
BootstrapUtils.showModal(dialog);
|
||||
|
||||
const miracleMenuFrame = dialog.find('#miracleemuframe')[0];
|
||||
assert(miracleMenuFrame instanceof HTMLIFrameElement);
|
||||
@@ -1896,7 +1897,7 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
|
||||
dismissTime: 10000,
|
||||
onBeforeShow: elem => {
|
||||
elem.find('#jsspeccy_emulink').on('click', () => {
|
||||
dialog.modal();
|
||||
BootstrapUtils.showModal(dialog);
|
||||
|
||||
const speccyemuframe = dialog.find('#speccyemuframe')[0];
|
||||
assert(speccyemuframe instanceof HTMLIFrameElement);
|
||||
@@ -1923,7 +1924,7 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
|
||||
dismissTime: 10000,
|
||||
onBeforeShow: elem => {
|
||||
elem.find('#emulink').on('click', () => {
|
||||
dialog.modal();
|
||||
BootstrapUtils.showModal(dialog);
|
||||
|
||||
const jsbeebemuframe = dialog.find('#jsbeebemuframe')[0];
|
||||
assert(jsbeebemuframe instanceof HTMLIFrameElement);
|
||||
@@ -1950,7 +1951,7 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
|
||||
dismissTime: 10000,
|
||||
onBeforeShow: elem => {
|
||||
elem.find('#emulink').on('click', () => {
|
||||
dialog.modal();
|
||||
BootstrapUtils.showModal(dialog);
|
||||
|
||||
const jsnesemuframe = dialog.find('#jsnesemuframe')[0];
|
||||
assert(jsnesemuframe instanceof HTMLIFrameElement);
|
||||
@@ -2683,7 +2684,7 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
|
||||
initToolButtons(): void {
|
||||
this.toolsMenu = this.domRoot.find('.new-tool-dropdown');
|
||||
const hideToolDropdown = () => {
|
||||
this.toolsMenu?.dropdown('hide');
|
||||
if (this.toolsMenu) BootstrapUtils.hideDropdown(this.toolsMenu);
|
||||
};
|
||||
this.toolsMenu.empty();
|
||||
|
||||
@@ -3053,14 +3054,14 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
|
||||
this.prependOptions.has(target as unknown as Element).length === 0 &&
|
||||
target.closest('.popover').length === 0
|
||||
)
|
||||
this.prependOptions.popover('hide');
|
||||
BootstrapUtils.hidePopover(this.prependOptions);
|
||||
|
||||
if (
|
||||
!target.is(this.fullCompilerName) &&
|
||||
this.fullCompilerName.has(target as unknown as Element).length === 0 &&
|
||||
target.closest('.popover').length === 0
|
||||
)
|
||||
this.fullCompilerName.popover('hide');
|
||||
BootstrapUtils.hidePopover(this.fullCompilerName);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3104,7 +3105,7 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
|
||||
// Dismiss the popover on escape.
|
||||
$(document).on('keyup.editable', e => {
|
||||
if (e.which === 27) {
|
||||
this.libsButton.popover('hide');
|
||||
BootstrapUtils.hidePopover(this.libsButton);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -3118,7 +3119,7 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
|
||||
elem.has(target as unknown as Element).length === 0 &&
|
||||
target.closest('.popover').length === 0
|
||||
) {
|
||||
elem.popover('hide');
|
||||
BootstrapUtils.hidePopover(elem);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -3460,8 +3461,13 @@ export class Compiler extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Co
|
||||
setCompilationOptionsPopover(content: string | null, warnings: string[]): void {
|
||||
const infoLine =
|
||||
'<div class="compiler-arg-warning info">You can configure icon animations in Settings>Compilation</div>\n';
|
||||
this.prependOptions.popover('dispose');
|
||||
this.prependOptions.popover({
|
||||
|
||||
// Dispose any existing popover
|
||||
const existingPopover = BootstrapUtils.getPopoverInstance(this.prependOptions);
|
||||
if (existingPopover) existingPopover.dispose();
|
||||
|
||||
// Create new popover
|
||||
BootstrapUtils.initPopover(this.prependOptions, {
|
||||
content:
|
||||
warnings.map(w => `<div class="compiler-arg-warning">${w}</div>`).join('\n') +
|
||||
'\n' +
|
||||
|
||||
@@ -29,6 +29,7 @@ import {escapeHTML, unique} from '../../shared/common-utils.js';
|
||||
import {CompilationResult} from '../../types/compilation/compilation.interfaces.js';
|
||||
import {CompilerInfo} from '../../types/compiler.interfaces.js';
|
||||
import {unwrapString} from '../assert.js';
|
||||
import * as BootstrapUtils from '../bootstrap-utils.js';
|
||||
import {CompilationStatus} from '../compiler-service.interfaces.js';
|
||||
import {CompilerService} from '../compiler-service.js';
|
||||
import * as Components from '../components.js';
|
||||
@@ -100,7 +101,7 @@ export class Conformance extends Pane<ConformanceViewState> {
|
||||
// Dismiss the popover on escape.
|
||||
$(document).on('keyup.editable', e => {
|
||||
if (e.which === 27) {
|
||||
this.libsButton.popover('hide');
|
||||
BootstrapUtils.hidePopover(this.libsButton);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -114,7 +115,7 @@ export class Conformance extends Pane<ConformanceViewState> {
|
||||
elem.has(target as unknown as Element).length === 0 &&
|
||||
target.closest('.popover').length === 0
|
||||
) {
|
||||
elem.popover('hide');
|
||||
BootstrapUtils.hidePopover(elem);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -150,7 +151,7 @@ export class Conformance extends Pane<ConformanceViewState> {
|
||||
this.conformanceContentRoot = this.domRoot.find('.conformance-wrapper');
|
||||
this.selectorList = this.domRoot.find('.compiler-list');
|
||||
this.addCompilerButton = this.domRoot.find('.add-compiler');
|
||||
this.selectorTemplate = $('#compiler-selector').find('.form-row');
|
||||
this.selectorTemplate = $('#compiler-selector').find('.row');
|
||||
this.topBar = this.domRoot.find('.top-bar');
|
||||
this.libsButton = this.topBar.find('.show-libs');
|
||||
this.hideable = this.domRoot.find('.hideable');
|
||||
@@ -225,15 +226,11 @@ export class Conformance extends Pane<ConformanceViewState> {
|
||||
.on('change', onOptionsChange)
|
||||
.on('keyup', onOptionsChange);
|
||||
|
||||
newSelector
|
||||
.find('.close')
|
||||
.not('.extract-compiler')
|
||||
.not('.copy-compiler')
|
||||
.on('click', () => {
|
||||
newSelector.find('.close-compiler').on('click', () => {
|
||||
this.removeCompilerPicker(newCompilerEntry);
|
||||
});
|
||||
|
||||
newSelector.find('.close.copy-compiler').on('click', () => {
|
||||
newSelector.find('.copy-compiler').on('click', () => {
|
||||
const config: AddCompilerPickerConfig = {
|
||||
compilerId: newCompilerEntry.picker?.lastCompilerId ?? '',
|
||||
options: newCompilerEntry.optionsField?.val() || '',
|
||||
@@ -301,8 +298,11 @@ export class Conformance extends Pane<ConformanceViewState> {
|
||||
): void {}
|
||||
|
||||
setCompilationOptionsPopover(element: JQuery<HTMLElement> | null, content: string): void {
|
||||
element?.popover('dispose');
|
||||
element?.popover({
|
||||
if (element) {
|
||||
const existingPopover = BootstrapUtils.getPopoverInstance(element);
|
||||
if (existingPopover) existingPopover.dispose();
|
||||
|
||||
BootstrapUtils.initPopover(element, {
|
||||
content: content || 'No options in use',
|
||||
template:
|
||||
'<div class="popover' +
|
||||
@@ -311,6 +311,7 @@ export class Conformance extends Pane<ConformanceViewState> {
|
||||
'<h3 class="popover-header"></h3><div class="popover-body"></div></div>',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
removeCompilerPicker(compilerEntry: CompilerEntry): void {
|
||||
this.compilerPickers = _.reject(this.compilerPickers, entry => compilerEntry.picker?.id === entry.picker?.id);
|
||||
|
||||
@@ -482,10 +482,7 @@ export class Diff extends MonacoPane<monaco.editor.IStandaloneDiffEditor, DiffSt
|
||||
) {
|
||||
if (!compiler) return;
|
||||
options = options || '';
|
||||
let name = compiler.name + ' ' + options;
|
||||
// TODO: tomselect doesn't play nicely with CSS tricks for truncation; this is the best I can do
|
||||
const maxLength = 30;
|
||||
if (name.length > maxLength - 3) name = name.substring(0, maxLength - 3) + '...';
|
||||
const name = compiler.name + ' ' + options;
|
||||
this.compilers[id] = {
|
||||
id: id,
|
||||
name: name,
|
||||
|
||||
@@ -29,6 +29,7 @@ import * as monaco from 'monaco-editor';
|
||||
import * as monacoVim from 'monaco-vim';
|
||||
import TomSelect from 'tom-select';
|
||||
import _ from 'underscore';
|
||||
import * as BootstrapUtils from '../bootstrap-utils.js';
|
||||
import * as colour from '../colour.js';
|
||||
import * as Components from '../components.js';
|
||||
import * as monacoConfig from '../monaco-config.js';
|
||||
@@ -472,7 +473,7 @@ export class Editor extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Edit
|
||||
}
|
||||
|
||||
enableVim(): void {
|
||||
const statusElem = this.domRoot.find('#v-status')[0];
|
||||
const statusElem = this.domRoot.find('.v-status')[0];
|
||||
const vimMode = monacoVim.initVimMode(this.editor, statusElem);
|
||||
this.vimMode = vimMode;
|
||||
this.vimFlag.prop('class', 'btn btn-info');
|
||||
@@ -481,7 +482,7 @@ export class Editor extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Edit
|
||||
|
||||
disableVim(): void {
|
||||
this.vimMode.dispose();
|
||||
this.domRoot.find('#v-status').html('');
|
||||
this.domRoot.find('.v-status').html('');
|
||||
this.vimFlag.prop('class', 'btn btn-light');
|
||||
(this.editor as any).vimInUse = false;
|
||||
}
|
||||
@@ -520,8 +521,8 @@ export class Editor extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Edit
|
||||
this.addExecutorButton = this.domRoot.find('.btn.add-executor');
|
||||
this.conformanceViewerButton = this.domRoot.find('.btn.conformance');
|
||||
const addEditorButton = this.domRoot.find('.btn.add-editor');
|
||||
const toggleVimButton = this.domRoot.find('#vim-flag');
|
||||
this.vimFlag = this.domRoot.find('#vim-flag');
|
||||
const toggleVimButton = this.domRoot.find('.vim-flag');
|
||||
this.vimFlag = this.domRoot.find('.vim-flag');
|
||||
toggleVimButton.on('click', () => {
|
||||
if ((this.editor as any).vimInUse) {
|
||||
this.disableVim();
|
||||
@@ -541,7 +542,7 @@ export class Editor extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Edit
|
||||
});
|
||||
|
||||
this.languageInfoButton = this.domRoot.find('.language-info');
|
||||
this.languageInfoButton.popover({});
|
||||
BootstrapUtils.initPopover(this.languageInfoButton);
|
||||
this.languageBtn = this.domRoot.find('.change-language');
|
||||
const changeLanguageButton = this.languageBtn[0];
|
||||
assert(changeLanguageButton instanceof HTMLSelectElement);
|
||||
@@ -598,7 +599,10 @@ export class Editor extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Edit
|
||||
.createDragSource(dragSource, dragConfig)
|
||||
// @ts-expect-error: createDragSource returns not void
|
||||
._dragListener.on('dragStart', () => {
|
||||
paneAdderDropdown.dropdown('toggle');
|
||||
const dropdown = BootstrapUtils.getDropdownInstance(paneAdderDropdown);
|
||||
if (dropdown) {
|
||||
dropdown.toggle();
|
||||
}
|
||||
});
|
||||
|
||||
dragSource.on('click', () => {
|
||||
@@ -1921,7 +1925,7 @@ export class Editor extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Edit
|
||||
): string {
|
||||
let result =
|
||||
'<div class="d-flex" style="align-items: center">' +
|
||||
'<div class="mr-1 d-flex" style="align-items: center">' +
|
||||
'<div class="me-1 d-flex" style="align-items: center">' +
|
||||
'<img src="' +
|
||||
(data.logoData ? data.logoData : '') +
|
||||
'" class="' +
|
||||
@@ -1961,9 +1965,12 @@ export class Editor extends MonacoPane<monaco.editor.IStandaloneCodeEditor, Edit
|
||||
onCompiler(compilerId: number, compiler: unknown, options: string, editorId: number, treeId: number): void {}
|
||||
|
||||
updateLanguageTooltip() {
|
||||
this.languageInfoButton.popover('dispose');
|
||||
// Dispose existing popover instance
|
||||
const existingPopover = BootstrapUtils.getPopoverInstance(this.languageInfoButton);
|
||||
if (existingPopover) existingPopover.dispose();
|
||||
|
||||
if (this.currentLanguage?.tooltip) {
|
||||
this.languageInfoButton.popover({
|
||||
BootstrapUtils.initPopover(this.languageInfoButton, {
|
||||
title: 'More info about this language',
|
||||
content: this.currentLanguage.tooltip,
|
||||
container: 'body',
|
||||
|
||||
@@ -38,6 +38,7 @@ import {Language} from '../../types/languages.interfaces.js';
|
||||
import {ResultLine} from '../../types/resultline/resultline.interfaces.js';
|
||||
import {Artifact, ArtifactType} from '../../types/tool.interfaces.js';
|
||||
import {Filter as AnsiToHtml} from '../ansi-to-html.js';
|
||||
import * as BootstrapUtils from '../bootstrap-utils.js';
|
||||
import {CompilationStatus as CompilerServiceCompilationStatus} from '../compiler-service.interfaces.js';
|
||||
import {CompilerService} from '../compiler-service.js';
|
||||
import {ICompilerShared} from '../compiler-shared.interfaces.js';
|
||||
@@ -799,15 +800,19 @@ export class Executor extends Pane<ExecutorState> {
|
||||
!target.is(this.prependOptions) &&
|
||||
this.prependOptions.has(target as any).length === 0 &&
|
||||
target.closest('.popover').length === 0
|
||||
)
|
||||
this.prependOptions.popover('hide');
|
||||
) {
|
||||
const popover = BootstrapUtils.getPopoverInstance(this.prependOptions);
|
||||
if (popover) popover.hide();
|
||||
}
|
||||
|
||||
if (
|
||||
!target.is(this.fullCompilerName) &&
|
||||
this.fullCompilerName.has(target as any).length === 0 &&
|
||||
target.closest('.popover').length === 0
|
||||
)
|
||||
this.fullCompilerName.popover('hide');
|
||||
) {
|
||||
const popover = BootstrapUtils.getPopoverInstance(this.fullCompilerName);
|
||||
if (popover) popover.hide();
|
||||
}
|
||||
});
|
||||
|
||||
this.optionsField.val(this.options);
|
||||
@@ -963,7 +968,8 @@ export class Executor extends Pane<ExecutorState> {
|
||||
// Dismiss the popover on escape.
|
||||
$(document).on('keyup.editable', e => {
|
||||
if (e.which === 27) {
|
||||
this.libsButton.popover('hide');
|
||||
const popover = BootstrapUtils.getPopoverInstance(this.libsButton);
|
||||
if (popover) popover.hide();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -997,7 +1003,8 @@ export class Executor extends Pane<ExecutorState> {
|
||||
const elem = this.libsButton;
|
||||
const target = $(e.target);
|
||||
if (!target.is(elem) && elem.has(target as any).length === 0 && target.closest('.popover').length === 0) {
|
||||
elem.popover('hide');
|
||||
const popover = BootstrapUtils.getPopoverInstance(elem);
|
||||
if (popover) popover.hide();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1186,8 +1193,12 @@ export class Executor extends Pane<ExecutorState> {
|
||||
}
|
||||
|
||||
setCompilationOptionsPopover(content: string | null) {
|
||||
this.prependOptions.popover('dispose');
|
||||
this.prependOptions.popover({
|
||||
// Dispose of existing popover
|
||||
const existingPopover = BootstrapUtils.getPopoverInstance(this.prependOptions);
|
||||
if (existingPopover) existingPopover.dispose();
|
||||
|
||||
// Initialize new popover
|
||||
BootstrapUtils.initPopover(this.prependOptions, {
|
||||
content: content || 'No options in use',
|
||||
template:
|
||||
'<div class="popover' +
|
||||
|
||||
@@ -29,6 +29,7 @@ import TomSelect from 'tom-select';
|
||||
import _ from 'underscore';
|
||||
import {escapeHTML} from '../../shared/common-utils.js';
|
||||
import {assert, unwrap, unwrapString} from '../assert.js';
|
||||
import * as BootstrapUtils from '../bootstrap-utils.js';
|
||||
import * as Components from '../components.js';
|
||||
import {EventHub} from '../event-hub.js';
|
||||
import {Hub} from '../hub.js';
|
||||
@@ -448,7 +449,11 @@ export class Tree {
|
||||
(this.container.layoutManager.createDragSource(dragSource, dragConfig.bind(this)) as any)._dragListener.on(
|
||||
'dragStart',
|
||||
() => {
|
||||
this.domRoot.find('.add-pane').dropdown('toggle');
|
||||
const dropdown = this.domRoot.find('.add-pane');
|
||||
const dropdownInstance = BootstrapUtils.getDropdownInstance(dropdown);
|
||||
if (dropdownInstance) {
|
||||
dropdownInstance.toggle();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ export function setupRealDark(hub: Hub) {
|
||||
$('#settings .theme').val('real-dark').trigger('change');
|
||||
}
|
||||
});
|
||||
$('#true-dark .content .close').on('click', e => {
|
||||
$('#true-dark .content .dark-close').on('click', e => {
|
||||
local.localStorage.set(localKey, 'hidden');
|
||||
toggleButton();
|
||||
toggleOverlay();
|
||||
|
||||
@@ -22,18 +22,20 @@
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import {Modal, Tooltip} from 'bootstrap';
|
||||
import ClipboardJS from 'clipboard';
|
||||
import GoldenLayout from 'golden-layout';
|
||||
import $ from 'jquery';
|
||||
import _ from 'underscore';
|
||||
import {unwrap} from './assert.js';
|
||||
import * as BootstrapUtils from './bootstrap-utils.js';
|
||||
import {sessionThenLocalStorage} from './local.js';
|
||||
import {options} from './options.js';
|
||||
import * as url from './url.js';
|
||||
|
||||
import ClickEvent = JQuery.ClickEvent;
|
||||
import TriggeredEvent = JQuery.TriggeredEvent;
|
||||
import {SentryCapture} from './sentry.js';
|
||||
import {Settings, SiteSettings} from './settings.js';
|
||||
import ClickEvent = JQuery.ClickEvent;
|
||||
|
||||
const cloneDeep = require('lodash.clonedeep');
|
||||
|
||||
@@ -87,24 +89,31 @@ export class Sharing {
|
||||
private layout: GoldenLayout;
|
||||
private lastState: any;
|
||||
|
||||
private share: JQuery;
|
||||
private shareShort: JQuery;
|
||||
private shareFull: JQuery;
|
||||
private shareEmbed: JQuery;
|
||||
private readonly share: JQuery;
|
||||
private readonly shareTooltipTarget: JQuery;
|
||||
private readonly shareShort: JQuery;
|
||||
private readonly shareFull: JQuery;
|
||||
private readonly shareEmbed: JQuery;
|
||||
|
||||
private settings: SiteSettings;
|
||||
|
||||
private clippyButton: ClipboardJS | null;
|
||||
private readonly shareLinkDialog: HTMLElement;
|
||||
|
||||
constructor(layout: any) {
|
||||
this.layout = layout;
|
||||
this.lastState = null;
|
||||
this.shareLinkDialog = unwrap(document.getElementById('sharelinkdialog'), 'Share modal element not found');
|
||||
|
||||
this.share = $('#share');
|
||||
this.shareTooltipTarget = $('#share-tooltip-target');
|
||||
this.shareShort = $('#shareShort');
|
||||
this.shareFull = $('#shareFull');
|
||||
this.shareEmbed = $('#shareEmbed');
|
||||
|
||||
[this.shareShort, this.shareFull, this.shareEmbed].forEach(el =>
|
||||
el.on('click', e => BootstrapUtils.showModal(this.shareLinkDialog, e.currentTarget)),
|
||||
);
|
||||
this.settings = Settings.getStoredSettings();
|
||||
|
||||
this.clippyButton = null;
|
||||
@@ -122,9 +131,9 @@ export class Sharing {
|
||||
});
|
||||
this.layout.on('stateChanged', this.onStateChanged.bind(this));
|
||||
|
||||
$('#sharelinkdialog')
|
||||
.on('show.bs.modal', this.onOpenModalPane.bind(this))
|
||||
.on('hidden.bs.modal', this.onCloseModalPane.bind(this));
|
||||
BootstrapUtils.initModal(this.shareLinkDialog);
|
||||
this.shareLinkDialog.addEventListener('show.bs.modal', this.onOpenModalPane.bind(this));
|
||||
this.shareLinkDialog.addEventListener('hidden.bs.modal', this.onCloseModalPane.bind(this));
|
||||
|
||||
this.layout.eventHub.on('settingsChange', (newSettings: SiteSettings) => {
|
||||
this.settings = newSettings;
|
||||
@@ -176,11 +185,16 @@ export class Sharing {
|
||||
}
|
||||
}
|
||||
|
||||
private onOpenModalPane(event: TriggeredEvent<HTMLElement, undefined, HTMLElement, HTMLElement>): void {
|
||||
// @ts-ignore The property is added by bootstrap
|
||||
const button = $(event.relatedTarget);
|
||||
const currentBind = Sharing.bindToLinkType(button.data('bind'));
|
||||
const modal = $(event.currentTarget);
|
||||
private onOpenModalPane(event: Event): void {
|
||||
const modalEvent = event as Modal.Event;
|
||||
if (!modalEvent.relatedTarget) {
|
||||
throw new Error('No relatedTarget found in modal event');
|
||||
}
|
||||
|
||||
const button = $(modalEvent.relatedTarget);
|
||||
const bindStr = button.data('bind') as string;
|
||||
const currentBind = Sharing.bindToLinkType(bindStr);
|
||||
const modal = $(event.currentTarget as HTMLElement);
|
||||
const socialSharingElements = modal.find('.socialsharing');
|
||||
const permalink = modal.find('.permalink');
|
||||
const embedsettings = modal.find('#embedsettings');
|
||||
@@ -262,15 +276,16 @@ export class Sharing {
|
||||
}
|
||||
}
|
||||
|
||||
private onClipButtonPressed(event: ClickEvent, type: LinkType): void {
|
||||
private onClipButtonPressed(event: ClickEvent, type: LinkType): boolean {
|
||||
// Don't let the modal show up.
|
||||
// We need this because the button is a child of the dropdown-item with a data-toggle=modal
|
||||
// We need this because the button is a child of the dropdown-item with a data-bs-toggle=modal
|
||||
if (Sharing.isNavigatorClipboardAvailable()) {
|
||||
event.stopPropagation();
|
||||
this.copyLinkTypeToClipboard(type);
|
||||
// As we prevented bubbling, the dropdown won't close by itself. We need to trigger it manually
|
||||
this.share.dropdown('hide');
|
||||
event.stopPropagation();
|
||||
// As we prevented bubbling, the dropdown won't close by itself.
|
||||
BootstrapUtils.hideDropdown(this.share);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private getLinkOfType(type: LinkType): Promise<string> {
|
||||
@@ -278,7 +293,7 @@ export class Sharing {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
Sharing.getLinks(config, type, (error: any, newUrl: string, extra: string, updateState: boolean) => {
|
||||
if (error || !newUrl) {
|
||||
this.displayTooltip(this.share, 'Oops, something went wrong');
|
||||
this.displayTooltip(this.shareTooltipTarget, 'Oops, something went wrong');
|
||||
SentryCapture(error, 'Getting short link failed');
|
||||
reject();
|
||||
} else {
|
||||
@@ -295,7 +310,7 @@ export class Sharing {
|
||||
const config = this.layout.toConfig();
|
||||
Sharing.getLinks(config, type, (error: any, newUrl: string, extra: string, updateState: boolean) => {
|
||||
if (error || !newUrl) {
|
||||
this.displayTooltip(this.share, 'Oops, something went wrong');
|
||||
this.displayTooltip(this.shareTooltipTarget, 'Oops, something went wrong');
|
||||
SentryCapture(error, 'Getting short link failed');
|
||||
} else {
|
||||
if (updateState) {
|
||||
@@ -306,16 +321,33 @@ export class Sharing {
|
||||
});
|
||||
}
|
||||
|
||||
// TODO we can consider using bootstrap's "Toast" support in future.
|
||||
private displayTooltip(where: JQuery, message: string): void {
|
||||
where.tooltip('dispose');
|
||||
where.tooltip({
|
||||
// First dispose any existing tooltip
|
||||
const tooltipEl = where[0];
|
||||
if (!tooltipEl) return;
|
||||
|
||||
const existingTooltip = Tooltip.getInstance(tooltipEl);
|
||||
if (existingTooltip) {
|
||||
existingTooltip.dispose();
|
||||
}
|
||||
|
||||
// Create and show new tooltip
|
||||
try {
|
||||
const tooltip = BootstrapUtils.initTooltip(tooltipEl, {
|
||||
placement: 'bottom',
|
||||
trigger: 'manual',
|
||||
title: message,
|
||||
});
|
||||
where.tooltip('show');
|
||||
|
||||
tooltip.show();
|
||||
|
||||
// Manual triggering of tooltips does not hide them automatically. This timeout ensures they do
|
||||
setTimeout(() => where.tooltip('hide'), 1500);
|
||||
setTimeout(() => tooltip.hide(), 1500);
|
||||
} catch (e) {
|
||||
// If element doesn't exist, just silently fail
|
||||
console.warn('Could not show tooltip:', e);
|
||||
}
|
||||
}
|
||||
|
||||
private openShareModalForType(type: LinkType): void {
|
||||
@@ -336,7 +368,7 @@ export class Sharing {
|
||||
if (Sharing.isNavigatorClipboardAvailable()) {
|
||||
navigator.clipboard
|
||||
.writeText(link)
|
||||
.then(() => this.displayTooltip(this.share, 'Link copied to clipboard'))
|
||||
.then(() => this.displayTooltip(this.shareTooltipTarget, 'Link copied to clipboard'))
|
||||
.catch(() => this.openShareModalForType(type));
|
||||
} else {
|
||||
this.openShareModalForType(type);
|
||||
@@ -397,7 +429,7 @@ export class Sharing {
|
||||
): string {
|
||||
const embedUrl = Sharing.getEmbeddedUrl(config, root, isReadOnly, extraOptions);
|
||||
// The attributes must be double quoted, the full url's rison contains single quotes
|
||||
return `<iframe width="800px" height="200px" src="${embedUrl}"></iframe>`;
|
||||
return `<iframe width='800px' height='200px' src='${embedUrl}'></iframe>`;
|
||||
}
|
||||
|
||||
private static getEmbeddedUrl(config: any, root: string, readOnly: boolean, extraOptions: object): string {
|
||||
@@ -455,7 +487,7 @@ export class Sharing {
|
||||
const newElement = baseTemplate.children('a.share-item').clone();
|
||||
if (service.logoClass) {
|
||||
newElement.prepend(
|
||||
$('<span>').addClass('dropdown-icon mr-1').addClass(service.logoClass).prop('title', serviceName),
|
||||
$('<span>').addClass('dropdown-icon me-1').addClass(service.logoClass).prop('title', serviceName),
|
||||
);
|
||||
}
|
||||
if (service.text) {
|
||||
|
||||
@@ -36,6 +36,11 @@ body {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
// Fix for Bootstrap 5 navbar
|
||||
.navbar .container-fluid {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.navbar-brand img.logo-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
@@ -75,13 +80,23 @@ body {
|
||||
|
||||
.compiler-picker {
|
||||
min-width: 14em;
|
||||
flex-grow: 0.2 !important; // Ensures the compiler picker doesn't flex-grow too much and take up more space
|
||||
}
|
||||
|
||||
// Prevent TomSelect items from spilling onto multiple lines
|
||||
.ts-wrapper .item {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.compiler-picker .ts-input {
|
||||
text-align: center;
|
||||
border-left: none !important;
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
border-left: none !important; /* Fallback for older browsers */
|
||||
border-inline-start: none !important; /* Logical property for RTL support */
|
||||
border-top-left-radius: 0; /* Fallback for older browsers */
|
||||
border-bottom-left-radius: 0; /* Fallback for older browsers */
|
||||
border-start-start-radius: 0; /* Logical property for RTL support */
|
||||
border-end-start-radius: 0; /* Logical property for RTL support */
|
||||
}
|
||||
|
||||
.function-picker {
|
||||
@@ -294,6 +309,12 @@ pre.content.wrap * {
|
||||
}
|
||||
}
|
||||
|
||||
#site-template-loader {
|
||||
.modal-dialog {
|
||||
min-width: 800px; /* ensure template modal has adequate width */
|
||||
}
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
min-height: 200px;
|
||||
overflow-y: auto; /* make body scrollable -> keep Header & Footer onscreen, if possible */
|
||||
@@ -377,7 +398,7 @@ pre.content.wrap * {
|
||||
max-width: 100% !important;
|
||||
}
|
||||
|
||||
.toast-header .close {
|
||||
.toast-header .btn-close {
|
||||
float: left;
|
||||
margin-right: 5px;
|
||||
}
|
||||
@@ -387,17 +408,25 @@ pre.content.wrap * {
|
||||
}
|
||||
|
||||
.font-size-list {
|
||||
min-width: 43px !important;
|
||||
max-height: 70% !important;
|
||||
overflow-y: scroll;
|
||||
min-width: 60px !important;
|
||||
max-height: 70vh !important;
|
||||
overflow-y: auto;
|
||||
width: auto;
|
||||
// For my fellow Firefox users
|
||||
scrollbar-width: thin;
|
||||
padding: 0.25rem 0;
|
||||
}
|
||||
|
||||
.font-size-list button {
|
||||
margin-left: 0 !important;
|
||||
border-radius: 0;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
padding: 0.25rem 0.5rem;
|
||||
}
|
||||
|
||||
.font-size-list button:hover {
|
||||
background-color: rgba(0, 0, 0, 0.075);
|
||||
}
|
||||
|
||||
.font-option {
|
||||
@@ -893,18 +922,19 @@ div.populararguments div.dropdown-menu {
|
||||
}
|
||||
|
||||
.corporate .ces {
|
||||
font-size: 165%;
|
||||
height: 9em;
|
||||
.btn {
|
||||
--bs-btn-font-size: 24px;
|
||||
}
|
||||
height: 20em;
|
||||
}
|
||||
|
||||
.legendary .ces {
|
||||
font-size: 165%;
|
||||
height: 7em;
|
||||
}
|
||||
|
||||
.legendary .ces button {
|
||||
.btn {
|
||||
--bs-btn-font-size: 24px;
|
||||
padding: 1em;
|
||||
}
|
||||
height: 20em;
|
||||
}
|
||||
|
||||
.ces-logo {
|
||||
max-height: 1.5em;
|
||||
@@ -1115,7 +1145,7 @@ div.populararguments div.dropdown-menu {
|
||||
margin-right: 2pt;
|
||||
}
|
||||
|
||||
span.badge.badge-pill {
|
||||
span.badge.rounded-pill {
|
||||
margin-left: 2pt;
|
||||
}
|
||||
|
||||
@@ -1185,11 +1215,42 @@ html[data-theme='one-dark'] {
|
||||
padding-right: 2rem !important;
|
||||
}
|
||||
|
||||
/* Add back the dropdown arrow for TomSelect in Bootstrap 5 */
|
||||
.ts-wrapper.single .ts-control:not(.input-active)::after {
|
||||
content: " ";
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 15px;
|
||||
margin-top: -3px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-style: solid;
|
||||
border-width: 5px 5px 0 5px;
|
||||
border-color: #343a40 transparent transparent transparent;
|
||||
}
|
||||
|
||||
/* Styling for the dropdown arrow when dropdown is active */
|
||||
.ts-wrapper.single.dropdown-active .ts-control::after {
|
||||
margin-top: -4px;
|
||||
border-width: 0 5px 5px 5px;
|
||||
border-color: transparent transparent #343a40 transparent;
|
||||
}
|
||||
|
||||
// Fix Bootstrap 5's input-group border overlap issues with TomSelect
|
||||
// Bootstrap applies a -1px margin to elements matching `:not(:first-child)` in input groups
|
||||
// TomSelect creates a wrapper (.ts-wrapper) around the select element, which becomes a
|
||||
// child of the input-group. This wrapper gets the negative margin, causing it to shift
|
||||
// left by 1px and visually overflow its container boundary.
|
||||
.input-group > .ts-wrapper:not(:first-child) {
|
||||
margin-left: 0 !important; // Reset Bootstrap's negative margin for TomSelect wrappers
|
||||
}
|
||||
|
||||
.copy-link-btn {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.conformance-wrapper .compiler-list .form-row {
|
||||
.conformance-wrapper .compiler-list .row {
|
||||
padding-top: 3px;
|
||||
}
|
||||
|
||||
@@ -1229,8 +1290,10 @@ html[data-theme='one-dark'] {
|
||||
|
||||
.prepend-options,
|
||||
.picker-popout-button {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
border-top-right-radius: 0; /* Fallback for older browsers */
|
||||
border-bottom-right-radius: 0; /* Fallback for older browsers */
|
||||
border-start-end-radius: 0; /* Logical property for RTL support */
|
||||
border-end-end-radius: 0; /* Logical property for RTL support */
|
||||
}
|
||||
|
||||
.picker-popout-button {
|
||||
@@ -1257,7 +1320,9 @@ html[data-theme='one-dark'] {
|
||||
}
|
||||
|
||||
.popular-arguments-btn {
|
||||
border-top-right-radius: 0;
|
||||
border-top-right-radius: 0; /* Fallback for older browsers */
|
||||
border-start-end-radius: 0; /* Logical property for RTL support */
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.panel-compilation {
|
||||
@@ -1315,9 +1380,14 @@ html[data-theme='one-dark'] {
|
||||
> div {
|
||||
padding: 0;
|
||||
flex-shrink: 0;
|
||||
&.site-templates-list-col {
|
||||
min-width: 150px;
|
||||
width: 20%;
|
||||
}
|
||||
&.site-template-preview-col {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
min-width: 400px;
|
||||
img {
|
||||
width: 1000px;
|
||||
aspect-ratio: 1000 / 800;
|
||||
@@ -1579,11 +1649,11 @@ html[data-theme='one-dark'] {
|
||||
}
|
||||
}
|
||||
|
||||
.close {
|
||||
.dark-close {
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
bottom: 0;
|
||||
right: -12px;
|
||||
//background: #e787e7;
|
||||
padding: 0;
|
||||
background: linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, #1a1a1a 48%, #1a1a1a 100%);
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
|
||||
@@ -28,12 +28,24 @@ body {
|
||||
background-color: #333 !important;
|
||||
}
|
||||
|
||||
// Border color adjustments for form elements in dark theme
|
||||
.form-select,
|
||||
.form-control,
|
||||
.input-group-text,
|
||||
.ts-wrapper .ts-control {
|
||||
--bs-border-color: #444;
|
||||
}
|
||||
|
||||
input,
|
||||
textarea {
|
||||
color: #eee !important;
|
||||
background-color: #474747;
|
||||
border: 0 !important;
|
||||
|
||||
&::placeholder {
|
||||
color: #888 !important;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
color: #eee !important;
|
||||
background-color: #474747;
|
||||
@@ -166,7 +178,7 @@ textarea.form-control {
|
||||
.conformance-wrapper {
|
||||
background-color: #1e1e1e !important;
|
||||
|
||||
.compiler-list .form-row {
|
||||
.compiler-list .row {
|
||||
border-bottom: 1px solid #3e3e3e;
|
||||
}
|
||||
}
|
||||
@@ -184,7 +196,7 @@ textarea.form-control {
|
||||
background-color: rgba(49, 54, 60, 0.85);
|
||||
}
|
||||
|
||||
.custom-select {
|
||||
.form-select {
|
||||
background-color: #76a1c8 !important;
|
||||
}
|
||||
|
||||
@@ -196,6 +208,11 @@ textarea.form-control {
|
||||
color: #fff !important;
|
||||
background-color: #23272b !important;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: #235765 !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
@@ -366,8 +383,8 @@ textarea.form-control {
|
||||
color: #eee !important;
|
||||
background-color: #333 !important;
|
||||
|
||||
.close {
|
||||
color: #fff;
|
||||
.btn-close {
|
||||
filter: invert(100%);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -437,8 +454,8 @@ textarea.form-control {
|
||||
background-color: #aa3333 !important;
|
||||
color: #fff;
|
||||
|
||||
.close {
|
||||
color: #fff;
|
||||
.btn-close {
|
||||
filter: invert(100%);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -451,8 +468,8 @@ textarea.form-control {
|
||||
background-color: #222 !important;
|
||||
color: #fff;
|
||||
|
||||
.close {
|
||||
color: #fff;
|
||||
.btn-close {
|
||||
filter: invert(100%);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -164,16 +164,16 @@ a.navbar-brand img.logo.normal {
|
||||
.notification-error {
|
||||
background-color: indianred;
|
||||
color: white;
|
||||
.close {
|
||||
color: white;
|
||||
.btn-close {
|
||||
filter: invert(100%);
|
||||
}
|
||||
}
|
||||
|
||||
.notification-on {
|
||||
background-color: green;
|
||||
color: #fff;
|
||||
.close {
|
||||
color: white;
|
||||
.btn-close {
|
||||
filter: invert(100%);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,7 +346,7 @@ div.argmenuitem span.argdescription {
|
||||
color: #007bfd;
|
||||
}
|
||||
|
||||
.conformance-wrapper .compiler-list .form-row {
|
||||
.conformance-wrapper .compiler-list .row {
|
||||
border-bottom: 1px solid #e3e3e3;
|
||||
}
|
||||
|
||||
@@ -387,6 +387,11 @@ div.argmenuitem span.argdescription {
|
||||
background-color: #dae0e5;
|
||||
}
|
||||
|
||||
.dropdown-item.active {
|
||||
background-color: #007bfd;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.currentCursorPosition {
|
||||
color: #15a3b9;
|
||||
background-color: darken(rgba(248, 249, 250, 0.85), 3%);
|
||||
|
||||
@@ -39,11 +39,23 @@ body {
|
||||
background-color: $base !important;
|
||||
}
|
||||
|
||||
// Border color adjustments for form elements in dark theme
|
||||
.form-select,
|
||||
.form-control,
|
||||
.input-group-text,
|
||||
.ts-wrapper .ts-control {
|
||||
--bs-border-color: $dark;
|
||||
}
|
||||
|
||||
input {
|
||||
color: #eee !important;
|
||||
background-color: $lighter;
|
||||
border: 0 !important;
|
||||
|
||||
&::placeholder {
|
||||
color: #888 !important;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
color: #eee !important;
|
||||
background-color: $lightest;
|
||||
@@ -204,7 +216,7 @@ textarea.form-control {
|
||||
.conformance-wrapper {
|
||||
background-color: #1e1e1e !important;
|
||||
|
||||
.compiler-list .form-row {
|
||||
.compiler-list .row {
|
||||
border-bottom: 1px solid #3e3e3e;
|
||||
}
|
||||
}
|
||||
@@ -222,7 +234,7 @@ textarea.form-control {
|
||||
background-color: opacify($dark, 0.8);
|
||||
}
|
||||
|
||||
.custom-select {
|
||||
.form-select {
|
||||
background-color: #dddddd !important;
|
||||
color: #000 !important;
|
||||
}
|
||||
@@ -235,6 +247,11 @@ textarea.form-control {
|
||||
color: #fff !important;
|
||||
background-color: $lighter !important;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: #405f9d !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
@@ -325,7 +342,7 @@ textarea.form-control {
|
||||
}
|
||||
}
|
||||
|
||||
#v-status {
|
||||
.v-status {
|
||||
color: #eee !important;
|
||||
}
|
||||
|
||||
@@ -422,8 +439,8 @@ textarea.form-control {
|
||||
color: #eee !important;
|
||||
background-color: $base !important;
|
||||
|
||||
.close {
|
||||
color: #eee;
|
||||
.btn-close {
|
||||
filter: invert(90%);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -493,8 +510,8 @@ textarea.form-control {
|
||||
background-color: #aa3333 !important;
|
||||
color: #fff;
|
||||
|
||||
.close {
|
||||
color: #fff;
|
||||
.btn-close {
|
||||
filter: invert(100%);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -507,8 +524,8 @@ textarea.form-control {
|
||||
background-color: #222 !important;
|
||||
color: #fff;
|
||||
|
||||
.close {
|
||||
color: #fff;
|
||||
.btn-close {
|
||||
filter: invert(100%);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,14 @@ body {
|
||||
background-color: $base !important;
|
||||
}
|
||||
|
||||
// Border color adjustments for form elements
|
||||
.form-select,
|
||||
.form-control,
|
||||
.input-group-text,
|
||||
.ts-wrapper .ts-control {
|
||||
--bs-border-color: $dark;
|
||||
}
|
||||
|
||||
input {
|
||||
//color: #000 !important;
|
||||
background-color: $base;
|
||||
@@ -174,7 +182,7 @@ textarea.form-control {
|
||||
.conformance-wrapper {
|
||||
background-color: #1e1e1e !important;
|
||||
|
||||
.compiler-list .form-row {
|
||||
.compiler-list .row {
|
||||
border-bottom: 1px solid #3e3e3e;
|
||||
}
|
||||
}
|
||||
@@ -188,7 +196,7 @@ textarea.form-control {
|
||||
background-color: opacify($dark, 0.8);
|
||||
}
|
||||
|
||||
.custom-select {
|
||||
.form-select {
|
||||
background-color: #76a1c8 !important;
|
||||
}
|
||||
|
||||
@@ -198,6 +206,11 @@ textarea.form-control {
|
||||
&:hover {
|
||||
background-color: $dark !important;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: $darker !important;
|
||||
color: #212529 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
@@ -383,10 +396,6 @@ textarea.form-control {
|
||||
color: #212529 !important;
|
||||
background-color: $base !important;
|
||||
border-bottom-color: $dark;
|
||||
|
||||
.close {
|
||||
color: #212529;
|
||||
}
|
||||
}
|
||||
|
||||
.nav.nav-tabs {
|
||||
@@ -459,8 +468,8 @@ textarea.form-control {
|
||||
background-color: #aa3333 !important;
|
||||
color: #fff;
|
||||
|
||||
.close {
|
||||
color: #fff;
|
||||
.btn-close {
|
||||
filter: invert(100%);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -473,8 +482,8 @@ textarea.form-control {
|
||||
background-color: #222 !important;
|
||||
color: #fff;
|
||||
|
||||
.close {
|
||||
color: #fff;
|
||||
.btn-close {
|
||||
filter: invert(100%);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
import $ from 'jquery';
|
||||
|
||||
import * as BootstrapUtils from '../bootstrap-utils.js';
|
||||
import {AlertAskOptions, AlertEnterTextOptions, AlertNotifyOptions} from './alert.interfaces.js';
|
||||
|
||||
export class Alert {
|
||||
@@ -57,10 +58,10 @@ export class Alert {
|
||||
modal.toggleClass('error-alert', isError === true);
|
||||
modal.find('.modal-title').html(title);
|
||||
modal.find('.modal-body').html(body);
|
||||
modal.modal();
|
||||
BootstrapUtils.showModal(modal);
|
||||
|
||||
if (onClose) {
|
||||
modal.off('hidden.bs.modal');
|
||||
modal.on('hidden.bs.modal', onClose);
|
||||
BootstrapUtils.setElementEventHandler(modal, 'hidden.bs.modal', onClose);
|
||||
}
|
||||
return modal;
|
||||
}
|
||||
@@ -83,10 +84,10 @@ export class Alert {
|
||||
modal.find('.modal-footer .no').removeClass('btn-link').addClass(askOptions.noClass);
|
||||
}
|
||||
if (askOptions.onClose) {
|
||||
modal.off('hidden.bs.modal');
|
||||
modal.on('hidden.bs.modal', askOptions.onClose);
|
||||
BootstrapUtils.setElementEventHandler(modal, 'hidden.bs.modal', askOptions.onClose);
|
||||
}
|
||||
modal.modal();
|
||||
|
||||
BootstrapUtils.showModal(modal);
|
||||
return modal;
|
||||
}
|
||||
|
||||
@@ -108,10 +109,8 @@ export class Alert {
|
||||
const newElement = $(`
|
||||
<div class="toast" tabindex="-1" role="alert" aria-live="assertive" aria-atomic="true">
|
||||
<div class="toast-header ${alertClass}">
|
||||
<strong class="mr-auto">${this.prefixMessage}</strong>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<strong class="me-auto">${this.prefixMessage}</strong>
|
||||
<button type="button" class="ms-2 mb-1 btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="toast-body ${alertClass}">
|
||||
<span id="msg">${body}</span>
|
||||
@@ -119,21 +118,26 @@ export class Alert {
|
||||
</div>
|
||||
`);
|
||||
container.append(newElement);
|
||||
newElement.toast({
|
||||
const toastOptions = {
|
||||
autohide: autoDismiss,
|
||||
delay: dismissTime,
|
||||
});
|
||||
};
|
||||
|
||||
BootstrapUtils.initToast(newElement, toastOptions);
|
||||
|
||||
if (group !== '') {
|
||||
if (collapseSimilar) {
|
||||
// Only collapsing if a group has been specified
|
||||
const old = container.find(`[data-group="${group}"]`);
|
||||
old.toast('hide');
|
||||
old.remove();
|
||||
old.each((_, element) => {
|
||||
BootstrapUtils.hideToast(element);
|
||||
$(element).remove();
|
||||
});
|
||||
}
|
||||
newElement.attr('data-group', group);
|
||||
}
|
||||
onBeforeShow(newElement);
|
||||
newElement.toast('show');
|
||||
BootstrapUtils.showToast(newElement);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -174,14 +178,13 @@ export class Alert {
|
||||
noButton.removeClass('btn-light').addClass(askOptions.noClass);
|
||||
}
|
||||
if (askOptions.onClose) {
|
||||
modal.off('hidden.bs.modal');
|
||||
modal.on('hidden.bs.modal', askOptions.onClose);
|
||||
BootstrapUtils.setElementEventHandler(modal, 'hidden.bs.modal', askOptions.onClose);
|
||||
}
|
||||
|
||||
modal.on('shown.bs.modal', () => {
|
||||
BootstrapUtils.setElementEventHandler(modal, 'shown.bs.modal', () => {
|
||||
answerEdit.trigger('focus');
|
||||
});
|
||||
modal.modal();
|
||||
BootstrapUtils.showModal(modal);
|
||||
return modal;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import {
|
||||
EnvVarOverrides,
|
||||
} from '../../types/compilation/compiler-overrides.interfaces.js';
|
||||
import {assert, unwrap} from '../assert.js';
|
||||
import * as BootstrapUtils from '../bootstrap-utils.js';
|
||||
import {CompilerInfo} from '../compiler.interfaces.js';
|
||||
import {localStorage} from '../local.js';
|
||||
import {options} from '../options.js';
|
||||
@@ -160,8 +161,8 @@ export class CompilerOverridesWidget {
|
||||
btn.addClass('active');
|
||||
} else if (state instanceof IncompatibleState) {
|
||||
btn.prop('disabled', true);
|
||||
btn.prop('data-toggle', 'tooltip');
|
||||
btn.prop('data-placement', 'top');
|
||||
btn.prop('data-bs-toggle', 'tooltip');
|
||||
btn.prop('data-bs-placement', 'top');
|
||||
btn.prop('title', state.reason);
|
||||
}
|
||||
div.data('ov-name', fave.name);
|
||||
@@ -416,9 +417,8 @@ export class CompilerOverridesWidget {
|
||||
|
||||
const lastOverrides = JSON.stringify(this.configured);
|
||||
|
||||
const popup = this.popupDomRoot.modal();
|
||||
// popup is shared, so clear the events first
|
||||
popup.off('hidden.bs.modal').on('hidden.bs.modal', () => {
|
||||
BootstrapUtils.setElementEventHandler(this.popupDomRoot, 'hidden.bs.modal', () => {
|
||||
this.configured = this.loadStateFromUI();
|
||||
|
||||
const newOverrides = JSON.stringify(this.configured);
|
||||
@@ -428,5 +428,7 @@ export class CompilerOverridesWidget {
|
||||
this.onChangeCallback();
|
||||
}
|
||||
});
|
||||
|
||||
BootstrapUtils.showModal(this.popupDomRoot);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import * as sifter from '@orchidjs/sifter';
|
||||
import {escapeHTML, intersection, remove, unique} from '../../shared/common-utils.js';
|
||||
import {CompilerInfo} from '../../types/compiler.interfaces.js';
|
||||
import {unwrap, unwrapString} from '../assert.js';
|
||||
import * as BootstrapUtils from '../bootstrap-utils.js';
|
||||
import {CompilerService} from '../compiler-service.js';
|
||||
import {highlight} from '../highlight.js';
|
||||
import {CompilerPicker} from './compiler-picker.js';
|
||||
@@ -64,7 +65,7 @@ export class CompilerPickerPopup {
|
||||
this.categoryFilters = [];
|
||||
this.searchBar.val('');
|
||||
|
||||
this.modal.on('shown.bs.modal', () => {
|
||||
BootstrapUtils.setElementEventHandler(this.modal, 'shown.bs.modal', () => {
|
||||
this.searchBar[0].focus();
|
||||
});
|
||||
}
|
||||
@@ -186,7 +187,7 @@ export class CompilerPickerPopup {
|
||||
`
|
||||
<div class="compiler d-flex" data-value="${compiler.id}">
|
||||
<div>${searchRegexes ? highlight(name, searchRegexes) : name}</div>
|
||||
<div title="Click to mark or unmark as a favorite" class="ml-auto toggle-fav">
|
||||
<div title="Click to mark or unmark as a favorite" class="ms-auto toggle-fav">
|
||||
<i class="${extraClasses}"></i>
|
||||
</div>
|
||||
</div>
|
||||
@@ -264,10 +265,10 @@ export class CompilerPickerPopup {
|
||||
show() {
|
||||
this.searchBar.trigger('input');
|
||||
this.fillCompilers();
|
||||
this.modal.modal({});
|
||||
BootstrapUtils.showModal(this.modal);
|
||||
}
|
||||
|
||||
hide() {
|
||||
this.modal.modal('hide');
|
||||
BootstrapUtils.hideModal(this.modal);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ export class CompilerPicker {
|
||||
'<div class="d-flex"><div>' +
|
||||
escapeHtml(data.name) +
|
||||
'</div>' +
|
||||
'<div title="Click to mark or unmark as a favorite" class="ml-auto toggle-fav">' +
|
||||
'<div title="Click to mark or unmark as a favorite" class="ms-auto toggle-fav">' +
|
||||
'<i class="' +
|
||||
extraClasses +
|
||||
'"></i>' +
|
||||
@@ -143,6 +143,7 @@ export class CompilerPicker {
|
||||
'</div>'
|
||||
);
|
||||
},
|
||||
item: (data, escapeHtml) => `<div title="${escapeHtml(data.name)}">${escapeHtml(data.name)}</div>`,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
import $ from 'jquery';
|
||||
import {escapeHTML} from '../../shared/common-utils.js';
|
||||
import * as BootstrapUtils from '../bootstrap-utils.js';
|
||||
import {options} from '../options.js';
|
||||
|
||||
export type CompilerVersionInfo = {version: string; fullVersion?: string};
|
||||
@@ -78,14 +79,19 @@ function reallySetCompilerVersionPopover(
|
||||
.on('click', () => {
|
||||
versionContent.toggle();
|
||||
hiddenVersionText.toggle();
|
||||
pane.fullCompilerName.popover('update');
|
||||
const popover = BootstrapUtils.getPopoverInstance(pane.fullCompilerName);
|
||||
if (popover) popover.update();
|
||||
});
|
||||
hiddenSection.append(hiddenVersionText).append(clickToExpandContent);
|
||||
bodyContent.append(hiddenSection);
|
||||
}
|
||||
|
||||
pane.fullCompilerName.popover('dispose');
|
||||
pane.fullCompilerName.popover({
|
||||
// Dispose of existing popover
|
||||
const existingPopover = BootstrapUtils.getPopoverInstance(pane.fullCompilerName);
|
||||
if (existingPopover) existingPopover.dispose();
|
||||
|
||||
// Initialize new popover
|
||||
BootstrapUtils.initPopover(pane.fullCompilerName, {
|
||||
html: true,
|
||||
title: notification
|
||||
? ($.parseHTML('<span>Compiler Version: ' + notification + '</span>')[0] as Element)
|
||||
|
||||
@@ -47,11 +47,7 @@ function makeFontSizeDropdown(elem: JQuery, obj: FontScale, buttonDropdown: JQue
|
||||
for (let i = 8; i <= 30; i++) {
|
||||
const item = $('<button></button>');
|
||||
|
||||
item.attr('data-value', i)
|
||||
.addClass('dropdown-item btn btn-sm btn-light')
|
||||
.text(i)
|
||||
.appendTo(elem)
|
||||
.on('click', onClickEvent);
|
||||
item.attr('data-value', i).addClass('dropdown-item').text(i).appendTo(elem).on('click', onClickEvent);
|
||||
|
||||
if (obj.scale === i) {
|
||||
item.addClass('active');
|
||||
|
||||
@@ -25,9 +25,10 @@
|
||||
import $ from 'jquery';
|
||||
import {editor} from 'monaco-editor';
|
||||
import {pluck} from 'underscore';
|
||||
import {unwrap} from '../assert.js';
|
||||
import * as BootstrapUtils from '../bootstrap-utils.js';
|
||||
import {EditorSource, HistoryEntry, sortedList} from '../history.js';
|
||||
import ITextModel = editor.ITextModel;
|
||||
import {unwrap} from '../assert.js';
|
||||
|
||||
type Entry = {dt: number; name: string; load: () => void};
|
||||
|
||||
@@ -72,7 +73,9 @@ export class HistoryWidget {
|
||||
name: `${dt.replace(/\s\(.*\)/, '')} (${languages})`,
|
||||
load: () => {
|
||||
this.onLoad(data);
|
||||
this.modal?.modal('hide');
|
||||
if (this.modal) {
|
||||
BootstrapUtils.hideModal(this.modal);
|
||||
}
|
||||
},
|
||||
};
|
||||
}),
|
||||
@@ -140,7 +143,8 @@ export class HistoryWidget {
|
||||
this.onLoadCallback = onLoad;
|
||||
|
||||
// It can't tell that we initialize modal on initializeIfNeeded, so it sticks to the possibility of it being null
|
||||
unwrap(this.modal).on('shown.bs.modal', () => this.resizeLayout());
|
||||
unwrap(this.modal).modal();
|
||||
const modalElement = unwrap(this.modal)[0];
|
||||
modalElement.addEventListener('shown.bs.modal', () => this.resizeLayout());
|
||||
BootstrapUtils.showModal(modalElement);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
import $ from 'jquery';
|
||||
import {unwrapString} from '../assert.js';
|
||||
import * as BootstrapUtils from '../bootstrap-utils.js';
|
||||
import {localStorage} from '../local.js';
|
||||
import {Library, LibraryVersion} from '../options.interfaces.js';
|
||||
import {options} from '../options.js';
|
||||
@@ -187,8 +188,7 @@ export class LibsWidget {
|
||||
this.domRoot.addClass('mobile');
|
||||
}
|
||||
|
||||
this.domRoot
|
||||
.on('shown.bs.modal', () => {
|
||||
BootstrapUtils.setElementEventHandler(this.domRoot, 'shown.bs.modal', () => {
|
||||
searchInput.trigger('focus');
|
||||
|
||||
for (const filter of this.filters) {
|
||||
@@ -202,8 +202,9 @@ export class LibsWidget {
|
||||
break;
|
||||
}
|
||||
}
|
||||
})
|
||||
.on('hide.bs.modal', () => {
|
||||
});
|
||||
|
||||
BootstrapUtils.setElementEventHandler(this.domRoot, 'hide.bs.modal', () => {
|
||||
this.hidePopups();
|
||||
});
|
||||
|
||||
@@ -212,7 +213,7 @@ export class LibsWidget {
|
||||
this.domRoot.find('.lib-search-button').on('click', this.startSearching.bind(this));
|
||||
|
||||
this.dropdownButton.on('click', () => {
|
||||
this.domRoot.modal({});
|
||||
BootstrapUtils.showModal(this.domRoot);
|
||||
});
|
||||
|
||||
this.updateButton();
|
||||
@@ -342,11 +343,14 @@ export class LibsWidget {
|
||||
}
|
||||
|
||||
hidePopups() {
|
||||
this.searchResults.find('.lib-info-button').popover('hide');
|
||||
this.searchResults.find('.lib-info-button').each((_, el) => BootstrapUtils.hidePopover($(el)));
|
||||
}
|
||||
|
||||
clearSearchResults() {
|
||||
this.searchResults.find('.lib-info-button').popover('dispose');
|
||||
this.searchResults.find('.lib-info-button').each((_, el) => {
|
||||
const popover = BootstrapUtils.getPopoverInstance($(el));
|
||||
if (popover) popover.dispose();
|
||||
});
|
||||
this.searchResults.html('');
|
||||
}
|
||||
|
||||
@@ -498,7 +502,7 @@ export class LibsWidget {
|
||||
'<div class="arrow"></div>' +
|
||||
'<h3 class="popover-header"></h3><div class="popover-body"></div>' +
|
||||
'</div>';
|
||||
infoButton.popover({
|
||||
BootstrapUtils.initPopover(infoButton, {
|
||||
html: true,
|
||||
title: 'Build info for ' + getCompilerName(this.currentCompilerId),
|
||||
content: () => {
|
||||
|
||||
@@ -29,6 +29,7 @@ import {escapeHTML} from '../../shared/common-utils.js';
|
||||
import {Language} from '../../types/languages.interfaces.js';
|
||||
import {SourceApiEntry} from '../../types/source.interfaces.js';
|
||||
import {unwrap, unwrapString} from '../assert.js';
|
||||
import * as BootstrapUtils from '../bootstrap-utils.js';
|
||||
import {HistorySource} from '../history.js';
|
||||
import {localStorage} from '../local.js';
|
||||
import {Alert} from './alert.js';
|
||||
@@ -98,7 +99,9 @@ export class LoadSave {
|
||||
window.location.origin + this.base + 'source/builtin/load/' + element.lang + '/' + element.file,
|
||||
response => this.onLoad(response.file),
|
||||
);
|
||||
this.modal?.modal('hide');
|
||||
if (this.modal) {
|
||||
BootstrapUtils.hideModal(this.modal);
|
||||
}
|
||||
}
|
||||
|
||||
private static populate(root: JQuery, list: PopulateItem[]) {
|
||||
@@ -143,7 +146,9 @@ export class LoadSave {
|
||||
name: name,
|
||||
load: () => {
|
||||
this.onLoad(data);
|
||||
this.modal?.modal('hide');
|
||||
if (this.modal) {
|
||||
BootstrapUtils.hideModal(this.modal);
|
||||
}
|
||||
},
|
||||
delete: () => {
|
||||
this.alertSystem.ask(
|
||||
@@ -183,7 +188,9 @@ export class LoadSave {
|
||||
name: dt.replace(/\s\(.*\)/, ''),
|
||||
load: () => {
|
||||
this.onLoad(data.source);
|
||||
this.modal?.modal('hide');
|
||||
if (this.modal) {
|
||||
BootstrapUtils.hideModal(this.modal);
|
||||
}
|
||||
},
|
||||
};
|
||||
}),
|
||||
@@ -214,7 +221,9 @@ export class LoadSave {
|
||||
};
|
||||
reader.readAsText(file);
|
||||
}
|
||||
this.modal?.modal('hide');
|
||||
if (this.modal) {
|
||||
BootstrapUtils.hideModal(this.modal);
|
||||
}
|
||||
}
|
||||
|
||||
public run(onLoad, editorText, currentLanguage: Language) {
|
||||
@@ -224,7 +233,11 @@ export class LoadSave {
|
||||
this.populateLocalHistory();
|
||||
this.onLoadCallback = onLoad;
|
||||
unwrap(this.modal).find('.local-file').attr('accept', currentLanguage.extensions.join(','));
|
||||
this.populateBuiltins().then(() => this.modal?.modal());
|
||||
this.populateBuiltins().then(() => {
|
||||
if (this.modal) {
|
||||
BootstrapUtils.showModal(this.modal);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private onSaveToBrowserStorage() {
|
||||
@@ -238,7 +251,9 @@ export class LoadSave {
|
||||
LoadSave.setLocalFile(name, this.editorText);
|
||||
};
|
||||
if (name in LoadSave.getLocalFiles()) {
|
||||
this.modal?.modal('hide');
|
||||
if (this.modal) {
|
||||
BootstrapUtils.hideModal(this.modal);
|
||||
}
|
||||
this.alertSystem.ask(
|
||||
'Replace current?',
|
||||
`Do you want to replace the existing saved file '${escapeHTML(name)}'?`,
|
||||
@@ -246,7 +261,9 @@ export class LoadSave {
|
||||
);
|
||||
} else {
|
||||
doneCallback();
|
||||
this.modal?.modal('hide');
|
||||
if (this.modal) {
|
||||
BootstrapUtils.hideModal(this.modal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ import {
|
||||
RuntimeToolType,
|
||||
} from '../../types/execution/execution.interfaces.js';
|
||||
import {assert} from '../assert.js';
|
||||
import * as BootstrapUtils from '../bootstrap-utils.js';
|
||||
import {CompilerInfo} from '../compiler.interfaces.js';
|
||||
import {localStorage} from '../local.js';
|
||||
import {options} from '../options.js';
|
||||
@@ -392,9 +393,8 @@ export class RuntimeToolsWidget {
|
||||
|
||||
const lastOverrides = JSON.stringify(this.configured);
|
||||
|
||||
const popup = this.popupDomRoot.modal();
|
||||
// popup is shared, so clear the events first
|
||||
popup.off('hidden.bs.modal').on('hidden.bs.modal', () => {
|
||||
BootstrapUtils.setElementEventHandler(this.popupDomRoot, 'hidden.bs.modal', () => {
|
||||
this.configured = this.loadStateFromUI();
|
||||
|
||||
const newOverrides = JSON.stringify(this.configured);
|
||||
@@ -404,5 +404,7 @@ export class RuntimeToolsWidget {
|
||||
this.onChangeCallback();
|
||||
}
|
||||
});
|
||||
|
||||
BootstrapUtils.showModal(this.popupDomRoot);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import GoldenLayout from 'golden-layout';
|
||||
import {escapeHTML} from '../../shared/common-utils.js';
|
||||
import {SiteTemplateResponse, UserSiteTemplate} from '../../types/features/site-templates.interfaces.js';
|
||||
import {assert, unwrap, unwrapString} from '../assert.js';
|
||||
import * as BootstrapUtils from '../bootstrap-utils.js';
|
||||
import {localStorage} from '../local.js';
|
||||
import {Settings} from '../settings.js';
|
||||
import * as url from '../url.js';
|
||||
@@ -174,7 +175,7 @@ class SiteTemplatesWidget {
|
||||
this.populated = true;
|
||||
}
|
||||
show() {
|
||||
this.modal.modal('show');
|
||||
BootstrapUtils.showModal(this.modal);
|
||||
if (!this.populated) {
|
||||
this.populate();
|
||||
}
|
||||
|
||||
@@ -24,11 +24,12 @@
|
||||
|
||||
import {Chart, ChartData, defaults} from 'chart.js';
|
||||
import $ from 'jquery';
|
||||
import {Settings} from '../settings.js';
|
||||
import 'chart.js/auto';
|
||||
import {isString} from '../../shared/common-utils.js';
|
||||
import {CompilationResult} from '../../types/compilation/compilation.interfaces.js';
|
||||
import {unwrap} from '../assert.js';
|
||||
import * as BootstrapUtils from '../bootstrap-utils.js';
|
||||
import {Settings} from '../settings.js';
|
||||
import 'chart.js/auto';
|
||||
|
||||
type Data = ChartData<'bar', number[], string> & {steps: number};
|
||||
|
||||
@@ -188,7 +189,7 @@ function displayData(data: Data) {
|
||||
},
|
||||
},
|
||||
});
|
||||
modal.modal('show');
|
||||
BootstrapUtils.showModal(modal);
|
||||
}
|
||||
|
||||
export function displayCompilationTiming(compileResult: CompilationResult | null, totalTime: number) {
|
||||
|
||||
@@ -24,8 +24,8 @@ block content
|
||||
div.ces-item-description= level.description
|
||||
.ces-top
|
||||
each sponsor in level.sponsors
|
||||
.ces
|
||||
button.btn-block.btn-secondary(title=sponsor.title onclick=sponsor.onclick disabled=!sponsor.url style=sponsor.style)
|
||||
.ces.d-grid
|
||||
button.btn.btn-secondary(title=sponsor.title onclick=sponsor.onclick disabled=!sponsor.url style=sponsor.style)
|
||||
if sponsor.displayType === 'SideBySide'
|
||||
.d-flex
|
||||
.ces-item-title
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.btn-group.btn-group-sm(role="group" aria-label="Font size")
|
||||
button.dropdown-toggle.btn.btn-light.fs-button(type="button" title="Change font size\nTip #1: You can use scroll wheel while hovering over this button\nTip #2: You can ctrl+click this button to reset to default" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" data-flip="false" data-boundary="viewport")
|
||||
button.dropdown-toggle.btn.btn-light.fs-button(type="button" title="Change font size\nTip #1: You can use scroll wheel while hovering over this button\nTip #2: You can ctrl+click this button to reset to default" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" data-bs-flip="false" data-bs-boundary="viewport")
|
||||
span.fa.fa-font #[b.caret]
|
||||
.dropdown-menu.font-size-list(aria-labelledby="fs-button")
|
||||
|
||||
@@ -2,13 +2,14 @@ extends _layout.pug
|
||||
|
||||
block prepend content
|
||||
nav.navbar.navbar-godbolt.navbar-expand-md.navbar-light.bg-light
|
||||
.container-fluid
|
||||
include logo.pug
|
||||
button.navbar-toggler(type="button" data-toggle="collapse" data-target="#navbarContent" aria-controls="navbarContent" aria-expanded="false" aria-label="Toggle navigation")
|
||||
button.navbar-toggler(type="button" data-bs-toggle="collapse" data-bs-target="#navbarContent" aria-controls="navbarContent" aria-expanded="false" aria-label="Toggle navigation")
|
||||
span.navbar-toggler-icon
|
||||
.collapse.navbar-collapse#navbarContent
|
||||
ul.navbar-nav.navbar-left.mr-auto
|
||||
ul.navbar-nav.me-auto.mb-2.mb-md-0
|
||||
li.nav-item.dropdown
|
||||
button.btn.btn-light.nav-link.dropdown-toggle#addDropdown(role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false") Add...
|
||||
button.btn.btn-light.nav-link.dropdown-toggle#addDropdown(role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false") Add...
|
||||
div.dropdown-menu(aria-labelledby="addDropdown")
|
||||
button.dropdown-item.btn#add-editor(title="Click or drag to desired destination")
|
||||
span.dropdown-icon.fa.fa-code
|
||||
@@ -20,9 +21,9 @@ block prepend content
|
||||
span.dropdown-icon.fa.fa-list-alt
|
||||
| Tree (IDE Mode)
|
||||
li.nav-item.dropdown
|
||||
button.btn.btn-light.nav-link.dropdown-toggle#moreDropdown(role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" data-cy="more-dropdown-btn") More
|
||||
button.btn.btn-light.nav-link.dropdown-toggle#moreDropdown(role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" data-cy="more-dropdown-btn") More
|
||||
div.dropdown-menu(aria-labelledby="moreDropdown")
|
||||
button.dropdown-item.btn#setting(data-target="#settings" data-toggle="modal")
|
||||
button.dropdown-item.btn#setting(data-bs-target="#settings" data-bs-toggle="modal")
|
||||
span.dropdown-icon.fas.fa-sliders-h
|
||||
| Settings
|
||||
div.dropdown-divider
|
||||
@@ -60,47 +61,52 @@ block prepend content
|
||||
a.nav-link.ui-presentation-next(href="javascript:;")
|
||||
span.dropdown-icon.fas.fa-forward
|
||||
| Next
|
||||
ul#motd.navbar-nav.navbar-left.mr-auto.community-advert.d-none
|
||||
|
||||
ul#motd.navbar-nav.community-advert.d-none.mx-auto
|
||||
span.content
|
||||
| Thanks for using Compiler Explorer
|
||||
span.community-hide(title="Hide and never show again" aria-label="Close")
|
||||
button.close(type="button" aria-hidden="true") ×
|
||||
ul.navbar-nav.navbar-right
|
||||
button.btn-close(type="button" aria-label="Close")
|
||||
|
||||
ul.navbar-nav.ms-auto.mb-2.mb-md-0
|
||||
if showSponsors
|
||||
li.nav-item.btn.btn-outline-info#ces(data-toggle="modal")
|
||||
li.nav-item.btn.btn-outline-info#ces
|
||||
span#ces-banner-text Sponsors
|
||||
include sponsor-icons.pug
|
||||
li.nav-item.dropdown
|
||||
button.btn.btn-light.nav-link.dropdown-toggle#share(role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false") Share
|
||||
div.dropdown-menu.dropdown-menu-right
|
||||
li.nav-item.dropdown#share-tooltip-target
|
||||
button.btn.btn-light.nav-link.dropdown-toggle#share(role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false") Share
|
||||
div.dropdown-menu.dropdown-menu-end
|
||||
// In order for these to support both the clipboard button _and_ optionally opening the dialog, we can't
|
||||
// use `data-bs-toggle="modal"` on the `<a>` itself, as that would prevent the clipboard button from working.
|
||||
// Bootstrap's default blanket event handler beats out any event handler we manually attach to the button.
|
||||
if storageSolution !== "null"
|
||||
a.dropdown-item#shareShort(href="javascript:;" data-target="#sharelinkdialog" data-toggle="modal" data-bind="Short")
|
||||
a.dropdown-item#shareShort(href="javascript:;" data-bs-target="#sharelinkdialog" data-bind="Short")
|
||||
span.dropdown-icon.fas.fa-cloud.d-inline
|
||||
| Short Link
|
||||
button.btn.btn-sm.copy-link-btn.clip-icon.float-right(data-toggle="none")
|
||||
button.btn.btn-sm.copy-link-btn.clip-icon.float-end(data-bs-target="" data-bs-toggle="none")
|
||||
span.dropdown-icon.fa.fa-clipboard
|
||||
a.dropdown-item#shareFull(href="javascript:;" data-target="#sharelinkdialog" data-toggle="modal" data-bind="Full")
|
||||
a.dropdown-item#shareFull(href="javascript:;" data-bs-target="#sharelinkdialog" data-bind="Full")
|
||||
span.dropdown-icon.fas.fa-store-slash.d-inline
|
||||
| Full Link
|
||||
button.btn.btn-sm.copy-link-btn.clip-icon.float-right(data-toggle="none")
|
||||
button.btn.btn-sm.copy-link-btn.clip-icon.float-end(data-bs-toggle="none")
|
||||
span.dropdown-icon.fa.fa-clipboard
|
||||
a.dropdown-item#shareEmbed(href="javascript:;" data-target="#sharelinkdialog" data-toggle="modal" data-bind="Embed")
|
||||
a.dropdown-item#shareEmbed(href="javascript:;" data-bs-target="#sharelinkdialog" data-bind="Embed")
|
||||
span.dropdown-icon.fas.fa-window-restore.d-inline
|
||||
| Embed in iframe
|
||||
// This is not an oversight, there is in fact a .float-right missing here that's there in the other 2
|
||||
button.btn.btn-sm.copy-link-btn.clip-icon(data-toggle="none")
|
||||
// This is not an oversight, there is in fact a .float-end missing here that's there in the other 2
|
||||
button.btn.btn-sm.copy-link-btn.clip-icon(data-bs-toggle="none")
|
||||
span.dropdown-icon.fa.fa-clipboard
|
||||
if policies.cookies.enabled || policies.privacy.enabled
|
||||
li.nav-item.dropdown
|
||||
button.btn.btn-light.nav-link.dropdown-toggle#policiesDropdown(role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false")
|
||||
button.btn.btn-light.nav-link.dropdown-toggle#policiesDropdown(role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false")
|
||||
| Policies
|
||||
span#policyBellNotification.d-none.badge.badge-pill.badge-primary
|
||||
span#policyBellNotification.d-none.badge.rounded-pill.bg-primary
|
||||
span.fa.fa-bell
|
||||
div.dropdown-menu.dropdown-menu-right(aria-labelledby="policiesDropdown")
|
||||
div.dropdown-menu.dropdown-menu-end(aria-labelledby="policiesDropdown")
|
||||
include menu-policies.pug
|
||||
li.nav-item.dropdown
|
||||
button.btn.btn-light.nav-link.dropdown-toggle#otherDropdown(role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false") Other
|
||||
div.dropdown-menu.dropdown-menu-right(aria-labelledby="otherDropdown")
|
||||
button.btn.btn-light.nav-link.dropdown-toggle#otherDropdown(role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false") Other
|
||||
div.dropdown-menu.dropdown-menu-end(aria-labelledby="otherDropdown")
|
||||
include menu-other.pug
|
||||
|
||||
block append footer
|
||||
@@ -108,5 +114,4 @@ block append footer
|
||||
#real-dark
|
||||
#true-dark
|
||||
.content Try the real dark theme 🔦
|
||||
.close
|
||||
i.fa-solid.fa-xmark
|
||||
button.btn.dark-close.fas.fa-times(type="button" aria-label="Close")
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
button.dropdown-item.btn#cookies
|
||||
span.dropdown-icon.fas.fa-cookie-bite
|
||||
| Cookie policy
|
||||
span#cookiesBellNotification.d-none.badge.badge-pill.badge-primary
|
||||
span#cookiesBellNotification.d-none.badge.rounded-pill.bg-primary
|
||||
span.fa.fa-bell
|
||||
button.dropdown-item.btn#privacy
|
||||
span.dropdown-icon.fas.fa-user-lock
|
||||
| Privacy policy
|
||||
span#privacyBellNotification.d-none.badge.badge-pill.badge-primary
|
||||
span#privacyBellNotification.d-none.badge.rounded-pill.bg-primary
|
||||
span.fa.fa-bell
|
||||
|
||||
@@ -6,7 +6,7 @@ block content
|
||||
input#filterAnsi(name='filterAnsi' value='true' type='hidden')
|
||||
|
||||
.form-pair.inlined.dropdown
|
||||
a.btn.nodropdown-toggle#outputDropdown(href="javascript:;" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false")
|
||||
a.btn.nodropdown-toggle#outputDropdown(href="javascript:;" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false")
|
||||
span.fas.fa-cog
|
||||
| Output
|
||||
|
||||
@@ -14,7 +14,7 @@ block content
|
||||
include ../options-output.pug
|
||||
|
||||
.form-pair.inlined.dropdown
|
||||
a.btn.nodropdown-toggle#filtersDropdown(href="javascript:;" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false")
|
||||
a.btn.nodropdown-toggle#filtersDropdown(href="javascript:;" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false")
|
||||
span.fas.fa-filter
|
||||
| Filters
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
block footer
|
||||
nav.bg-light
|
||||
if mobileViewer
|
||||
a.btn.nodropdown-toggle#otherDropdown(href="javascript:;" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false") Other
|
||||
a.btn.nodropdown-toggle#otherDropdown(href="javascript:;" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false") Other
|
||||
|
||||
.noscriptdropdown(aria-labelledby="otherDropdown")
|
||||
include ../menu-other.pug
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
.header
|
||||
nav.navbar.navbar-godbolt.navbar-expand-md.navbar-light.bg-light
|
||||
include ../logo.pug
|
||||
#motd.navbar-nav.navbar-center.mr-auto.community-advert.d-none
|
||||
#motd.navbar-nav.navbar-center.me-auto.community-advert.d-none
|
||||
span.content
|
||||
| Thanks for using Compiler Explorer
|
||||
.navbar-nav.navbar-right
|
||||
if showSponsors
|
||||
li.nav-item.btn.btn-outline-primary#ces(data-toggle="modal")
|
||||
li.nav-item.btn.btn-outline-primary#ces(data-bs-toggle="modal")
|
||||
a(href=`${httpRoot}noscript/sponsors`) Sponsors
|
||||
include ../sponsor-icons.pug
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
block header
|
||||
nav.bg-light
|
||||
if mobileViewer
|
||||
a.btn.nodropdown-toggle#languageDropdown(href="javascript:;" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false") Language
|
||||
a.btn.nodropdown-toggle#languageDropdown(href="javascript:;" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false") Language
|
||||
|
||||
.noscriptdropdown(aria-labelledby="languageDropdown")
|
||||
each language in languages
|
||||
|
||||
@@ -3,9 +3,7 @@
|
||||
.modal-content
|
||||
.modal-header
|
||||
h5.modal-title Something alert worthy
|
||||
button.close(type="button" data-dismiss="modal" aria-hidden="true" aria-label="Close")
|
||||
span(aria-hidden="true")
|
||||
| ×
|
||||
button.btn-close(type="button" data-bs-dismiss="modal" aria-hidden="true" aria-label="Close")
|
||||
.modal-body
|
||||
.modal-footer
|
||||
button.btn.btn-outline-primary(type="button" data-dismiss="modal" data-cy="close-alert-btn") Close
|
||||
button.btn.btn-outline-primary(type="button" data-bs-dismiss="modal" data-cy="close-alert-btn") Close
|
||||
|
||||
@@ -3,9 +3,7 @@
|
||||
.modal-content
|
||||
.modal-header
|
||||
h5.modal-title Compilers
|
||||
button.close(type="button" data-dismiss="modal" aria-hidden="true" aria-label="Close")
|
||||
span(aria-hidden="true")
|
||||
| ×
|
||||
button.btn-close(type="button" data-bs-dismiss="modal" aria-hidden="true" aria-label="Close")
|
||||
.modal-body
|
||||
.card
|
||||
.card-body
|
||||
|
||||
@@ -3,12 +3,11 @@
|
||||
.modal-content
|
||||
.modal-header
|
||||
h5.modal-title Enter something here
|
||||
button.close(type="button" data-dismiss="modal" aria-hidden="true" aria-label="Close")
|
||||
span(aria-hidden="true")
|
||||
| ×
|
||||
button.btn-close(type="button" data-bs-dismiss="modal" aria-hidden="true" aria-label="Close")
|
||||
.modal-body
|
||||
.question
|
||||
input.question-answer
|
||||
.mb-3
|
||||
label.form-label.question
|
||||
input.form-control.question-answer
|
||||
.modal-footer
|
||||
button.btn.btn-light.no(type="button" data-dismiss="modal") Cancel
|
||||
button.btn.btn-light.yes(type="button" data-dismiss="modal") Ok
|
||||
button.btn.btn-light.no(type="button" data-bs-dismiss="modal") Cancel
|
||||
button.btn.btn-light.yes(type="button" data-bs-dismiss="modal") Ok
|
||||
|
||||
@@ -3,9 +3,7 @@
|
||||
.modal-content
|
||||
.modal-header
|
||||
h5.modal-title History
|
||||
button.close(type="button" data-dismiss="modal" aria-hidden="true" aria-label="Close")
|
||||
span(aria-hidden="true")
|
||||
| ×
|
||||
button.btn-close(type="button" data-bs-dismiss="modal" aria-hidden="true" aria-label="Close")
|
||||
.modal-body
|
||||
.card
|
||||
.card-body
|
||||
@@ -18,4 +16,4 @@
|
||||
div.src-content#load-history-src-display(style="height:600px;overflow-y:scroll;flex:2")
|
||||
div.monaco-placeholder
|
||||
.modal-footer
|
||||
button.btn.btn-outline-primary(type="button" data-dismiss="modal") Close
|
||||
button.btn.btn-outline-primary(type="button" data-bs-dismiss="modal") Close
|
||||
|
||||
@@ -3,9 +3,7 @@
|
||||
.modal-content
|
||||
.modal-header
|
||||
h5.modal-title Libraries
|
||||
button.close(type="button" data-dismiss="modal" aria-hidden="true" aria-label="Close")
|
||||
span(aria-hidden="true")
|
||||
| ×
|
||||
button.btn-close(type="button" data-bs-dismiss="modal" aria-hidden="true" aria-label="Close")
|
||||
.modal-body
|
||||
.card
|
||||
.card-body
|
||||
@@ -13,7 +11,8 @@
|
||||
.row
|
||||
.col-lg
|
||||
div(style='text-align: center')
|
||||
input.lib-search-input(value="" placeholder="Search text")
|
||||
.input-group.mb-3
|
||||
input.form-control.lib-search-input(value="" placeholder="Search text")
|
||||
button.btn.btn-primary.lib-search-button(type="button") Search
|
||||
hr
|
||||
.row
|
||||
|
||||
@@ -3,17 +3,15 @@
|
||||
.modal-content(style="max-width: unset")
|
||||
.modal-header
|
||||
h5.modal-title Load and save editor text
|
||||
button.close(type="button" data-dismiss="modal" aria-hidden="true" aria-label="Close")
|
||||
span(aria-hidden="true")
|
||||
| ×
|
||||
button.btn-close(type="button" data-bs-dismiss="modal" aria-label="Close")
|
||||
.modal-body
|
||||
.card
|
||||
.card-header
|
||||
ul.nav.nav-tabs.card-header-tabs(role="tablist")
|
||||
li.nav-item(role="presentation"): a.nav-link.active(href="#load-examples" role="tab" data-toggle="tab") Examples
|
||||
li.nav-item(role="presentation"): a.nav-link(href="#load-browser-local" role="tab" data-toggle="tab") Browser-local storage
|
||||
li.nav-item(role="presentation"): a.nav-link(href="#load-browser-local-history" role="tab" data-toggle="tab") Browser-local history
|
||||
li.nav-item(role="presentation"): a.nav-link(href="#load-file-system" role="tab" data-toggle="tab") File system
|
||||
li.nav-item(role="presentation"): a.nav-link.active(href="#load-examples" role="tab" data-bs-toggle="tab") Examples
|
||||
li.nav-item(role="presentation"): a.nav-link(href="#load-browser-local" role="tab" data-bs-toggle="tab") Browser-local storage
|
||||
li.nav-item(role="presentation"): a.nav-link(href="#load-browser-local-history" role="tab" data-bs-toggle="tab") Browser-local history
|
||||
li.nav-item(role="presentation"): a.nav-link(href="#load-file-system" role="tab" data-bs-toggle="tab") File system
|
||||
.card-body.tab-content
|
||||
#load-examples.tab-pane.active(role="tabpanel")
|
||||
h4.card-title Load from examples:
|
||||
@@ -23,16 +21,15 @@
|
||||
h4.card-title Load from browser-local storage:
|
||||
ul.local-storage.small-v-scrollable
|
||||
li.template
|
||||
a.mr-3(href="javascript:;")
|
||||
button.overwrite.btn.btn-sm.btn-light.mr-1
|
||||
span.fa.fa-edit.mr-1
|
||||
a.me-3(href="javascript:;")
|
||||
button.overwrite.btn.btn-sm.btn-light.me-1
|
||||
span.fa.fa-edit.me-1
|
||||
| Overwrite
|
||||
button.delete.btn.btn-sm.btn-light
|
||||
span.fa.fa-trash.mr-1
|
||||
span.fa.fa-trash.me-1
|
||||
| Delete
|
||||
.input-group
|
||||
input.save-name(type="text" size="20" placeholder="Set name of state")
|
||||
.input-group-append
|
||||
.input-group.mb-3
|
||||
input.form-control.save-name(type="text" placeholder="Set name of state")
|
||||
button.btn.btn-light.save-button(type="button") Save to browser-local storage
|
||||
#load-browser-local-history.tab-pane(role="tabpanel")
|
||||
h4.card-title Load from browser-local history:
|
||||
@@ -40,9 +37,10 @@
|
||||
li.template: a(href="javascript:;")
|
||||
#load-file-system.tab-pane(role="tabpanel")
|
||||
h4.card-title Load/save to your system
|
||||
label.btn.btn-outline-secondary.btn-file(role="button") Load from a local file
|
||||
input.local-file(type="file")
|
||||
label.btn.btn-outline-secondary.btn-file.save-btn(role="button") Save to file
|
||||
input.save-file(type="button")
|
||||
.mb-3
|
||||
label.form-label Load from a local file
|
||||
input.form-control.local-file(type="file")
|
||||
.mb-3
|
||||
button.btn.btn-outline-secondary.save-btn(type="button") Save to file
|
||||
.modal-footer
|
||||
button.btn.btn-outline-primary(type="button" data-dismiss="modal" aria-label="Close") Close
|
||||
button.btn.btn-outline-primary(type="button" data-bs-dismiss="modal" aria-label="Close") Close
|
||||
|
||||
@@ -3,9 +3,7 @@
|
||||
.modal-content
|
||||
.modal-header
|
||||
h5.modal-title Compiler overrides
|
||||
button.close(type="button" data-dismiss="modal" aria-hidden="true" aria-label="Close")
|
||||
span(aria-hidden="true")
|
||||
| ×
|
||||
button.btn-close(type="button" data-bs-dismiss="modal" aria-hidden="true" aria-label="Close")
|
||||
.modal-body
|
||||
.card
|
||||
.card-body
|
||||
@@ -25,8 +23,8 @@
|
||||
span.override-name Compiler environment variables
|
||||
.card-body
|
||||
span.description One environment variable per line, KEY=VALUE, that will be set during compilation.
|
||||
span.custom-override
|
||||
textarea.envvars(cols="30")
|
||||
span
|
||||
textarea.form-control.envvars(cols="30", rows="3")
|
||||
.possible-overrides.items
|
||||
.overrides-favorites-col.col-md
|
||||
h6 Favorites
|
||||
|
||||
@@ -3,9 +3,7 @@
|
||||
.modal-content
|
||||
.modal-header
|
||||
h5.modal-title Rename Pane
|
||||
button.close(type="button" data-dismiss="modal" aria-hidden="true" aria-label="Close")
|
||||
span(aria-hidden="true")
|
||||
| ×
|
||||
button.btn-close(type="button" data-bs-dismiss="modal" aria-hidden="true" aria-label="Close")
|
||||
.modal-body
|
||||
.card
|
||||
.card-body
|
||||
@@ -13,5 +11,5 @@
|
||||
.input-group
|
||||
input#renamepaneinput.form-control.panename(type="text" placeholder="New pane name" size="1024")
|
||||
.modal-footer
|
||||
button.btn.btn-outline-secondary(type="button" data-dismiss="modal") Close
|
||||
button#renamepanesubmit.btn.btn-outline-primary(type="submit" data-dismiss="modal" value="Save Changes") Save Changes
|
||||
button.btn.btn-outline-secondary(type="button" data-bs-dismiss="modal") Close
|
||||
button#renamepanesubmit.btn.btn-outline-primary(type="submit" data-bs-dismiss="modal" value="Save Changes") Save Changes
|
||||
|
||||
@@ -3,9 +3,7 @@
|
||||
.modal-content
|
||||
.modal-header
|
||||
h5.modal-title Runtime tools
|
||||
button.close(type="button" data-dismiss="modal" aria-hidden="true" aria-label="Close")
|
||||
span(aria-hidden="true")
|
||||
| ×
|
||||
button.btn-close(type="button" data-bs-dismiss="modal" aria-hidden="true" aria-label="Close")
|
||||
.modal-body
|
||||
.card
|
||||
.card-body
|
||||
@@ -23,8 +21,8 @@
|
||||
span.runtimetool-name Runtime environment variables
|
||||
.card-body
|
||||
span.description One environment variable per line, KEY=VALUE.
|
||||
span.custom-runtimetool
|
||||
textarea.envvars(cols="30")
|
||||
span
|
||||
textarea.form-control.envvars(cols="30", rows="3")
|
||||
.possible-runtimetools.items
|
||||
.runtimetools-favorites-col.col-md
|
||||
h6 Favorites
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
mixin checkbox(cls, text)
|
||||
.checkbox
|
||||
label
|
||||
input(class=cls type="checkbox")
|
||||
!= text
|
||||
.form-check
|
||||
input.form-check-input(class=cls type="checkbox" id="settings-checkbox-"+cls)
|
||||
label.form-check-label(for="settings-checkbox-"+cls)!= text
|
||||
|
||||
mixin select(cls, text)
|
||||
div
|
||||
label!= text
|
||||
select(class=cls)
|
||||
.mb-3
|
||||
label.form-label(for="settings-select-"+cls)!= text
|
||||
select.form-select(class=cls id="settings-select-"+cls)
|
||||
|
||||
mixin input(cls, type, text, style)
|
||||
div
|
||||
label!= text
|
||||
input(class=cls type=type style=style)
|
||||
.mb-3
|
||||
label.form-label(for="settings-input-"+cls)!= text
|
||||
input.form-control(class=cls type=type style=style id="settings-input-"+cls)
|
||||
|
||||
|
||||
#settings.modal.fade.gl_keep(tabindex="-1" role="dialog")
|
||||
@@ -21,8 +20,7 @@ mixin input(cls, type, text, style)
|
||||
.modal-header
|
||||
h5.modal-title
|
||||
| Compiler Explorer Settings
|
||||
button.close(type="button" data-dismiss="modal" aria-label="Close")
|
||||
span(aria-hidden="true") ×
|
||||
button.btn-close(type="button" data-bs-dismiss="modal" aria-label="Close")
|
||||
.modal-body
|
||||
.card
|
||||
.card-header
|
||||
@@ -30,53 +28,54 @@ mixin input(cls, type, text, style)
|
||||
| preserved as part of shared URLs, and are persisted locally using browser
|
||||
| local storage.
|
||||
ul.nav.nav-tabs.card-header-tabs(role="tablist")
|
||||
li.nav-item(role="presentation"): a.nav-link.active(href="#colouring" role="tab" data-toggle="tab") Colouring
|
||||
li.nav-item(role="presentation"): a.nav-link(href="#site-behaviour" role="tab" data-toggle="tab") Site behaviour
|
||||
li.nav-item(role="presentation"): a.nav-link(href="#keybindings" role="tab" data-toggle="tab") Keybindings
|
||||
li.nav-item(role="presentation"): a.nav-link(href="#editor" role="tab" data-toggle="tab") Editor
|
||||
li.nav-item(role="presentation"): a.nav-link(href="#compilation" role="tab" data-toggle="tab") Compilation
|
||||
li.nav-item(role="presentation"): a.nav-link.active(href="#colouring" role="tab" data-bs-toggle="tab") Colouring
|
||||
li.nav-item(role="presentation"): a.nav-link(href="#site-behaviour" role="tab" data-bs-toggle="tab") Site behaviour
|
||||
li.nav-item(role="presentation"): a.nav-link(href="#keybindings" role="tab" data-bs-toggle="tab") Keybindings
|
||||
li.nav-item(role="presentation"): a.nav-link(href="#editor" role="tab" data-bs-toggle="tab") Editor
|
||||
li.nav-item(role="presentation"): a.nav-link(href="#compilation" role="tab" data-bs-toggle="tab") Compilation
|
||||
.card-body.tab-content
|
||||
#colouring.tab-pane.active.form-group(role="group")
|
||||
#colouring.tab-pane.active(role="group")
|
||||
+select("theme", "Site theme")
|
||||
+checkbox("colourise", "Colourise lines to show how the source maps to the output")
|
||||
+checkbox("alwaysEnableAllSchemes", "Make all colour schemes available regardless of theme")
|
||||
+select("colourScheme", "Line highlighting colour scheme")
|
||||
#site-behaviour.tab-pane.form-group(role="group")
|
||||
label
|
||||
| Default language
|
||||
#site-behaviour.tab-pane(role="group")
|
||||
.mb-3
|
||||
label.form-label(for="settings-select-defaultLanguage") Default language
|
||||
small(style="margin-left: 3px")
|
||||
span.fas.fa-info-circle(title="New editors only (Reset UI to clear yours)" aria-label="New editors only (Reset UI to clear yours)")
|
||||
select.defaultLanguage
|
||||
select.form-select.defaultLanguage(id="settings-select-defaultLanguage")
|
||||
+checkbox("keepMultipleTabs", "Keep page status per tab")
|
||||
+checkbox("allowStoreCodeDebug", "Allow my source code to be temporarily stored for diagnostic purposes in the event of an error")
|
||||
+checkbox("newEditorLastLang", "Use last selected language when opening new Editors")
|
||||
+checkbox("enableCommunityAds", "Show community events")
|
||||
#keybindings.tab-pane.form-group(role="group")
|
||||
#keybindings.tab-pane(role="group")
|
||||
+checkbox("useVim", "Vim editor mode")
|
||||
.the-save-option-to-auto-share
|
||||
label
|
||||
mb-3
|
||||
label.form-label(for="settings-checkbox-enableCtrlS")
|
||||
kbd Ctrl
|
||||
| +
|
||||
kbd S
|
||||
| behaviour
|
||||
select.enableCtrlS
|
||||
.checkbox.the-save-option-to-tree-save
|
||||
label
|
||||
input.enableCtrlStree(type="checkbox")
|
||||
select.form-select.enableCtrlS(id="settings-checkbox-enableCtrlS")
|
||||
.form-check.the-save-option-to-tree-save
|
||||
input.form-check-input.enableCtrlStree(type="checkbox" id="settings-checkbox-enableCtrlStree")
|
||||
label.form-check-label(for="settings-checkbox-enableCtrlStree")
|
||||
| Make
|
||||
kbd Ctrl
|
||||
| +
|
||||
kbd S
|
||||
| include and save the file to a Tree if that's added to the UI
|
||||
.checkbox.the-popup-dialog-box-option
|
||||
label
|
||||
input.enableSharingPopover(type="checkbox")
|
||||
.form-check.the-popup-dialog-box-option
|
||||
input.form-check-input.enableSharingPopover(type="checkbox" id="settings-checkbox-enableSharingPopover")
|
||||
label.form-check-label(for="settings-checkbox-enableSharingPopover")
|
||||
| Pop up a dialog box when
|
||||
kbd Ctrl
|
||||
| +
|
||||
kbd S
|
||||
| is set to create a short link.
|
||||
#editor.tab-pane.form-group(role="group")
|
||||
#editor.tab-pane(role="group")
|
||||
+input("editorsFFont", "text", "Desired Font Family in editors", "width:100%")
|
||||
+select("defaultFontScale", "Default font scale")
|
||||
+checkbox("editorsFLigatures", "Enable font ligatures")
|
||||
@@ -97,14 +96,15 @@ mixin input(cls, type, text, style)
|
||||
+checkbox("wordWrap", "Enable Word Wrapping")
|
||||
+checkbox("enableCodeLens", "Enable CodeLens features (requires refresh to take effect)")
|
||||
+checkbox("colouriseBrackets", "Colourise matching bracket pairs")
|
||||
#compilation.tab-pane.form-group(role="group")
|
||||
#compilation.tab-pane(role="group")
|
||||
div
|
||||
+checkbox("compileOnChange", "Compile automatically when source changes")
|
||||
+checkbox("autoDelayBeforeCompile", "Use automatic delay before compiling")
|
||||
div
|
||||
label Delay before compiling:
|
||||
mb-3
|
||||
label.form-label(for="settings-input-delay") Delay before compiling:
|
||||
span.delay-current-value
|
||||
.slider-input
|
||||
.slider-input(id="settings-input-delay")
|
||||
b 0.25s
|
||||
input.delay(type="range")
|
||||
b 3s
|
||||
@@ -112,4 +112,4 @@ mixin input(cls, type, text, style)
|
||||
+checkbox("executorCompileOnChange", "Compile executor automatically when arguments change")
|
||||
+checkbox("shakeStatusIconOnWarnings", "Shake the status icon on argument warnings")
|
||||
.modal-footer
|
||||
button.btn.btn-outline-primary(type="button" data-dismiss="modal") Close
|
||||
button.btn.btn-outline-primary(type="button" data-bs-dismiss="modal") Close
|
||||
|
||||
@@ -3,26 +3,23 @@
|
||||
.modal-content
|
||||
.modal-header
|
||||
h5.modal-title Share
|
||||
button.close(type="button" data-dismiss="modal" aria-hidden="true" aria-label="Close")
|
||||
span(aria-hidden="true")
|
||||
| ×
|
||||
button.btn-close(type="button" data-bs-dismiss="modal" aria-hidden="true" aria-label="Close")
|
||||
.modal-body
|
||||
.card
|
||||
.card-body
|
||||
.container
|
||||
label.form-label.visually-hidden(for="share-permalink") Share URL
|
||||
.input-group
|
||||
input.form-control.permalink(type="text" placeholder="Loading" readonly size="1024")
|
||||
.input-group-append
|
||||
button.btn.btn-outline-secondary.clippy(type="button" data-clipboard-target="#sharelinkdialog .permalink" title="Copy to clipboard")
|
||||
input.form-control.permalink#share-permalink(type="text" placeholder="Loading" readonly size="1024" aria-describedby="share-permalink-help")
|
||||
button.btn.btn-outline-secondary.clippy(type="button" data-clipboard-target="#sharelinkdialog .permalink" title="Copy to clipboard" aria-label="Copy to clipboard")
|
||||
span.fa.fa-clipboard
|
||||
#embedsettings.form-group(role="group")
|
||||
.checkbox
|
||||
label
|
||||
input.readOnly(type="checkbox")
|
||||
| Read Only
|
||||
.checkbox
|
||||
label
|
||||
input.hideEditorToolbars(type="checkbox")
|
||||
| Hide Editor Toolbars
|
||||
small.form-text.text-muted#share-permalink-help Use this URL to share your code with others
|
||||
#embedsettings.mb-3(role="group")
|
||||
.form-check
|
||||
input.form-check-input.readOnly(type="checkbox" id="share-checkbox-readonly")
|
||||
label.form-check-label(for="share-checkbox-readonly") Read Only
|
||||
.form-check
|
||||
input.form-check-input.hideEditorToolbars(type="checkbox" id="share-checkbox-hideEditorToolbars")
|
||||
label.form-check-label(for="share-checkbox-hideEditorToolbars") Hide Editor Toolbars
|
||||
if sharingEnabled
|
||||
.socialsharing.mt-2
|
||||
|
||||
@@ -3,9 +3,7 @@
|
||||
.modal-content
|
||||
.modal-header
|
||||
h5.modal-title Load Site Template
|
||||
button.close(type="button" data-dismiss="modal" aria-hidden="true" aria-label="Close")
|
||||
span(aria-hidden="true")
|
||||
| ×
|
||||
button.btn-close(type="button" data-bs-dismiss="modal" aria-hidden="true" aria-label="Close")
|
||||
.modal-body
|
||||
.container
|
||||
.row(id="site-template-modal-row")
|
||||
|
||||
@@ -3,10 +3,8 @@
|
||||
.modal-content
|
||||
.modal-header
|
||||
h5.modal-title Timing
|
||||
button.close(type="button" data-dismiss="modal" aria-hidden="true" aria-label="Close")
|
||||
span(aria-hidden="true")
|
||||
| ×
|
||||
button.btn-close(type="button" data-bs-dismiss="modal" aria-hidden="true" aria-label="Close")
|
||||
.modal-body
|
||||
#chart
|
||||
.modal-footer
|
||||
button.btn.btn-outline-primary(type="button" data-dismiss="modal") Close
|
||||
button.btn.btn-outline-primary(type="button" data-bs-dismiss="modal") Close
|
||||
|
||||
@@ -3,10 +3,8 @@
|
||||
.modal-content
|
||||
.modal-header
|
||||
h5.modal-title Well, do you or not?
|
||||
button.close(type="button" data-dismiss="modal" aria-hidden="true" aria-label="Close")
|
||||
span(aria-hidden="true")
|
||||
| ×
|
||||
button.btn-close(type="button" data-bs-dismiss="modal" aria-hidden="true" aria-label="Close")
|
||||
.modal-body
|
||||
.modal-footer
|
||||
button.btn.btn-link.no(type="button" data-dismiss="modal") No
|
||||
button.btn.btn-link.yes(type="button" data-dismiss="modal") Yes
|
||||
button.btn.btn-link.no(type="button" data-bs-dismiss="modal") No
|
||||
button.btn.btn-link.yes(type="button" data-bs-dismiss="modal") Yes
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
.btn-group.btn-group-sm(role="group")
|
||||
select.function-selector
|
||||
.btn-group.btn-group-sm(role="group" aria-label="CFG Export")
|
||||
button.btn.btn-sm.btn-light.dropdown-toggle(type="button" title="LLVM Opt Pass Options" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" aria-label="Set output options")
|
||||
button.btn.btn-sm.btn-light.dropdown-toggle(type="button" title="LLVM Opt Pass Options" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" aria-label="Set output options")
|
||||
span.fas.fa-arrow-down
|
||||
span.hideable Export
|
||||
.dropdown-menu
|
||||
|
||||
@@ -8,7 +8,7 @@ mixin optionButton(bind, isActive, text, title)
|
||||
.top-bar.btn-toolbar.bg-light(role="toolbar")
|
||||
include ../../font-size
|
||||
.btn-group.btn-group-sm.options(role="group")
|
||||
button.btn.btn-sm.btn-light.dropdown-toggle(type="button" title="ClangIR Options" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" aria-label="Set output options")
|
||||
button.btn.btn-sm.btn-light.dropdown-toggle(type="button" title="ClangIR Options" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" aria-label="Set output options")
|
||||
span.fas.fa-anchor
|
||||
span.hideable Options
|
||||
.dropdown-menu
|
||||
|
||||
@@ -10,7 +10,7 @@ mixin newPaneButton(classId, text, title, label, icon)
|
||||
button.btn.btn-sm.btn-light.load-save(title="Load or save text" aria-label="Load or save text")
|
||||
span.fa.fa-save
|
||||
span.hideable Save/Load
|
||||
button.dropdown-toggle.btn.btn-sm.btn-light.add-pane(type="button" title="Add a new pane" aria-label="Add a new pane" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" data-cy="new-editor-dropdown-btn")
|
||||
button.dropdown-toggle.btn.btn-sm.btn-light.add-pane(type="button" title="Add a new pane" aria-label="Add a new pane" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" data-cy="new-editor-dropdown-btn")
|
||||
span.fa.fa-plus
|
||||
span.hideable Add new...
|
||||
.dropdown-menu(data-cy="new-editor-pane-dropdown")
|
||||
@@ -18,7 +18,7 @@ mixin newPaneButton(classId, text, title, label, icon)
|
||||
+newPaneButton("add-executor", "Execution Only", "Add a new executor for this source", "New executor", "fas fa-microchip")
|
||||
+newPaneButton("conformance", "Conformance View", "Add a new conformance view", "New conformance view", "fa fa-list")
|
||||
+newPaneButton("add-editor", "Source Editor", "Add a new source editor", "New source editor", "fa fa-code")
|
||||
button#vim-flag.btn.btn-sm.btn-light(title="Toggle Vim Keybindings")
|
||||
button.vim-flag.btn.btn-sm.btn-light(title="Toggle Vim Keybindings")
|
||||
span.fab.fa-vimeo-v
|
||||
span.hideable Vim
|
||||
if thirdPartyIntegrationEnabled
|
||||
@@ -35,10 +35,10 @@ mixin newPaneButton(classId, text, title, label, icon)
|
||||
button.btn.btn-sm.btn-outline-info.ctrlSNothing(disabled=true style="display: none")
|
||||
span.fas.fa-smile
|
||||
|
||||
.btn-group.btn-group-sm.ml-auto(role="group" aria-label="Editor language")
|
||||
.btn-group.btn-group-sm.ms-auto(role="group" aria-label="Editor language")
|
||||
button.btn.btn-sm.language-info
|
||||
span.fas.fa-info
|
||||
select.change-language(title="Change this editor's (and associated panels) language" placeholder="Language" disabled=embedded && readOnly)
|
||||
div.currentCursorPosition
|
||||
div#v-status
|
||||
div.v-status
|
||||
.monaco-placeholder
|
||||
|
||||
@@ -10,4 +10,4 @@
|
||||
button.btn.btn-sm.btn-light.select-all(type="button" title="Select all lines")
|
||||
span.fa.fa-align-justify(style="border: 1px dotted white;border-radius: 0.125em;padding: 2px")
|
||||
span.hideable Select all
|
||||
pre.content.output-content
|
||||
pre.content.output-content(aria-live="polite" role="log" aria-label="Compiler output")
|
||||
|
||||
@@ -6,35 +6,31 @@ mixin newPaneButton(classId, text, title, icon)
|
||||
#compiler
|
||||
.top-bar.btn-toolbar.bg-light(role="toolbar")
|
||||
.btn-group.btn-group-sm(role="group" aria-label="Compiler picker")
|
||||
.input-group
|
||||
.input-group-prepend
|
||||
.input-group
|
||||
select.compiler-picker
|
||||
.input-group-append
|
||||
button.btn.btn-sm.btn-light.input-group-text.picker-popout-button(data-trigger="click" style="cursor: pointer;" role="button" title="Compiler picker popout")
|
||||
span
|
||||
i.fa-solid.fa-arrow-up-right-from-square
|
||||
.input-group-append
|
||||
button.btn.btn-sm.btn-light.input-group-text.prepend-options(data-trigger="click" style="cursor: pointer;" role="button" title="All compilation options")
|
||||
span.status-icon
|
||||
input.options.form-control(type="text" placeholder="Compiler options..." size="256" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false")
|
||||
.input-group-append.populararguments(title="Popular arguments")
|
||||
button.btn.btn-sm.btn-light.btn-outline-secondary.dropdown-toggle.dropdown-toggle-split.popular-arguments-btn(type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false")
|
||||
span.sr-only Popular arguments
|
||||
div.dropdown-menu.dropdown-menu-right
|
||||
input.options.form-control(type="text" placeholder="Compiler options..." size="256" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" aria-label="Compiler options")
|
||||
.populararguments(title="Popular arguments")
|
||||
button.btn.btn-sm.btn-light.btn-outline-secondary.dropdown-toggle.dropdown-toggle-split.popular-arguments-btn(type="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false")
|
||||
span.visually-hidden Popular arguments
|
||||
div.dropdown-menu.dropdown-menu-end
|
||||
button.dropdown-item.btn.btn-light.btn-sm
|
||||
.argmenuitem
|
||||
span.argtitle Detailed Compiler Flags
|
||||
span.argdescription Open a new window to edit verbose compiler flags
|
||||
include ../../font-size
|
||||
.btn-group.btn-group-sm.filters(role="group")
|
||||
button.btn.btn-sm.btn-light.dropdown-toggle(type="button" title="Compiler output options" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" aria-label="Change how the compiler's output is generated")
|
||||
button.btn.btn-sm.btn-light.dropdown-toggle(type="button" title="Compiler output options" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" aria-label="Change how the compiler's output is generated")
|
||||
span.fas.fa-cog
|
||||
span.hideable Output...
|
||||
.dropdown-menu
|
||||
include ../../options-output
|
||||
.btn-group.btn-group-sm.filters(role="group")
|
||||
button.btn.btn-sm.btn-light.dropdown-toggle(type="button" title="Compiler output filters" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" aria-label="Change how the compiler output is filtered")
|
||||
button.btn.btn-sm.btn-light.dropdown-toggle(type="button" title="Compiler output filters" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" aria-label="Change how the compiler output is filtered")
|
||||
span.fas.fa-filter
|
||||
span.hideable Filter...
|
||||
.dropdown-menu
|
||||
@@ -48,10 +44,10 @@ mixin newPaneButton(classId, text, title, icon)
|
||||
span.fas.fa-wrench
|
||||
span.dp-text.hideable Overrides
|
||||
.btn-group.btn-group-sm(role="group")
|
||||
button.btn.btn-sm.btn-light.dropdown-toggle.add-pane(type="button" title="Add a new pane" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" aria-label="Add new element for this compiler" data-cy="new-compiler-dropdown-btn")
|
||||
button.btn.btn-sm.btn-light.dropdown-toggle.add-pane(type="button" title="Add a new pane" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" aria-label="Add new element for this compiler" data-cy="new-compiler-dropdown-btn")
|
||||
span.fas.fa-plus
|
||||
span.hideable Add new...
|
||||
.dropdown-menu.dropdown-menu-right.new-pane-dropdown(data-cy="new-compiler-pane-dropdown")
|
||||
.dropdown-menu.dropdown-menu-end.new-pane-dropdown(data-cy="new-compiler-pane-dropdown")
|
||||
+newPaneButton("add-compiler", "Clone Compiler", "Clone this compiler window (click or drag)", "far fa-clone")
|
||||
+newPaneButton("create-executor", "Executor From This", "Create executor from this compiler", "fas fa-microchip")
|
||||
+newPaneButton("view-optimization", "Opt Remarks", "Show optimization remarks", "fas fa-weight")
|
||||
@@ -73,22 +69,21 @@ mixin newPaneButton(classId, text, title, icon)
|
||||
+newPaneButton("view-gnatdebug", "GNAT Debug Expanded Code", "Show GNAT debug expanded code", "fas fa-tree")
|
||||
+newPaneButton("view-cfg", "Control Flow Graph", "Show assembly control flow graphs", "fas fa-exchange-alt")
|
||||
.btn-group.btn-group-sm(role="group")
|
||||
button.btn.btn-sm.btn-light.dropdown-toggle.add-tool(type="button" title="Add tool" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" aria-label="Add tooling to this editor and compiler")
|
||||
button.btn.btn-sm.btn-light.dropdown-toggle.add-tool(type="button" title="Add tool" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" aria-label="Add tooling to this editor and compiler")
|
||||
span.fas.fa-screwdriver
|
||||
span.hideable Add tool...
|
||||
.dropdown-menu.dropdown-menu-right.new-tool-dropdown
|
||||
.dropdown-menu.dropdown-menu-end.new-tool-dropdown
|
||||
.monaco-placeholder
|
||||
.bottom-bar.bg-light
|
||||
if !embedded
|
||||
.btn-group.btn-group-sm
|
||||
.input-group
|
||||
.input-group-prepend
|
||||
button.btn.btn-sm.btn-light.clear-cache(title="Clear cache & recompile")
|
||||
button.btn.btn-sm.btn-light.clear-cache(title="Clear cache & recompile" aria-label="Clear cache and recompile")
|
||||
span.fas.fa-redo
|
||||
button.btn.btn-sm.btn-light.output-btn(data-cy="new-output-pane-btn")
|
||||
button.btn.btn-sm.btn-light.output-btn(data-cy="new-output-pane-btn" aria-label="Show compiler output")
|
||||
span.fas.fa-receipt.status-text
|
||||
| Output
|
||||
span.output-count
|
||||
span.output-count(aria-live="polite")
|
||||
| (
|
||||
span.text-count
|
||||
| 0
|
||||
@@ -96,11 +91,11 @@ mixin newPaneButton(classId, text, title, icon)
|
||||
span.err-count
|
||||
| 0
|
||||
| )
|
||||
span.short-compiler-name.mr-1
|
||||
button.btn.btn-sm.btn-light.full-compiler-name(data-trigger="click" style="cursor: pointer;" role="button")
|
||||
span.short-compiler-name.me-1(aria-hidden="true")
|
||||
button.btn.btn-sm.btn-light.full-compiler-name(data-trigger="click" style="cursor: pointer;" role="button" aria-label="Show compiler information")
|
||||
span.fas.fa-info
|
||||
span.compile-info.mr-1(title="Compilation info")
|
||||
button.btn.btn-sm.btn-light.full-timing-info(data-trigger="click" style="cursor: pointer;" role="button")
|
||||
span.compile-info.me-1(title="Compilation info" aria-label="Compilation information")
|
||||
button.btn.btn-sm.btn-light.full-timing-info(data-trigger="click" style="cursor: pointer;" role="button" aria-label="Show full timing information")
|
||||
span.fas.fa-chart-bar
|
||||
button.btn.btn-sm.btn-light.compiler-license(data-trigger="click" style="cursor: pointer;" role="button")
|
||||
button.btn.btn-sm.btn-light.compiler-license(data-trigger="click" style="cursor: pointer;" role="button" aria-label="View compiler license")
|
||||
span Compiler License
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
.top-bar.btn-toolbar.bg-light(role="toolbar")
|
||||
include ../../font-size
|
||||
.btn-group.btn-group-sm(role="group")
|
||||
select.change-device(placeholder="Select a device...")
|
||||
select.form-select.change-device(placeholder="Select a device...")
|
||||
.monaco-placeholder
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
#diff
|
||||
.top-bar.btn-toolbar.bg-light(role="toolbar")
|
||||
.top-bar.btn-toolbar.bg-light.py-1.d-flex.align-items-center(role="toolbar")
|
||||
include ../../font-size
|
||||
.btn-group.btn-group-sm
|
||||
.input-group.input-group-sm.mb-auto
|
||||
.input-group-prepend
|
||||
.btn-group.btn-group-sm.flex-grow-1.me-2
|
||||
.input-group.input-group-sm.w-100
|
||||
label.input-group-text
|
||||
| Left:
|
||||
select.diff-picker.lhs(placeholder="Select compiler...")
|
||||
select.difftype-picker.lhsdifftype(placeholder="...")
|
||||
.btn-group.btn-group-sm.ml-4
|
||||
.input-group.input-group-sm.mb-auto
|
||||
.input-group-prepend
|
||||
.btn-group.btn-group-sm.flex-grow-1
|
||||
.input-group.input-group-sm.w-100
|
||||
label.input-group-text
|
||||
| Right:
|
||||
select.diff-picker.rhs(placeholder="Select compiler...")
|
||||
|
||||
@@ -29,41 +29,38 @@
|
||||
span.hideable Compiler output
|
||||
.top-bar.btn-toolbar.bg-light.panel-compilation(role="toolbar")
|
||||
.btn-group.btn-group-sm(role="group" aria-label="Compiler picker")
|
||||
.input-group
|
||||
.input-group-prepend
|
||||
.input-group
|
||||
select.compiler-picker
|
||||
.input-group-append
|
||||
button.btn.btn-sm.btn-light.input-group-text.picker-popout-button(data-trigger="click" style="cursor: pointer;" role="button" title="Compiler picker popout")
|
||||
span
|
||||
i.fa-solid.fa-arrow-up-right-from-square
|
||||
.input-group-append
|
||||
button.btn.btn-sm.btn-light.input-group-text.prepend-options(data-trigger="click" style="cursor: pointer;" role="button" title="All compilation options")
|
||||
span.btn.btn-sm.btn-light.status-icon
|
||||
input.compilation-options.form-control(type="text" placeholder="Compiler options..." size="256" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false")
|
||||
label.visually-hidden(for="compilation-options") Compiler options for execution
|
||||
input.compilation-options.form-control#compilation-options(type="text" placeholder="Compiler options..." size="256" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" aria-label="Compiler options for execution")
|
||||
// TODO: Maybe enable this in the future?
|
||||
//.input-group-append.populararguments(title="Popular arguments")
|
||||
button.btn.btn-sm.btn-light.btn-outline-secondary.dropdown-toggle.dropdown-toggle-split.popular-arguments-btn(type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false")
|
||||
span.sr-only Popular arguments
|
||||
div.dropdown-menu.dropdown-menu-right
|
||||
//.populararguments(title="Popular arguments")
|
||||
button.btn.btn-sm.btn-light.btn-outline-secondary.dropdown-toggle.dropdown-toggle-split.popular-arguments-btn(type="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false")
|
||||
span.visually-hidden Popular arguments
|
||||
div.dropdown-menu.dropdown-menu-end
|
||||
button.dropdown-item.btn.btn-light.btn-sm
|
||||
.argmenuitem
|
||||
span.argtitle Detailed Compiler Flags
|
||||
span.argdescription Open a new window to edit verbose compiler flags
|
||||
.top-bar.btn-toolbar.bg-light.panel-args.d-none(role="toolbar")
|
||||
input.execution-arguments.form-control(type="text" placeholder="Execution arguments..." size="256" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false")
|
||||
input.execution-arguments.form-control(type="text" placeholder="Execution arguments..." size="256" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" aria-label="Execution arguments")
|
||||
.top-bar.btn-toolbar.bg-light.panel-stdin.d-none(role="toolbar")
|
||||
textarea.execution-stdin.form-control(placeholder="Execution stdin..." cols="1024" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" aria-multiline="false" style="resize: vertical")
|
||||
textarea.execution-stdin.form-control(placeholder="Execution stdin..." cols="1024" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" aria-multiline="true" style="resize: vertical" aria-label="Standard input for program execution")
|
||||
pre.content
|
||||
.execution-status
|
||||
.compiler-output
|
||||
.execution-output
|
||||
.execution-status(aria-live="polite" role="status" aria-label="Execution status")
|
||||
.compiler-output(aria-live="polite" role="log" aria-label="Compiler output")
|
||||
.execution-output(aria-live="polite" role="log" aria-label="Program execution output")
|
||||
.bottom-bar.bg-light
|
||||
button.btn.btn-sm.btn-light.rerun(title="Rerun")
|
||||
button.btn.btn-sm.btn-light.rerun(title="Rerun" aria-label="Rerun execution")
|
||||
span.fas.fa-circle-play
|
||||
button.btn.btn-sm.btn-light.clear-cache(title="Clear cache & recompile")
|
||||
button.btn.btn-sm.btn-light.clear-cache(title="Clear cache & recompile" aria-label="Clear cache and recompile")
|
||||
span.fas.fa-redo
|
||||
span.short-compiler-name
|
||||
button.btn.btn-sm.btn-light.fas.fa-info.full-compiler-name(data-trigger="click" style="cursor: pointer;" role="button")
|
||||
span.compile-time(title="Compilation time (Result size)")
|
||||
button.btn.btn-sm.btn-light.fas.fa-chart-bar.full-timing-info(data-trigger="click" style="cursor: pointer;" role="button")
|
||||
span.short-compiler-name(aria-hidden="true")
|
||||
button.btn.btn-sm.btn-light.fas.fa-info.full-compiler-name(data-trigger="click" style="cursor: pointer;" role="button" aria-label="Show compiler info")
|
||||
span.compile-time(title="Compilation time (Result size)" aria-label="Compilation time and result size")
|
||||
button.btn.btn-sm.btn-light.fas.fa-chart-bar.full-timing-info(data-trigger="click" style="cursor: pointer;" role="button" aria-label="Show full timing information")
|
||||
|
||||
@@ -10,7 +10,7 @@ mixin optionButton(bind, isActive, text, title)
|
||||
.btn-group.btn-group-sm(role="group")
|
||||
select.gccdump-pass-picker(placeholder="Select a pass...")
|
||||
.btn-group.btn-group-sm.dump-filters
|
||||
button.btn.btn-sm.btn-light.dropdown-toggle(type="button" title="Dump passes" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" aria-label="Available dump passes")
|
||||
button.btn.btn-sm.btn-light.dropdown-toggle(type="button" title="Dump passes" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" aria-label="Available dump passes")
|
||||
span.fas.fa-compass
|
||||
span.hideable Passes
|
||||
.dropdown-menu
|
||||
@@ -18,7 +18,7 @@ mixin optionButton(bind, isActive, text, title)
|
||||
+optionButton("rtlDump", true, "RTL Pass", "Show RTL passes")
|
||||
+optionButton("ipaDump", true, "IPA Pass", "Show IPA passes")
|
||||
.btn-group.btn-group-sm.dump-filters
|
||||
button.btn.btn-sm.btn-light.dropdown-toggle(type="button" title="Dump pass options" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" aria-label="Control the details of the dump")
|
||||
button.btn.btn-sm.btn-light.dropdown-toggle(type="button" title="Dump pass options" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" aria-label="Control the details of the dump")
|
||||
span.fas.fa-microchip
|
||||
span.hideable Options
|
||||
.dropdown-menu
|
||||
|
||||
@@ -13,14 +13,14 @@ mixin optionButton(bind, isActive, text, title)
|
||||
span Wrap lines
|
||||
input.d-none(type="checkbox" checked=false)
|
||||
.btn-group.btn-group-sm.options(role="group")
|
||||
button.btn.btn-sm.btn-light.dropdown-toggle(type="button" title="LLVM Opt Pass Options" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" aria-label="Set output options")
|
||||
button.btn.btn-sm.btn-light.dropdown-toggle(type="button" title="LLVM Opt Pass Options" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" aria-label="Set output options")
|
||||
span.fas.fa-anchor
|
||||
span.hideable Options
|
||||
.dropdown-menu
|
||||
+optionButton("demangle-symbols", true, "Demangle Symbols", "Demangle symbols")
|
||||
+optionButton("-fno-discard-value-names", true, "-fno-discard-value-names", "Keep value names instead of LLVM value numbers")
|
||||
.btn-group.btn-group-sm.filters(role="group")
|
||||
button.btn.btn-sm.btn-light.dropdown-toggle(type="button" title="LLVM Opt Pass Filters" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" aria-label="Set output filters")
|
||||
button.btn.btn-sm.btn-light.dropdown-toggle(type="button" title="LLVM Opt Pass Filters" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" aria-label="Set output filters")
|
||||
span.fas.fa-filter
|
||||
span.hideable Filters
|
||||
.dropdown-menu
|
||||
|
||||
@@ -8,7 +8,7 @@ mixin optionButton(bind, isActive, text, title)
|
||||
.top-bar.btn-toolbar.bg-light(role="toolbar")
|
||||
include ../../font-size
|
||||
.btn-group.btn-group-sm.options(role="group")
|
||||
button.btn.btn-sm.btn-light.dropdown-toggle(type="button" title="Opt Pass Options" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" aria-label="Set output options")
|
||||
button.btn.btn-sm.btn-light.dropdown-toggle(type="button" title="Opt Pass Options" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" aria-label="Set output options")
|
||||
span.fas.fa-anchor
|
||||
span.hideable Options
|
||||
.dropdown-menu
|
||||
@@ -16,7 +16,7 @@ mixin optionButton(bind, isActive, text, title)
|
||||
+optionButton("demangle-symbols", true, "Demangle Symbols", "Demangle symbols")
|
||||
+optionButton("-fno-discard-value-names", true, "-fno-discard-value-names", "Keep value names instead of LLVM value numbers")
|
||||
.btn-group.btn-group-sm.filters(role="group")
|
||||
button.btn.btn-sm.btn-light.dropdown-toggle(type="button" title="Opt Pass Filters" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" aria-label="Set output filters")
|
||||
button.btn.btn-sm.btn-light.dropdown-toggle(type="button" title="Opt Pass Filters" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" aria-label="Set output filters")
|
||||
span.fas.fa-filter
|
||||
span.hideable Filters
|
||||
.dropdown-menu
|
||||
@@ -26,7 +26,6 @@ mixin optionButton(bind, isActive, text, title)
|
||||
//- +optionButton("library-functions", true, "Filter Library Functions", "Filter library functions")
|
||||
.btn-group.btn-group-sm
|
||||
.input-group.input-group-sm.mb-auto
|
||||
.input-group-prepend
|
||||
label.input-group-text.opt-group-name
|
||||
| Function:
|
||||
select.opt-group-picker.group-selector(placeholder="Select group")
|
||||
|
||||
@@ -14,7 +14,7 @@ mixin optionButton(bind, isActive, text, title)
|
||||
input.d-none(type="checkbox" checked=false)
|
||||
// TODO: Options - display inlining context, color token (from col-num), remove duplicates
|
||||
.btn-group.btn-group-sm.filters(role="group")
|
||||
button.btn.btn-sm.btn-light.dropdown-toggle(type="button" title="Opt-Remarks Filters" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" aria-label="Set output filters")
|
||||
button.btn.btn-sm.btn-light.dropdown-toggle(type="button" title="Opt-Remarks Filters" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" aria-label="Set output filters")
|
||||
span.fas.fa-filter
|
||||
span.hideable Filters
|
||||
.dropdown-menu
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#tree
|
||||
.top-bar.btn-toolbar.bg-light.mainbar(role="toolbar")
|
||||
.btn-group.btn-group-sm.menu(role="group" aria-label="Menu")
|
||||
button.dropdown-toggle.btn.btn-sm.btn-light.file-menu(type="button" title="File" aria-label="File" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false")
|
||||
button.dropdown-toggle.btn.btn-sm.btn-light.file-menu(type="button" title="File" aria-label="File" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false")
|
||||
span.fa.fa-save
|
||||
span.hideable Project
|
||||
.dropdown-menu
|
||||
@@ -10,7 +10,7 @@
|
||||
span.dropdown-icon.fa.fa-save
|
||||
| Save
|
||||
.btn-group.btn-group-sm.options(role="group" aria-label="Tree settings")
|
||||
button.dropdown-toggle.btn.btn-sm.btn-light.add-pane(type="button" title="Add a new pane" aria-label="Add a new pane" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false")
|
||||
button.dropdown-toggle.btn.btn-sm.btn-light.add-pane(type="button" title="Add a new pane" aria-label="Add a new pane" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false")
|
||||
span.fa.fa-plus
|
||||
span.hideable Add new...
|
||||
.dropdown-menu
|
||||
@@ -27,19 +27,19 @@
|
||||
button.btn.btn-sm.btn-light.cmake-project(type="button" title="CMake project" data-bind="isCMakeProject" aria-pressed="false" aria-label="CMake project")
|
||||
span CMake
|
||||
input.d-none(type="checkbox" checked=false)
|
||||
.btn-group.btn-group-sm.ml-auto(role="group" aria-label="Language")
|
||||
.btn-group.btn-group-sm.ms-auto(role="group" aria-label="Language")
|
||||
select.change-language(title="Change the language" placeholder="Language" disabled=embedded && readOnly)
|
||||
.top-bar.btn-toolbar.bg-light.panel-args.d-none(role="toolbar")
|
||||
input.cmake-arguments.form-control(type="text" placeholder="CMake arguments..." size="256" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false")
|
||||
.top-bar.btn-toolbar.bg-light.panel-outputfile.d-none(role="toolbar")
|
||||
input.cmake-customOutputFilename.form-control(type="text" placeholder="output.s" size="256" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false")
|
||||
.tree.v-scroll
|
||||
ul.list-group
|
||||
ul.list-group.list-group-flush
|
||||
li.root.list-group-item.far-fa-folder
|
||||
.group-header Included files
|
||||
ul.list-group.named-editors
|
||||
ul.list-group.list-group-flush.named-editors
|
||||
li.root.list-group-item.far-fa-folder
|
||||
.group-header Excluded files
|
||||
ul.list-group.unnamed-editors
|
||||
ul.list-group.list-group-flush.unnamed-editors
|
||||
li.drophere.row.align-items-center(style="display: none;")
|
||||
span.col-lg.text-center Drop files here
|
||||
|
||||
@@ -1,19 +1,14 @@
|
||||
#compiler-selector
|
||||
.form-row
|
||||
.input-group
|
||||
.input-group-prepend
|
||||
.row
|
||||
.input-group
|
||||
select.compiler-picker
|
||||
.input-group-append
|
||||
button.btn.btn-sm.btn-light.input-group-text.picker-popout-button(data-trigger="click" style="cursor: pointer;" role="button" title="Compiler picker popout")
|
||||
span
|
||||
i.fa-solid.fa-arrow-up-right-from-square
|
||||
.input-group-append
|
||||
button.btn.btn-sm.btn-light.input-group-text.prepend-options(tabindex="0" data-trigger="focus" style="cursor: pointer;" role="button" title="All compilation options")
|
||||
span.btn.btn-sm.btn-light.status-icon
|
||||
input.conformance-options.form-control(type="text" placeholder="Compiler options..." size="256" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false")
|
||||
.input-group-append
|
||||
button.btn.btn-sm.fas.fa-receipt.d-none.compiler-out.compiler-selector-icon(disabled=true style="cursor: help;" title="This compiler has generated some output. Open its associated pane to read it.")
|
||||
button.btn.btn-sm.fas.fa-times.close.compiler-selector-icon(aria-label="Close" title="Close")
|
||||
button.btn.btn-sm.fas.fa-share.close.extract-compiler.compiler-selector-icon(aria-label="Pop compiler" title="Show compiler")
|
||||
button.btn.btn-sm.fas.fa-copy.close.copy-compiler.compiler-selector-icon(aria-label="Copy compiler" title="Copy compiler")
|
||||
button.btn.btn-sm.fas.fa-times.close-compiler.compiler-selector-icon(aria-label="Close" title="Close")
|
||||
button.btn.btn-sm.fas.fa-share.extract-compiler.compiler-selector-icon(aria-label="Pop compiler" title="Show compiler")
|
||||
button.btn.btn-sm.fas.fa-copy.copy-compiler.compiler-selector-icon(aria-label="Copy compiler" title="Copy compiler")
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
span
|
||||
b.lib-name
|
||||
span.lib-version
|
||||
select.custom-select.custom-select-sm.lib-version-select
|
||||
select.form-select.form-select-sm.lib-version-select
|
||||
option -
|
||||
.card-body
|
||||
p.lib-description
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#libs-entry
|
||||
.input-group.input-group-sm
|
||||
.input-group-prepend
|
||||
label.input-group-text
|
||||
select.custom-select.custom-select-sm
|
||||
select.form-select.form-select-sm
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
.card-header
|
||||
span.override-name
|
||||
span.override
|
||||
select.custom-select.custom-select-sm
|
||||
select.form-select.form-select-sm
|
||||
.card-body
|
||||
p.override-description
|
||||
span.override-fav
|
||||
|
||||
@@ -13,4 +13,4 @@
|
||||
.runtime-tool-option
|
||||
span.tool-option-name
|
||||
span.tool-option-select
|
||||
select.tool-option-select.custom-select-sm
|
||||
select.tool-option-select.form-select-sm
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#tree-editor-tpl
|
||||
li.list-group-item.tree-editor-file.input-group-append
|
||||
li.list-group-item.tree-editor-file
|
||||
span.filename someresource.txt
|
||||
button.btn.delete-file.fa.fa-trash(title="Remove this file" aria-label="Delete")
|
||||
button.btn.rename-file.fa.fa-tag(title="Rename this file" aria-label="Rename")
|
||||
|
||||
Reference in New Issue
Block a user