UNPKG

ep_images_extended

Version:

Insert images inline with text, float them, resize them, and more.

346 lines (291 loc) 9.46 kB
/* Import Bootstrap Icons if not already available */ @import url('https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css'); /* Bootstrap Icons support */ .image-format-button i { font-size: 18px; line-height: 1; } .image { display: inline-block; position: relative; line-height: 0; } .image>img { height: auto !important; -moz-user-select: -moz-none; -khtml-user-select: none; -webkit-user-select: none; user-select: none; display: block; } /* Styles for the new handle spans */ .image span.image-resize-handle { content: ''; position: absolute; width: 12px; height: 12px; background-color: #1a73e8; /* Google Docs blue square */ border: 1px solid #fff; /* White border for visibility */ z-index: 1; cursor: nw-resize; /* Double-sided diagonal arrow */ } .image span.image-resize-handle.br { bottom: -4px; right: -4px; cursor: nw-resize; } /* Hide the handles if the image is very small */ .image[style*="width: 10%;"] span.image-resize-handle, .image[style*="width: 11%;"] span.image-resize-handle, .image[style*="width: 12%;"] span.image-resize-handle, .image[style*="width: 13%;"] span.image-resize-handle, .image[style*="width: 14%;"] span.image-resize-handle, .image[style*="width: 15%;"] span.image-resize-handle { display: none; } /* Rules moved from clientHooks.js aceEditorCSS */ .ace-line .inline-image.white-space-pre-wrap { white-space: pre-wrap !important; } span.inline-image.character { white-space: pre-wrap !important; } /* CSS Pseudo-element approach for image display */ span.inline-image.image-placeholder { /* Hide original text content (placeholder character or "undefined") */ color: transparent; /* Make text invisible */ line-height: 0; /* Try to collapse height */ display: inline-block; vertical-align: middle; /* Align the container span */ /* Prevent selection of the underlying space/character */ -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; position: relative; /* Added */ max-width: 100%; /* ADDED to make placeholder respect its container's width */ /* Prevent text input into the image placeholder */ -webkit-user-modify: read-only; } /* Allow pointer events on inner spans for image interaction */ span.inline-image.image-placeholder span.image-inner, span.inline-image.image-placeholder span.image-resize-handle { pointer-events: auto; } /* Style the INNER span to display the image */ span.inline-image.image-placeholder span.image-inner { content: ''; /* Necessary for pseudo-element */ display: inline-block; /* Or block, if placeholder only contains this and handles */ max-width: 100%; /* Keep: ensures inner span respects outer placeholder's width */ height: auto; /* ADDED: Allow aspect-ratio to determine height */ aspect-ratio: var(--image-css-aspect-ratio, 1 / 1); /* ADDED: Use CSS var, fallback to 1:1 */ background-image: var(--image-src); /* Use the CSS variable */ background-size: contain; /* Use contain to fit image */ background-repeat: no-repeat; background-position: center center; } /* === START Styles for resize handles (ported from old plugin) === */ /* Base style for handle spans */ span.inline-image.image-placeholder span.image-resize-handle { content: ''; position: absolute; width: 12px; height: 12px; background-color: #1a73e8; /* Google Docs blue square */ border: 1px solid #fff; /* White border for visibility */ z-index: 1; display: none; /* Initially hidden */ cursor: nw-resize; /* Double-sided diagonal arrow */ /* Prevent text input and selection */ -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; /* Ensure contenteditable false is respected */ -webkit-user-modify: read-only; /* Prevent any text content from showing */ color: transparent !important; font-size: 0 !important; line-height: 0 !important; /* Override any inherited text styles */ text-decoration: none !important; font-weight: normal !important; font-style: normal !important; } /* Selection styling is handled via dynamic CSS injection in JavaScript */ /* This completely avoids triggering content collection hooks */ /* Default state - all images unselected */ span.inline-image.image-placeholder span.image-inner { outline: 0; outline-offset: 0; } span.inline-image.image-placeholder span.image-resize-handle { display: none; } /* Dynamic CSS rules are injected into the document head to show selection */ /* Format: span.inline-image.image-placeholder[data-image-id="ID"] span.image-inner { outline: ... } */ /* Image formatting menu */ .image-format-menu { position: absolute; background: white; border: 1px solid #c4c7c5; border-radius: 6px; box-shadow: 0 2px 8px rgba(0,0,0,0.15); padding: 6px; display: none; z-index: 1001; width: auto; min-width: 200px; } .image-format-menu.visible { display: block; } .image-format-menu-section { display: inline-block; } .image-format-menu-divider { width: 1px; height: 20px; background: #c4c7c5; margin: 0 4px; display: inline-block; vertical-align: middle; } .image-format-menu-buttons { display: inline-flex; gap: 3px; } .image-format-button { width: 28px; height: 28px; border: 1px solid transparent; border-radius: 3px; background: white; cursor: pointer; display: flex; align-items: center; justify-content: center; transition: all 0.15s; } .image-format-button:hover { background: #f1f3f4; border-color: #dadce0; } .image-format-button.active { background: #e8f0fe; border-color: #1a73e8; } .image-format-button i { color: #202124; transition: color 0.15s; font-weight: 500; } .image-format-button.active i { color: #1a73e8; font-weight: 600; } .image-format-button.image-delete-button:hover { background: #fce8e6; border-color: #ea4335; } .image-format-button.image-delete-button:hover i { color: #ea4335; } /* Copy button styling */ .image-format-button[data-action="copy"]:hover { background: #e8f0fe; /* Light blue background */ border-color: #1a73e8; /* Google blue border */ } .image-format-button[data-action="copy"]:hover i { color: #1a73e8; /* Google blue icon */ } /* Cut button styling */ .image-format-button[data-action="cut"]:hover { background: #e8f0fe; /* Light blue background */ border-color: #1a73e8; /* Google blue border */ } .image-format-button[data-action="cut"]:hover i { color: #1a73e8; /* Google blue icon */ } /* Improve active state for wrap buttons to look like Google Drive */ .image-format-button[data-wrap].active { background: #1a73e8; border-color: #1a73e8; } .image-format-button[data-wrap].active i { color: white; } /* Position the bottom-right handle only */ span.inline-image.image-placeholder span.image-resize-handle.br { bottom: -4px; right: -4px; cursor: nw-resize; } /* Float functionality for images */ span.inline-image.image-placeholder.image-float-none { float: none; display: inline-block; margin: 0; } span.inline-image.image-placeholder.image-float-left { float: left; display: inline-block; /* Keep inline-block to allow text wrapping */ margin: 0 10px 10px 0; /* Remove clear to allow horizontal stacking */ /* clear: left; */ } span.inline-image.image-placeholder.image-float-right { float: right; display: inline-block; /* Keep inline-block to allow text wrapping */ margin: 0 0 10px 10px; /* Remove clear to allow horizontal stacking */ /* clear: right; */ } /* Optional: Add spacing between consecutive floated images */ span.inline-image.image-placeholder.image-float-left + span.inline-image.image-placeholder.image-float-left { margin-left: 5px; } span.inline-image.image-placeholder.image-float-right + span.inline-image.image-placeholder.image-float-right { margin-right: 5px; } /* Hide the handles if the image inner span is very small (example thresholds) */ /* This might need JS adjustment based on calculated width */ /* === END Styles for resize handles === */ /* === START Float containment fix - minimal approach === */ /* Clear floated content after the last line */ .ace-line:last-child::after { content: ""; display: table; clear: both; } /* === END Float containment fix === */ /* === Modal loader styling === */ #imageUploadModalLoader.popup, #imageUploadModalError.popup { /* Position horizontally centered near the top of the viewport */ top: 20px !important; left: 50% !important; transform: translateX(-50%) !important; /* only horizontal centering */ right: auto !important; margin: 0 !important; position: fixed !important; z-index: 10000; /* Add a subtle border around the whole modal */ border: 1px solid #dadce0; border-radius: 8px; } /* Ensure both modals share the same inner-box styling */ #imageUploadModalLoader .popup-content, #imageUploadModalError .popup-content { border: none; /* border applied on outer container */ } /* Style the inner content box */ #imageUploadModalLoader .popup-content { display: flex; align-items: center; justify-content: center; padding: 24px 32px; background: #fff; border-radius: 8px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); min-width: 200px; } /* Provide user-visible feedback */ #imageUploadModalLoader .loadingAnimation::before { content: "Uploading image..."; font-size: 1.1rem; font-weight: 500; color: #202124; }