Last active
April 18, 2019 10:48
-
-
Save CanRau/662a559a07d6d7c492159d1cd497944f to your computer and use it in GitHub Desktop.
Please read https://processwire.com/talk/topic/13471-better-ckeditor-image-insertion-at-least-for-me/ I'm fixing some bugs right now and am rearranging the whole thing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Adding ->cdn property to page images | |
* returning assets url | |
* Can be placed wherever you like, e.g. _init.php | |
* just need to be included before using TextformatterBlogImages.module | |
* | |
* return //assets.YOURDOMAIN... | |
* removing http: makes it work with http and https connections | |
*/ | |
$wire->addHookProperty('Pageimage::cdn', function($event) { | |
$image = $event->object; | |
$event->return = str_replace('www.', 'assets.', $image->httpUrl); | |
$event->return = str_replace('http:', '', $event->return); | |
}); | |
/** | |
* This will hook into inputfield render process (stopping if not InputfieldImage) | |
* and appending a little script and stylesheet | |
* the js will add a little clickable area to each image in the image field | |
* | |
* I have only one images field set to multiple | |
* | |
* Works only with CKEditor textareas right now | |
* Can be placed in an owm module or wherever you like | |
* but backend needs to be able to include it in boot process.. | |
* | |
* NOTE: This code requires at least PW 3.0.17 with new image field | |
*/ | |
$wire->addHookAfter('Inputfield::render', function($event) { | |
$inputfield = $event->object; | |
// optional, but better to limit to those you want | |
if(!$inputfield instanceof InputfieldImage) return; | |
$name = $inputfield->name; | |
$event->return .= <<< _SCRIPT | |
<script type='text/javascript'> | |
document.addEventListener('DOMContentLoaded', function() { | |
var editor = CKEDITOR.instances.Inputfield_body, | |
images = document.querySelectorAll('.gridImage'), | |
imagesLen = images.length; | |
for (i=0; i<imagesLen; i++) { | |
images[i].insertAdjacentHTML('beforeEnd', '<div class="HappyImageSelector" title="insert into text (at caret)">+</div>'); | |
images[i].addEventListener('click', function(e) { | |
var imageSrc = e.target.parentNode.querySelector('img').src.split('?')[0]; | |
editor.insertHtml('<img src="'+imageSrc+'">'); | |
}); | |
} | |
editor.on( 'instanceReady', function(e) { | |
if ( editor.contextMenu ) { | |
editor.addCommand('alignLeft', { exec: function (editor) { | |
var element = editor.getSelection().getStartElement(); | |
element.removeClass('align_right'); | |
element.addClass('align_left'); | |
} }); | |
editor.addCommand('alignRight', { exec: function (editor) { | |
var element = editor.getSelection().getStartElement(); | |
element.removeClass('align_left'); | |
element.addClass('align_right'); | |
} }); | |
editor.addCommand('removeAlignment', { exec: function (editor) { | |
var element = editor.getSelection().getStartElement(); | |
element.removeClass('align_left'); | |
element.removeClass('align_right'); | |
} }); | |
editor.addCommand('small', { exec: function (editor) { | |
var element = editor.getSelection().getStartElement().$; | |
element.setAttribute('width', 200); | |
} }); | |
editor.addCommand('medium', { exec: function (editor) { | |
var element = editor.getSelection().getStartElement().$; | |
element.setAttribute('width', 350); | |
} }); | |
editor.addCommand('removeWidth', { exec: function (editor) { | |
var element = editor.getSelection().getStartElement().$; | |
element.removeAttribute('width'); | |
} }); | |
editor.addMenuGroup( 'HappyImages' ); | |
editor.addMenuItems({ | |
alignLeft : { | |
label : 'Rechts umfließen', | |
command : 'alignLeft', | |
group : 'HappyImages', | |
order : 1 | |
}, | |
alignRight : { | |
label : 'Links umfließen', | |
command : 'alignRight', | |
group : 'HappyImages', | |
order : 2 | |
}, | |
removeAlignment : { | |
label : 'Nicht umfließen', | |
command : 'removeAlignment', | |
group : 'HappyImages', | |
order : 3 | |
}, | |
small : { | |
label : 'klein', | |
command : 'small', | |
group : 'HappyImages', | |
order : 4 | |
}, | |
medium : { | |
label : 'medium', | |
command : 'medium', | |
group : 'HappyImages', | |
order : 5 | |
}, | |
removeWidth : { | |
label : 'original', | |
command : 'removeWidth', | |
group : 'HappyImages', | |
order : 6 | |
} | |
}); | |
} | |
editor.contextMenu.addListener( function( element ) { | |
if ( element.getAscendant( 'img', true ) ) { | |
return { | |
alignLeft: CKEDITOR.TRISTATE_OFF, | |
alignRight: CKEDITOR.TRISTATE_OFF, | |
removeAlignment: CKEDITOR.TRISTATE_OFF, | |
small: CKEDITOR.TRISTATE_OFF, | |
medium: CKEDITOR.TRISTATE_OFF, | |
removeWidth: CKEDITOR.TRISTATE_OFF | |
}; | |
} | |
}); | |
}); | |
}, | |
false); | |
</script> | |
<style type='text/css'> | |
.HappyImageSelector { | |
position: relative; | |
background: #e3e3e3; | |
text-align: center; | |
cursor: pointer; | |
} | |
</style> | |
_SCRIPT; | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.HappyRow { | |
margin-bottom: 1em; | |
} | |
.HappyRow__block { | |
background: #e6e6e6; | |
} | |
.HappyRow__description { | |
display: inline-block; | |
padding: 0em .2em .1em; | |
} | |
.HappyRow--multi .HappyRow__block { | |
display: inline-block; | |
} | |
@media @max40 { | |
.HappyRow__block { | |
width: 100% !important; | |
} | |
.HappyRow--multi .HappyRow__block + .HappyRow__block { | |
margin-top: 1em; | |
} | |
} | |
@media @min40 { | |
.HappyRow--single .HappyRow__block { | |
margin: 0 auto; | |
width: 60%; | |
} | |
// HappyRow's containing more than one child get a gutter | |
.HappyRow--multi .HappyRow__block + .HappyRow__block { | |
margin-left: 2%; | |
} | |
/* HappyRow with 2 children */ | |
.HappyRow--2 .HappyRow__block { | |
width: 49%; | |
} | |
/* HappyRow with 3 children */ | |
.HappyRow--3 .HappyRow__block { | |
width: 32% | |
} | |
/* HappyRow with 4 children */ | |
.HappyRow--4 .HappyRow__block { | |
width: 23.5% | |
} | |
/* 1 landscapes 1 portrait */ | |
.HappyRow--1lx1p { | |
.HappyRow__block--landscape { | |
width: 62.7%; | |
} | |
.HappyRow__block--portrait { | |
width: 35.3%; | |
} | |
} | |
/* 2 landscapes 1 portrait */ | |
.HappyRow--2lx1p { | |
.HappyRow__block--landscape { | |
width: 37.5%; | |
} | |
.HappyRow__block--portrait { | |
width: 21%; | |
} | |
} | |
/* 1 landscape 2 portrait */ | |
.HappyRow--1lx2p { | |
.HappyRow__block--landscape { | |
width: 45.2%; | |
} | |
.HappyRow__block--portrait { | |
width: 25.4%; | |
} | |
} | |
/* 2 landscape 2 portrait */ | |
.HappyRow--2lx2p { | |
.HappyRow__block--landscape { | |
width: 30%; | |
} | |
.HappyRow__block--portrait { | |
width: 16.95%; | |
} | |
} | |
/* 1 landscape 3 portrait */ | |
.HappyRow--1lx3p { | |
.HappyRow__block--landscape { | |
width: 34.9%; | |
} | |
.HappyRow__block--portrait { | |
width: 19.6%; | |
} | |
} | |
/* 3 landscape 1 portrait */ | |
.HappyRow--3lx1p { | |
.HappyRow__block--landscape { | |
width: 26.3%; | |
} | |
.HappyRow__block--portrait { | |
width: 14.8%; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Add to any textarea field from field settings | |
* or place the following code into any template file | |
* | |
* $modules->TextformatterBlogImages->formatValue($page, new Field(), $page->body); | |
* where $page->body is your textarea | |
* | |
* make sure to review path to simple_html_dom.php | |
* | |
* To make use of the lazyloading and | |
* proper selection of the right image | |
* you need to include https://github.com/aFarkas/lazysizes into your project | |
*/ | |
class TextformatterBlogImages extends Textformatter { | |
public static function getModuleInfo() { | |
return array( | |
'title' => 'TextformatterBlogImages', | |
'summary' => __("Links images to full version, wraps linked image into span or figure based on the context, moves figures into own container", __FILE__), // Module Summary | |
'version' => 1, | |
'auhor' => 'Can Rau' | |
); | |
} | |
/** | |
* Format the given text string with Page and Field provided. | |
* | |
* Override this function completely when providing your own text formatter. No need to call the parent. | |
* | |
* @param Page $page | |
* @param Field $field | |
* @param mixed $value | |
* | |
*/ | |
public function formatValue(Page $page, Field $field, &$value) { | |
require_once '../../../../classes/simple_html_dom.php'; | |
$user = wire('user'); | |
// turn double linebreaks into paragraphs <br><br> to </p><p> | |
$value = preg_replace('#(?:<br\s*/?>\s*?){2,}#', '</p><p>', $value->getLanguageValue($user->language)); | |
$dom = str_get_html($value); | |
$paragraphs = $dom->find('p'); | |
foreach ($paragraphs as $p) { | |
$imgs = $p->find('img'); | |
$inGallery = false; | |
$gallery = "<div class='HappyRow'>"; | |
foreach ($imgs as $img) { | |
$src = $img->src; | |
$class = $img->class; | |
$width = $img->width; | |
$height = $img->height; | |
$imgName = strstr(substr($src, strrpos($src, '/')+1), '.', true); // strip path and variation from image name | |
$pageimage = $page->images->get("name^=$imgName"); | |
$small = $pageimage->maxWidth(100, array('quality'=>15)); | |
$medium = $pageimage->maxWidth(300); | |
// don't stuff image in HappyRow if image got a class 'align_' prepended | |
if (strpos($class, 'align_left') === false && strpos($class, 'align_right') === false) { | |
$inGallery = true; | |
} | |
$img->class = str_replace(array('align_left', 'align_right'), '', $img->class); | |
$img->class .= ' HappyImage'; | |
$img->src = $pageimage->cdn; | |
$img->srcset = 'data:image/png;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs='; | |
$img->{'data-srcset'} = "$small->cdn {$small->width}w, $medium->cdn {$medium->width}w, $pageimage->cdn {$pageimage->width}w"; | |
$img->{'data-sizes'} = 'auto'; | |
// @todo is it bad that width could be higher than rendered with? | |
$img->width = $pageimage->width; | |
$i = $img->outertext; | |
$i = "<a class='modal modal-image' href='$pageimage->detailpage' data-href='$pageimage->cdn' data-name='$pageimage->name'>$i</a>"; | |
$class .= $pageimage->width > $pageimage->height ? ' HappyRow__block--landscape' : ' HappyRow__block--portrait'; | |
// if image will be moved into HappyRow wrap in figure and remove from paragraph | |
if ($inGallery) { | |
$i = "<figure class='HappyRow__block $class'>$i"; | |
if ($pageimage->description) $i .= "<figcaption class='HappyRow__description'>$pageimage->description</figcaption>"; | |
$i .= "</figure>"; | |
$gallery .= $i; | |
$img->outertext = ''; | |
} else { | |
// otherwise wrap in span and replace | |
$i = "<span class='HappyRow__block HappyRow__block--inline $class' style='width:{$width}px'>$i"; | |
if ($pageimage->description) $i .= "<span class='HappyRow__description'>$pageimage->description</span>"; | |
$i .= "</span>"; | |
$img->outertext = $i; | |
} | |
} | |
$gallery .= "</div>"; | |
$newParagraph = trim(preg_replace( '#^\s*(?:<br\s?\/?>)*\s*|(?:<br\s?\/?>)*\s*$#', '', trim($p->innertext))); | |
$newParagraph = "<p>$newParagraph</p>"; | |
if ($inGallery) { | |
$p->outertext = $gallery . $newParagraph; | |
} | |
} | |
// save dom to $value | |
$value = $dom->save(); | |
// clear dom | |
$dom->clear(); | |
/** | |
* 2. round | |
* reload dom | |
*/ | |
$dom = str_get_html($value); | |
// search for newly created HappyRows | |
$galleries = $dom->find('.HappyRow'); | |
foreach ($galleries as $g) { | |
$numChildren = count($g->children); | |
if ($numChildren) { | |
$landscapes = count($g->find('.HappyRow__block--landscape')); | |
$portraits = count($g->find('.HappyRow__block--portrait')); | |
// add single or multiple class | |
$class = $numChildren === 1 ? 'HappyRow--single' : 'HappyRow--multi'; | |
// if multiple add number of children | |
$class .= $numChildren > 1 ? " HappyRow--$numChildren" : ''; | |
$class .= " HappyRow--{$landscapes}lx{$portraits}p"; | |
// append classes to gallery container | |
$g->class .= " $class"; | |
} else { | |
// if no children remove gallery | |
// shouldn't happen anyways, just in case.. | |
$g->outertext = ''; | |
} | |
} | |
// save dom back to $value | |
$value = $dom->save(); | |
// clear dom again | |
$dom->clear(); | |
// remove empty paragraphs which can occur when a paragraph only contained images | |
$value = str_replace('<p></p>', '', $value); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment