관리-도구
편집 파일: typography.js
import { __ } from '@wordpress/i18n'; import { LabelControl } from './label'; import { useState, useRef, useEffect } from '@wordpress/element'; import { RenderScreenIcons } from './screen-icon'; const { pagelayer_fonts } = pagelayer_config; // TODO: imporve this for global // TODO load Font Family export const TypoControl = (props) => { const { attributes, prop, label, value, setAttributes, deviceType } = props; const { name } = prop['c']; const typoRef = useRef(null); const globalRef = useRef(null); const globalIconRef = useRef(null); const [isTypoVisible, setTypoVisible] = useState(false); const [isGlobalVisible, setGlobalVisible] = useState(false); const [isGLobalTypo, setGLobalTypo] = useState(pagelayerIsGlobalTypo(value)); const modes = { desktop: '', tablet: '_tablet', mobile: '_mobile' }; var values = pagelayerParseTypo(value, false); var tabValue = pagelayerParseTypo(attributes[name+'_tablet']); var mobValue = pagelayerParseTypo(attributes[name+'_mobile']); // Convert the jQuery function to a React method const handleInputChange = (e) => { var jEle = jQuery(e.target); if(jQuery(e.target).attr('name') == 'font-family' ){ pagelayer_link_font_family(jQuery(e.target)); } jEle.closest('[pagelayer-set-global]').removeAttr('pagelayer-set-global'); // Set attributes handleSaveTypo(); }; // Convert the jQuery function to a React method const handleSaveTypo = () => { if(!isTypoVisible){ return; } const atts = {}; atts[name] = {}; atts[name + '_tablet'] = {}; atts[name + '_mobile'] = {}; if(!pagelayer_empty(isGLobalTypo)){ atts[name]['global-font'] = isGLobalTypo; } const inputElements = typoRef.current.querySelectorAll('.pagelayer-elp-typo-input'); inputElements.forEach((iEle) => { const eName = iEle.getAttribute('name'); const value = iEle.value; const isGlobal = jQuery(iEle).closest('[pagelayer-set-global]'); if((value == '' && isGlobal.length < 1 && pagelayer_empty(isGLobalTypo)) || isGlobal.length > 0){ return; } if(pagelayer_empty(value)){ return; } if (eName.indexOf('_tablet') > -1) { const modifiedName = eName.replace('_tablet', ''); atts[name + '_tablet'][modifiedName] = value; } else if (eName.indexOf('_mobile') > -1) { const modifiedName = eName.replace('_mobile', ''); atts[name + '_mobile'][modifiedName] = value; } else { atts[name][eName] = value; } }); // Set attributes setAttributes(atts); }; const onClickGlobalTypo = (e, globalTypo) => { e.stopPropagation(); var row = jQuery(typoRef.current); setGlobalVisible(false); if(isGLobalTypo == globalTypo){ row.find('[pagelayer-set-global]').removeAttr('pagelayer-set-global'); setGLobalTypo(''); return; } setGLobalTypo(globalTypo); var fontSelect = row.find('.pagelayer-elp-typo-input[name="font-family"]'); // Set global value to all fields and save row.find('.pagelayer-elp-label .pagelayer-typo-default').each(function(){ restoreGlobalHandler(jQuery(this), true, globalTypo); }); pagelayer_link_font_family(fontSelect); // Apply google fonts } const openCustomizer = (e) => { e.stopPropagation(); window.open(pagelayer_customizer_url+'&autofocus%5Bsection%5D=pagelayer_global_fonts_sec', '_blank'); }; useEffect(() => { handleSaveTypo(); }, [isGLobalTypo]); useEffect(() => { var row = jQuery(typoRef.current); row.on('click', '.pagelayer-typo-default', function(e, skip_save){ restoreGlobalHandler(jQuery(e.target), skip_save); }); // Active global typography if(!pagelayer_empty(isGLobalTypo)){ // Show the global values if is not customize row.find('.pagelayer-elp-typo').attr('pagelayer-set-global', 1); row.find('.pagelayer-elp-typo').find('select, input').each(function(){ var sEle = jQuery(this); var val = sEle.val(); if(pagelayer_empty(val)){ return true; } sEle.closest('.pagelayer-elp-typo').removeAttr('pagelayer-set-global'); }); row.find('[pagelayer-set-global="1"] .pagelayer-typo-default').trigger('click', [true]); } return (() => { row.unbind('click', '.pagelayer-typo-default'); }); }, [isTypoVisible]); useEffect(() => { const handleDocumentClick = (e) => { // Shodow Modal Handler if( typoRef.current && !typoRef.current.contains(e.target) ){ setTypoVisible(false); } if( globalRef.current && !globalRef.current.contains(e.target) && globalIconRef.current && !globalIconRef.current.contains(e.target) ){ setGlobalVisible(false); } }; document.addEventListener('click', handleDocumentClick); return () => { document.removeEventListener('click', handleDocumentClick); }; }, []); var save_timer; const restoreGlobalHandler = (label, skipSave, globalTypo = null) => { skipSave = skipSave || false; globalTypo = globalTypo || isGLobalTypo; if (pagelayer_empty(globalTypo) || !pagelayer_global_fonts[globalTypo]) { return; } const setFonts = pagelayer_global_fonts[globalTypo]['value']; const holder = label.closest('.pagelayer-elp-typo'); const inputs = holder.find('.pagelayer-elp-typo-input'); const name = inputs.first().attr('name'); let val = ''; holder.attr('pagelayer-set-global', 1); if (name in setFonts) { val = setFonts[name]; } if (typeof val === 'object') { for (const mode in modes) { let _val = ''; if (mode in val) { _val = val[mode]; } holder.find('.pagelayer-elp-typo-input[name="' + name + modes[mode] + '"]').val(_val); } } else { if (inputs.length > 1) { inputs.val(''); } inputs.first().val(val); } if (skipSave) { return; } // save value clearTimeout(save_timer); save_timer = setTimeout(handleSaveTypo, 200); } const RenderLabel = (props) => { return ( <label {...props}> { props.children } <span className="pagelayer-typo-default" title={ __('Restore Global') } > <i className="fas fa-undo"></i> </span> </label> ); } const selectOptions = { 'style': { '': 'Default', 'normal': 'Normal', 'italic': 'Italic', 'oblique': 'Oblique' }, 'weight': { '': 'Default', '100': '100', '200': '200', '300': '300', '400': '400', '500': '500', '600': '600', '700': '700', '800': '800', '900': '900', 'normal': 'Normal', 'lighter': 'Lighter', 'bold': 'Bold', 'bolder': 'Bolder', 'unset': 'Unset' }, 'variant': { '': 'Default', 'normal': 'Normal', 'small-caps': 'Small Caps' }, 'deco-line': { '': 'Default', 'none': 'None', 'overline': 'Overline', 'line-through': 'Line Through', 'underline': 'Underline', 'underline overline': 'Underline Overline' }, 'deco-style': { '': 'Default', 'solid': 'Solid', 'double': 'Double', 'dotted': 'Dotted', 'dashed': 'Dashed', 'wavy': 'Wavy' }, 'transform': { '': 'Default', 'capitalize': 'Capitalize', 'uppercase': 'Uppercase', 'lowercase': 'Lowercase' }, 'fonts': pagelayer_fonts, } const createOption = (value = '', lang, setVal = '') => { const selected = value.toLowerCase() === setVal.toLowerCase(); const displayLang = lang || 'Default'; return <option value={value} selected={selected}>{displayLang}</option>; }; const createSelect = (name, options, setVal, attrs) => { attrs = attrs || {}; return (<select name={name} className="pagelayer-elp-typo-input pagelayer-elp-select" onChange={handleInputChange} {...attrs} > {Object.keys(options).map((optionVal) => { return createOption(optionVal, options[optionVal], setVal); })} </select>); }; const fontOptions = []; const createFontOption = (val, lang, type, setVal) => { const selected = val !== setVal ? '' : 'selected="selected"'; const displayLang = lang || 'Default'; return ( <option className="pagelayer-elp-typo-sele-op" value={val} type={type} selected={selected} > {displayLang} </option> ); }; for(const y in selectOptions['fonts']){ if (y !== 'default') { fontOptions.push(<optgroup label={pagelayerUcwords(y)} />); } for (const x in selectOptions['fonts'][y]) { fontOptions.push( createFontOption( jQuery.isNumeric(x) ? selectOptions['fonts'][y][x] : x, selectOptions['fonts'][y][x], y, values[0] ) ); } } return ( <div className="components-base-control pagelayer-base-control"> <LabelControl {...props} /> <div className={`pagelayer-prop-holder ${ isGLobalTypo ? 'pagelayer-global-on' : ''}`} ref={typoRef}> <span className="pagelayer-prop-edit" onClick={() => setTypoVisible(!isTypoVisible)} > <i className="pli pli-pencil"></i> </span> { isTypoVisible && <div className="pagelayer-elp-typo-div" pagelayer-screen-mode={deviceType}> <div className="pagelayer-elp-global-typo"> <label className="pagelayer-elp-label">{ __('Global Fonts') }</label> <span className="pagelayer-elp-typo-icons"> <span className={`pagelayer-elp-global-icon ${ isGLobalTypo ? 'pagelayer-active-global' : ''}`} onClick={ () => setGlobalVisible(!isGlobalVisible) } ref={globalIconRef} ></span> <span className="pli pli-service" onClick={openCustomizer}></span> </span> { isGlobalVisible && ( <div className="pagelayer-global-font-list" ref={globalRef}> {Object.keys(pagelayer_global_fonts).map((y) => { return ( <div className={`pagelayer-global-font-list-item ${ y == isGLobalTypo ? 'pagelayer-global-selected' : ''}`} data-global-id={y} onClick={ (e) => onClickGlobalTypo(e, y) } > <span className="pagelayer-global-font-title">{pagelayer_global_fonts[y]['title']}</span> </div> ); })} </div> )} </div> <div className="pagelayer-elp-typo"> <RenderLabel className="pagelayer-elp-label">{ __('Font Family') }</RenderLabel> <select className="pagelayer-elp-typo-input pagelayer-elp-select" name="font-family" onChange={handleInputChange} >{ fontOptions }</select> </div> <div className="pagelayer-elp-typo"> <RenderLabel className="pagelayer-elp-label"> { __('Font Size') } <RenderScreenIcons {...props} /> </RenderLabel> <input className="pagelayer-elp-typo-input" type="number" max="200" min="0" step="1" name="font-size" pagelayer-show-device="desktop" value={values[1]} onChange={handleInputChange} /> <input className="pagelayer-elp-typo-input" type="number" max="200" min="0" step="1" name="font-size_tablet" pagelayer-show-device="tablet" value={tabValue[1]} onChange={handleInputChange} /> <input className="pagelayer-elp-typo-input" type="number" max="200" min="0" step="1" name="font-size_mobile" pagelayer-show-device="mobile" value={mobValue[1]} onChange={handleInputChange} /> </div> <div className="pagelayer-elp-typo"> <RenderLabel className="pagelayer-elp-label">{ __('Font Style') }</RenderLabel> {createSelect('font-style', selectOptions['style'], values[2])} </div> <div className="pagelayer-elp-typo"> <RenderLabel className="pagelayer-elp-label"> { __('Font Weight') } <RenderScreenIcons {...props} /> </RenderLabel> {createSelect('font-weight', selectOptions['weight'], values[3], { 'pagelayer-show-device': 'desktop' } )} {createSelect('font-weight_tablet', selectOptions['weight'], tabValue[3], { 'pagelayer-show-device': 'tablet' })} {createSelect('font-weight_mobile', selectOptions['weight'], mobValue[3], { 'pagelayer-show-device': 'mobile' })} </div> <div className="pagelayer-elp-typo"> <RenderLabel className="pagelayer-elp-label">{ __('Font Variant') }</RenderLabel> {createSelect("font-variant", selectOptions['variant'], values[4])} </div> <div className="pagelayer-elp-typo"> <RenderLabel className="pagelayer-elp-label">{ __('Decoration Line') }</RenderLabel> {createSelect('text-decoration-line', selectOptions['deco-line'], values[5])} </div> <div className="pagelayer-elp-typo"> <RenderLabel className="pagelayer-elp-label">{ __('Decoration Style') }</RenderLabel> {createSelect('text-decoration-style', selectOptions['deco-style'], values[6])} </div> <div className="pagelayer-elp-typo"> <RenderLabel className="pagelayer-elp-label"> { __('Line Height') } <RenderScreenIcons {...props} /> </RenderLabel> <input className="pagelayer-elp-typo-input" type="number" min="0" max="100" step="0.1" name="line-height" pagelayer-show-device="desktop" value={values[7]} onChange={handleInputChange} /> <input className="pagelayer-elp-typo-input" type="number" min="0" max="100" step="0.1" name="line-height_tablet" pagelayer-show-device="tablet" value={tabValue[7]} onChange={handleInputChange} /> <input className="pagelayer-elp-typo-input" type="number" min="0" max="100" step="0.1" name="line-height_mobile" pagelayer-show-device="mobile" value={mobValue[7]} onChange={handleInputChange} /> </div> <div className="pagelayer-elp-typo" > <RenderLabel className="pagelayer-elp-label">{ __('Text Transform') }</RenderLabel> {createSelect('text-transform', selectOptions['transform'], values[8])} </div> <div className="pagelayer-elp-typo"> <RenderLabel className="pagelayer-elp-label"> { __('Letter Spacing') } <RenderScreenIcons {...props} /> </RenderLabel> <input className="pagelayer-elp-typo-input" type="number" min="0" max="100" step="0.1" name="letter-spacing" pagelayer-show-device="desktop" value={values[9]} onChange={handleInputChange} /> <input className="pagelayer-elp-typo-input" type="number" min="0" max="100" step="0.1" name="letter-spacing_tablet" pagelayer-show-device="tablet" value={tabValue[9]} onChange={handleInputChange} /> <input className="pagelayer-elp-typo-input" type="number" min="0" max="100" step="0.1" name="letter-spacing_mobile" pagelayer-show-device="mobile" value={mobValue[9]} onChange={handleInputChange} /> </div> <div className="pagelayer-elp-typo"> <RenderLabel className="pagelayer-elp-label"> { __('Word Spacing') } <RenderScreenIcons {...props} /> </RenderLabel> <input className="pagelayer-elp-typo-input" type="number" min="0" max="50" step="0.1" name="word-spacing" pagelayer-show-device="desktop" value={values[10]} onChange={handleInputChange} /> <input className="pagelayer-elp-typo-input" type="number" min="0" max="50" step="0.1" name="word-spacing_tablet" pagelayer-show-device="tablet" value={tabValue[10]} onChange={handleInputChange} /> <input className="pagelayer-elp-typo-input" type="number" min="0" max="50" step="0.1" name="word-spacing_mobile" pagelayer-show-device="mobile" value={mobValue[10]} onChange={handleInputChange} /> </div> </div> } </div> </div> ); } // Link font family export const pagelayer_link_font_family = (sEle) => { var value = sEle.val(); if(!value || value == 'Default'){ return; } value = value.replace(' ', '+'); var t = sEle.find("option:selected").attr('type'); switch(t){ case 'google': if(pagelayer_query('#pagelayer-google-fonts').length == 0){ if(value==''){ return; } pagelayer_query('head').append('<link id="pagelayer-google-fonts" href="https://fonts.googleapis.com/css?family='+value+':100,100i,200,200i,300,300i,400,400i,500,500i,600,600i,700,700i,800,800i,900,900i" rel="stylesheet">'); }else{ var url = pagelayer_query('#pagelayer-google-fonts').attr('href'); if(url.indexOf(value) == -1){ url = url+'|'+value+':100,100i,200,200i,300,300i,400,400i,500,500i,600,600i,700,700i,800,800i,900,900i'; pagelayer_query('#pagelayer-google-fonts').attr('href', url); } } break; case 'custom': if(!pagelayer_empty(pagelayer_query('style[id='+value+'_plf]').length)){ break; } jQuery.ajax({ url: pagelayer_ajax_url+'&action=pagelayer_custom_font', type: 'POST', dataType: 'json', data: { 'pagelayer_nonce': pagelayer_ajax_nonce, 'font_name': value }, success: function(data) { if('style' in data){ pagelayer_query('body').append(data['style']); } } }); break; } }