(function () { 'use strict'; if(!window.GRMH) return; var fonts={inherit:'Genel ayarı kullan',condensed:'Dar ve ekstra kalın',heavy:'Ekstra kalın',bold:'Kalın',normal:'Normal'}; var cases={inherit:'Genel ayarı kullan',upper:'BÜYÜK HARF',normal:'Yazıldığı gibi'}; function clone(value) { return JSON.parse(JSON.stringify(value)); } document.querySelectorAll('[data-grmh-editor]').forEach(function(editor) { var data; try {data=JSON.parse(editor.dataset.grmhEditor);} catch(e) {return;} var state=data.design, payload=editor.querySelector('.grmh-payload'); var stage=editor.querySelector('.grmh-stage'),preview=editor.querySelector('.grmh-preview'); var shell=editor.querySelector('.grmh-preview-shell'),list=editor.querySelector('.grmh-block-list'); var device=editor.querySelector('.grmh-device'),status=editor.querySelector('.grmh-status'); var image=editor.querySelector('.grmh-preview-image'),selected=-1,layout=null,drag=null,pending=false,notice=''; var mediaId=null,lastTitle=data.title; var missingImage=data.placeholder||data.image; var toolMode='move',textSelection=null,lastGoodState=null,hasLayoutIssue=false; var tools=document.createElement('div');tools.className='grmh-preview-tools'; var moveTool=document.createElement('button');moveTool.type='button';moveTool.className='button grmh-tool-move';moveTool.textContent='Taşı / Boyutlandır'; var colorTool=document.createElement('button');colorTool.type='button';colorTool.className='button grmh-tool-color';colorTool.textContent='Metni seç / Renklendir'; var previewColor=document.createElement('input');previewColor.type='color';previewColor.value='#ff3838';previewColor.className='grmh-preview-color'; var previewPaint=document.createElement('button');previewPaint.type='button';previewPaint.className='button grmh-preview-paint';previewPaint.textContent='Seçili kısmı renklendir'; var clearSelectionButton=document.createElement('button');clearSelectionButton.type='button';clearSelectionButton.className='button grmh-selection-clear';clearSelectionButton.textContent='Seçimi temizle'; var selectionInfo=document.createElement('p');selectionInfo.className='grmh-selection-info';selectionInfo.setAttribute('role','status'); tools.append(moveTool,colorTool,label('Seçili kısmın rengi',colorControl(previewColor)),previewPaint,clearSelectionButton,selectionInfo); shell.before(tools); editor.querySelector('.grmh-preview-help').textContent='Taşı / Boyutlandır modunda blokları taşıyın ve ↔ tutamacını kullanın. Metni seç / Renklendir modunda fotoğraf üzerindeki kelimelere basılı tutup seçim yapın; üstteki renk ve renklendirme düğmesini kullanın.'; function showTextSelection(){ if(textSelection && textSelection.kind==='ready') { var valid=state.mode==='ready' && textSelection.text===GRMH.readyText(data); selectionInfo.textContent=valid?'Seçilen: '+Array.from(textSelection.text).slice(textSelection.start,textSelection.end).join(''):'Henüz metin seçilmedi.'; previewPaint.disabled=!valid;return; } var b=textSelection && state.blocks[textSelection.index]; var valid=b && b.text===textSelection.text; selectionInfo.textContent=valid?'Seçilen (Metin bloğu '+(textSelection.index+1)+'): '+Array.from(b.text).slice(textSelection.start,textSelection.end).join(''):'Henüz metin seçilmedi.'; previewPaint.disabled=!valid; } function clearTextSelection(){textSelection=null;showTextSelection();} function setToolMode(mode){ cancelReadyGesture();toolMode=mode;drag=null;clearTextSelection(); editor.classList.toggle('grmh-select-text',mode==='color'); moveTool.setAttribute('aria-pressed',String(mode==='move'));colorTool.setAttribute('aria-pressed',String(mode==='color')); schedule(); } moveTool.addEventListener('click',function(){setToolMode('move');}); colorTool.addEventListener('click',function(){setToolMode('color');}); clearSelectionButton.addEventListener('click',function(){clearTextSelection();window.getSelection().removeAllRanges();}); function saveTextSelection(index,start,end,source){ if(end<=start || !state.blocks[index]) return; textSelection={index:index,start:start,end:end,source:source,text:state.blocks[index].text}; selection(index);showTextSelection(); } function sourceIndex(b,offset,isEnd,letterCase){ var chars=Array.from(b.text),length=0; for(var i=0;i32){notice='En fazla 32 renkli bölüm kullanılabilir.';status.textContent=notice;return;} r.highlight_text=title;r.highlights=ranges;notice='Seçilen kelimeler renklendirildi. Güncelle / Yayımla ile kaydedin.';update(true);return; } var b=chosen && state.blocks[chosen.index]; if(!b || b.text!==chosen.text) {clearTextSelection();notice='Önce fotoğraf üzerindeki veya Metin kutusundaki kelimeleri seçin.';status.textContent=notice;return;} if(index!==null && chosen.index!==index) {notice='Seçim Metin bloğu '+(chosen.index+1)+' içinde. Fotoğrafın üstündeki renklendirme düğmesini kullanın.';status.textContent=notice;return;} var highlights=GRMH.recolor(b.text,b.highlights,chosen.start,chosen.end,color); if(highlights.length>32) {notice='Bir blokta en fazla 32 ayrı renkli bölüm olabilir.';status.textContent=notice;return;} b.highlights=highlights;notice='Seçilen kelimeler renklendirildi. Güncelle / Yayımla ile kaydedin.';selection(chosen.index);update(true); } previewPaint.addEventListener('click',function(){paintSelected(null,previewColor.value);}); showTextSelection();moveTool.setAttribute('aria-pressed','true');colorTool.setAttribute('aria-pressed','false'); function sync(save) { payload.value=JSON.stringify(state); if(save) recordHistory(); if(!save) return; payload.dispatchEvent(new Event('change',{bubbles:true})); // Normal WP REST metadata also marks a block-editor post as modified. if(window.wp && wp.data) { var dispatch=wp.data.dispatch('core/editor'); if(dispatch && dispatch.editPost) dispatch.editPost({meta:{_gr_mobile_headline:payload.value}}); } } function draw() { pending=false; refreshReady(); refreshPhoto();refreshPersonal();refreshFullscreen(); readPreviewSelection(); var nativeWidth=Number(device.value), available=shell.parentElement.clientWidth; if(!available) return; var scale=Math.min(1,available/nativeWidth); shell.style.width=Math.min(nativeWidth,available)+'px'; preview.style.width=nativeWidth+'px';preview.style.transform='scale('+scale+')'; shell.style.height=(290*scale)+'px'; editor.classList.toggle('grmh-is-manual',state.mode==='manual'); layout=GRMH.render(stage,data,data.category,undefined,{editor:true,strict:hasLayoutIssue}); hasLayoutIssue=!!(layout && layout.manual && !layout.valid); editor.classList.toggle('grmh-layout-warning',hasLayoutIssue); refreshReadyEditor(scale); if(layout && layout.manual && layout.valid) { applyPositions(layout);sync(false);lastGoodState=clone(state); } else if(layout && layout.manual) lastGoodState=null; stage.querySelectorAll('.grmh-block').forEach(function(el,i){ el.classList.toggle('grmh-selected',i===selected); if(layout && layout.manual) { el.tabIndex=0;el.setAttribute('role','group');el.setAttribute('aria-label','Metin bloğu '+(i+1)+': '+state.blocks[i].text); el.dataset.grmhText=state.blocks[i].text; el.dataset.grmhCase=state.blocks[i].case && state.blocks[i].case!=='inherit'?state.blocks[i].case:GRMH.resolve(data).case; if(toolMode==='color') return; var handle=document.createElement('button');handle.type='button';handle.className='grmh-resize';handle.textContent='↔'; handle.setAttribute('aria-label','Metin bloğu '+(i+1)+' yazı boyutunu değiştir'); handle.title='Sürükleyerek yazı boyutunu değiştir'; handle.style.width=(40/scale)+'px';handle.style.height=(40/scale)+'px';handle.style.fontSize=(20/scale)+'px'; // Keep the touch target reachable even when small text touches an edge. var p=layout.positions[i], rect=el.getBoundingClientRect(), handleSize=40/scale; var left=p.x/100*nativeWidth, top=p.y/100*290; handle.style.left=GRMH.clamp(rect.width/scale-handleSize,-left,nativeWidth-left-handleSize)+'px'; handle.style.top=GRMH.clamp(rect.height/scale-handleSize,-top,290-top-handleSize)+'px'; handle.style.right='auto';handle.style.bottom='auto'; el.appendChild(handle); } }); status.textContent=(layout?layout.warnings.join(' '):'')+(notice?' '+notice:''); } function schedule() {if(!pending){pending=true;requestAnimationFrame(draw);}} function applyPositions(result) { result.positions.forEach(function(p,i){ state.blocks[i].x=p.x;state.blocks[i].y=p.y; var card=list.children[i];if(!card) return; ['x','y'].forEach(function(key){var input=card.querySelector('[data-block-field='+key+']');if(input) input.value=Math.round(state.blocks[i][key]*100)/100;}); }); } function update(save,active,keepText) { if(save && state.mode==='manual' && state.blocks.length) { var result=GRMH.render(stage,data,data.category,undefined,{ editor:true, strict:!Number.isInteger(active), active:active }); if(result && !result.valid && keepText) { hasLayoutIssue=true; lastGoodState=null; notice='Metin korundu. Bloklar çakışıyor veya görsele sığmıyor. Kaydetmeden önce konumu, genişliği veya boyutu düzenleyin.'; } else if(result && !result.valid && lastGoodState) { state=clone(lastGoodState); data.design=state; clearTextSelection(); selected=-1; buildList(); editor.querySelectorAll('[data-grmh-field]').forEach(function(input){ input.value=state[input.dataset.grmhField]; }); notice='Sınıra ulaşıldı. Diğer bloğu taşıyın veya metni / boyutu küçültün.'; sync(false); schedule(); return false; } if(result && result.valid) { hasLayoutIssue=false; applyPositions(result); lastGoodState=clone(state); if(keepText) notice=''; } } sync(save); schedule(); return true; } function selection(index) { selected=index; list.querySelectorAll('.grmh-block-card').forEach(function(el,i){el.classList.toggle('grmh-selected',i===index);}); stage.querySelectorAll('.grmh-block').forEach(function(el,i){el.classList.toggle('grmh-selected',i===index);}); } function label(text, input) {var el=document.createElement('label');el.append(document.createTextNode(text),input);return el;} function colorControl(input) { var colors=[ ['Gazetem sarısı','#ffd600'],['Beyaz','#ffffff'], ['Kırmızı','#ff0000'],['Koyu kırmızı','#c90000'], ['Siyah','#000000'],['Lacivert','#123a63'], ['Mavi','#0057b8'],['Turuncu','#ff8a00'] ]; var wrap=document.createElement('div'); wrap.className='grmh-color-control'; input.type='hidden'; var open=document.createElement('button'); open.type='button'; open.className='button grmh-color-open'; var chip=document.createElement('span'); chip.className='grmh-color-chip'; var caption=document.createElement('span'); open.append(chip,caption); open.setAttribute('aria-expanded','false'); var menu=document.createElement('div'); menu.className='grmh-color-menu'; menu.hidden=true; var heading=document.createElement('strong'); heading.textContent='Sık kullanılan renkler'; var presets=document.createElement('div'); presets.className='grmh-color-presets'; var custom=document.createElement('details'); custom.className='grmh-custom-color'; var summary=document.createElement('summary'); summary.textContent='Özel renk seç'; var picker=document.createElement('input'); picker.type='color'; picker.setAttribute('aria-label','Özel renk skalası'); var hex=document.createElement('input'); hex.type='text'; hex.maxLength=7; hex.placeholder='#ffd600'; hex.setAttribute('aria-label','Özel renk kodu'); hex.autocomplete='off'; hex.spellcheck=false; var apply=document.createElement('button'); apply.type='button'; apply.className='button'; apply.textContent='Uygula'; var message=document.createElement('span'); message.className='grmh-color-message'; message.setAttribute('role','status'); function refresh() { var value=input.value.toLowerCase(); var known=colors.find(function(c){return c[1]===value;}); chip.style.backgroundColor=value; caption.textContent=(known?known[0]:value.toUpperCase())+' · Renk seç'; picker.value=value; hex.value=value; presets.querySelectorAll('button').forEach(function(button){ button.setAttribute('aria-pressed',String(button.dataset.color===value)); }); } function choose(value) { input.value=value; input.dispatchEvent(new Event('input',{bubbles:true})); input.dispatchEvent(new Event('change',{bubbles:true})); refresh(); message.textContent=''; } colors.forEach(function(color){ var button=document.createElement('button'); button.type='button'; button.className='grmh-color-preset'; button.dataset.color=color[1]; button.title=color[0]+' '+color[1]; button.setAttribute('aria-label',color[0]); var dot=document.createElement('span'); dot.style.backgroundColor=color[1]; dot.className='grmh-color-chip'; button.append(dot,document.createTextNode(color[0])); button.addEventListener('click',function(){ choose(color[1]); menu.hidden=true; open.setAttribute('aria-expanded','false'); }); presets.appendChild(button); }); picker.addEventListener('input',function(){choose(picker.value);}); picker.addEventListener('change',function(){choose(picker.value);}); apply.addEventListener('click',function(){ var value=hex.value.trim().toLowerCase(); if(value[0]!=='#') value='#'+value; if(/^#[0-9a-f]{3}$/.test(value)) { value='#'+value.slice(1).split('').map(function(c){ return c+c; }).join(''); } if(!/^#[0-9a-f]{6}$/.test(value)) { message.textContent='Geçerli bir renk kodu yazın: #ffd600'; return; } choose(value); }); open.addEventListener('click',function(){ var show=menu.hidden; editor.querySelectorAll('.grmh-color-menu').forEach(function(other){ other.hidden=true; other.parentElement.querySelector('.grmh-color-open') .setAttribute('aria-expanded','false'); }); menu.hidden=!show; open.setAttribute('aria-expanded',String(show)); }); wrap.addEventListener('keydown',function(event){ if(event.key==='Escape') { menu.hidden=true; open.setAttribute('aria-expanded','false'); open.focus(); } if(event.key==='Enter' && event.target===hex) { event.preventDefault(); apply.click(); } }); input.addEventListener('input',refresh); custom.append(summary,picker,hex,apply,message); menu.append(heading,presets,custom); wrap.append(input,open,menu); refresh(); input.grmhRefreshColor=refresh;return wrap; } document.addEventListener('click',function(event){ var active=event.target.closest('.grmh-color-control'); editor.querySelectorAll('.grmh-color-control').forEach(function(control){ if(control!==active) { control.querySelector('.grmh-color-menu').hidden=true; control.querySelector('.grmh-color-open') .setAttribute('aria-expanded','false'); } }); }); function select(choices,value) { var el=document.createElement('select'); Object.keys(choices).forEach(function(key){var option=document.createElement('option');option.value=key;option.textContent=choices[key];el.appendChild(option);}); el.value=value;return el; } function buildList() { list.replaceChildren(); state.blocks.forEach(function(b,i){ var card=document.createElement('div');card.className='grmh-block-card'; var heading=document.createElement('div');heading.className='grmh-block-heading'; var title=document.createElement('strong');title.textContent='Metin bloğu '+(i+1); var remove=document.createElement('button');remove.type='button';remove.className='button';remove.textContent='Sil'; remove.addEventListener('click',function(){clearTextSelection();state.blocks.splice(i,1);state.blocks.forEach(function(block){if(block.join_to===i) delete block.join_to;else if(Number.isInteger(block.join_to) && block.join_to>i) block.join_to--;});selected=-1;buildList();update(true);}); heading.append(title,remove);card.appendChild(heading); var text=document.createElement('textarea');text.value=b.text;text.rows=2;text.maxLength=300; text.addEventListener('focus',function(){ if(textSelection && textSelection.source==='preview') {clearTextSelection();window.getSelection().removeAllRanges();} }); function rememberSelection(event){ if(text.selectionEnd>text.selectionStart) { saveTextSelection(i,Array.from(text.value.slice(0,text.selectionStart)).length, Array.from(text.value.slice(0,text.selectionEnd)).length,'textarea'); } else if(event && (event.type==='keyup' || event.type==='pointerup') && textSelection && textSelection.source==='textarea' && textSelection.index===i) clearTextSelection(); } ['select','keyup','pointerup'].forEach(function(event){text.addEventListener(event,rememberSelection);}); text.addEventListener('input',function(){ b.highlights=GRMH.remapHighlights(b.text,text.value,b.highlights); b.text=text.value;clearTextSelection();rememberSelection();notice='';selection(i);update(true,undefined,true); }); card.appendChild(label('Metin',text)); var inlineTools=document.createElement('div');inlineTools.className='grmh-inline-tools'; var inlineColor=document.createElement('input');inlineColor.type='color';inlineColor.value='#ff3838';inlineColor.className='grmh-inline-color'; var paint=document.createElement('button');paint.type='button';paint.className='button grmh-paint-selection';paint.textContent='Seçili kısmı renklendir'; paint.addEventListener('click',function(){paintSelected(i,inlineColor.value);}); var clear=document.createElement('button');clear.type='button';clear.className='button grmh-clear-highlights';clear.textContent='Parça renklerini temizle'; clear.addEventListener('click',function(){b.highlights=[];notice='Bu blok, kendi Renk alanında seçilen tek renge döndü.';selection(i);update(true);}); inlineTools.append(label('Seçili kısmın rengi',colorControl(inlineColor)),paint,clear);card.appendChild(inlineTools); var help=document.createElement('p');help.className='grmh-inline-help';help.textContent='Metin alanında kelimeleri seçin, rengi belirleyin ve Seçili kısmı renklendir düğmesine basın. Diğer kelimeler bloğun Renk ayarını kullanır.';card.appendChild(help); var fields=document.createElement('div');fields.className='grmh-block-fields'; [['color','Renk','color'],['size','Boyut','number',12,72],['width','Genişlik (%)','number',10,100],['x','Yatay konum (%)','number',0,100],['y','Dikey konum (%)','number',0,100]].forEach(function(f){ var input=document.createElement('input');input.type=f[2];input.value=b[f[0]]; if(f[2]==='number') {input.min=f[3];input.max=f[4];input.step='0.1';} input.dataset.blockField=f[0]; input.addEventListener('input',function(){ if(f[2]==='number' && (input.value==='' || !Number.isFinite(Number(input.value)))) return; if(f[0]==='size') {selection(i);resize(i,input.value);return;} if(f[0]==='x' || f[0]==='y') detach(i); b[f[0]]=f[2]==='number'?GRMH.clamp(input.value,f[3],f[4]):input.value;selection(i);update(true); }); fields.appendChild(label(f[1],f[0]==='color'?colorControl(input):input)); }); [['font','Yazı karakteri',fonts],['case','Harf düzeni',cases],['align','Hizalama',{left:'Sol',center:'Orta',right:'Sağ'}]].forEach(function(f){ var input=select(f[2],b[f[0]]); input.addEventListener('change',function(){b[f[0]]=input.value;selection(i);update(true);}); fields.appendChild(label(f[1],input)); }); card.appendChild(fields);card.addEventListener('focusin',function(){selection(i);});list.appendChild(card); }); editor.querySelector('.grmh-add').disabled=state.blocks.length>=8; selection(selected); } function rebuild() { clearTextSelection(); state.mode='manual';editor.querySelector('[data-grmh-field=mode]').value='manual'; // Use the exact automatic fit to seed non-overlapping manual positions. var temporary=clone(data);temporary.design.mode='auto'; var seed=GRMH.render(stage,temporary,data.category,3); state.blocks=seed?seed.blocks.map(function(b,i){return Object.assign({},b,seed.positions[i]);}):GRMH.autoBlocks(data,3); state.blocks.forEach(function(b){b.size=GRMH.clamp(b.size,12,72);b.y=GRMH.clamp(b.y,0,100);}); selected=-1;buildList();update(true); } editor.querySelectorAll('[data-grmh-field]').forEach(function(input){ input.addEventListener('input',function(){ var key=input.dataset.grmhField; if(key==='custom_title' && state.mode==='ready') { var r=readyState(),old=GRMH.readyText(data),next=(input.value.trim()||String(data.title||'').trim()).replace(/\r\n?/g,'\n'); if(r.highlight_text===old){r.highlights=GRMH.remapHighlights(old,next,r.highlights);r.highlight_text=next;} clearTextSelection(); } if(key==='mode') cancelReadyGesture(); state[key]=key==='size'?GRMH.clamp(input.value,0,60):input.value; if(key==='mode') { hasLayoutIssue=false;notice=''; if(state.mode==='ready') {state.ready=GRMH.readyConfig(data);readyColorTemplate=null;} } if(key==='mode') {clearTextSelection();lastGoodState=null;toolMode='move';editor.classList.remove('grmh-select-text');moveTool.setAttribute('aria-pressed','true');colorTool.setAttribute('aria-pressed','false');} if(key==='mode' && state.mode==='manual' && !state.blocks.length) {rebuild();return;} if(key==='palette' && state.mode==='manual') { var colors=GRMH.resolve(data).colors;state.blocks.forEach(function(b,i){b.color=colors[i%colors.length];});buildList(); } update(true); }); }); editor.querySelector('.grmh-add').addEventListener('click',function(){ if(state.blocks.length>=8) return; var s=GRMH.resolve(data);state.blocks.push({text:'Yeni metin',color:s.colors[state.blocks.length%s.colors.length],size:30,x:4,y:50,width:92,align:'left',font:'inherit',case:'inherit'}); selected=state.blocks.length-1;buildList();update(true,selected); }); editor.querySelector('.grmh-rebuild').addEventListener('click',rebuild); editor.querySelector('.grmh-reset').addEventListener('click',function(){ clearTextSelection(); lastGoodState=null; state={version:1,mode:'auto',style:'inherit',palette:'inherit',font:'inherit',case:'inherit',size:0,custom_title:'',blocks:[]};data.design=state;selected=-1; editor.querySelectorAll('[data-grmh-field]').forEach(function(input){input.value=state[input.dataset.grmhField];}); buildList();update(true); }); device.addEventListener('change',schedule); stage.addEventListener('pointerdown',function(event){ if(!layout || !layout.manual || (event.pointerType==='mouse' && event.button!==0)) return; var el=event.target.closest('.grmh-block');if(!el) return; var i=Number(el.dataset.block);selection(i); if(toolMode==='color') return; el.focus({preventScroll:true}); var rect=stage.getBoundingClientRect(), position=layout.positions[i]; drag={id:event.pointerId,index:i,x:event.clientX,y:event.clientY,startX:position.x,startY:position.y,rect:rect,blockHeight:el.getBoundingClientRect().height,blockWidth:position.width, resize:!!event.target.closest('.grmh-resize'),startSize:state.blocks[i].size,previewScale:rect.width/Number(device.value)}; stage.setPointerCapture(event.pointerId);event.preventDefault(); }); function detach(index) { delete state.blocks[index].join_to; state.blocks.forEach(function(b){ if(b.join_to===index) delete b.join_to; }); } function dock(index) { var result=GRMH.render(stage,data,data.category,undefined,{ editor:true,strict:true }); if(!result || !result.valid) return; var a=result.boxes[index]; result.boxes.forEach(function(b,i){ if(i===index || a.x>=b.x+b.w-.001 || a.x+a.w<=b.x+.001) return; var lower,upper; if(Math.abs(a.y-(b.y+b.h))<.05) { lower=index;upper=i; } else if(Math.abs(b.y-(a.y+a.h))<.05) { lower=i;upper=index; } else { return; } state.blocks[lower].join_to=upper; }); update(true); } function move(index,x,y,height,width) { if(!layout) return; detach(index); var box=layout.boxes[index],bounds=layout.bounds; var point=layout.valid?GRMH.constrainMove(layout,index,x,y):{ x:GRMH.clamp(x,1.5,Math.max(1.5,98.5-box.w/bounds.width*100)), y:GRMH.clamp(y,0,Math.max(0,100-box.h/bounds.height*100)) }; var b=state.blocks[index]; b.x=point.x; b.y=point.y; var card=list.children[index]; ['x','y'].forEach(function(key){ card.querySelector('[data-block-field='+key+']').value= Math.round(b[key]*100)/100; }); update(true,undefined,hasLayoutIssue); } stage.addEventListener('pointermove',function(event){ if(!drag || drag.id!==event.pointerId) return; if(drag.resize) { var delta=((event.clientX-drag.x)+(event.clientY-drag.y))/2; resize(drag.index,drag.startSize+delta/drag.previewScale*.35); return; } move( drag.index, drag.startX+(event.clientX-drag.x)/drag.rect.width*100, drag.startY+(event.clientY-drag.y)/drag.rect.height*100, drag.blockHeight/drag.rect.height*100, drag.blockWidth ); }); function end(event) { if(!drag || drag.id!==event.pointerId) return; var id=drag.id; var index=drag.index; var shouldDock=!drag.resize && event.type==='pointerup'; drag=null; if(stage.hasPointerCapture(id)) stage.releasePointerCapture(id); if(shouldDock) dock(index); } stage.addEventListener('pointerup',end); stage.addEventListener('pointercancel',end); stage.addEventListener('lostpointercapture',end); function resize(index,size) { var b=state.blocks[index],old=b.size,wanted=Math.round(GRMH.clamp(size,12,72)*10)/10; function fits(candidate) { b.size=candidate; var result=GRMH.render(stage,data,data.category,undefined,{editor:true,strict:true}); return !result || result.valid; } var accepted=wanted; if(!fits(wanted) && wanted>old && fits(old)) { var low=old,high=wanted; for(var n=0;n<10;n++) {var mid=(low+high)/2;if(fits(mid)) low=mid;else high=mid;} accepted=Math.floor(low*10)/10; notice='Boyut sınırına ulaşıldı. Daha fazla büyütmek için diğer bloğu taşıyın.'; } b.size=accepted; list.children[index].querySelector('[data-block-field=size]').value=accepted; update(true); } stage.addEventListener('keydown',function(event){ if(toolMode==='color') return; var el=event.target.closest('.grmh-block');if(!el || !layout || !layout.manual) return; if(!['ArrowLeft','ArrowRight','ArrowUp','ArrowDown'].includes(event.key)) return; event.preventDefault();var i=Number(el.dataset.block),p=layout.positions[i],step=event.shiftKey?3:1; if(event.target.closest('.grmh-resize')) { resize(i,state.blocks[i].size+(event.key==='ArrowRight'||event.key==='ArrowUp'?step:-step)); requestAnimationFrame(function(){var next=stage.querySelector('[data-block="'+i+'"] .grmh-resize');if(next) next.focus({preventScroll:true});}); return; } var rect=stage.getBoundingClientRect(); move(i,p.x+(event.key==='ArrowRight'?step:event.key==='ArrowLeft'?-step:0), p.y+(event.key==='ArrowDown'?step:event.key==='ArrowUp'?-step:0),el.getBoundingClientRect().height/rect.height*100,p.width); dock(i); requestAnimationFrame(function(){var next=stage.querySelector('[data-block="'+i+'"]');if(next) next.focus({preventScroll:true});}); }); // Live title/featured-image changes from the block editor. Stale image requests cannot overwrite newer choices. if(window.wp && wp.data && wp.data.select('core/editor')) { wp.data.subscribe(function(){ var source=wp.data.select('core/editor');if(!source || !source.getEditedPostAttribute) return; var title=source.getEditedPostAttribute('title'); if(typeof title==='string' && title!==lastTitle) {data.title=title;lastTitle=title;schedule();} var id=source.getEditedPostAttribute('featured_media'); if(id===mediaId) return;mediaId=id; if(!id) {image.src=missingImage;schedule();return;} if(wp.apiFetch) wp.apiFetch({path:'/wp/v2/media/'+id}).then(function(media){ if(mediaId!==id) return; var sizes=media.media_details && media.media_details.sizes; image.src=sizes && sizes.medium_large?sizes.medium_large.source_url:media.source_url;schedule(); }).catch(function(){status.textContent='Yeni görselin önizlemesi alınamadı. Yazıyı kaydedip yeniden açın.';}); }); } // Classic Editor already updates this box after picking/removing the featured image. var classicTitle=document.querySelector('#title'); if(classicTitle) classicTitle.addEventListener('input',function(){data.title=classicTitle.value;schedule();}); var featured=document.querySelector('#postimagediv .inside'); if(featured) new MutationObserver(function(){var img=featured.querySelector('img');image.src=img?(img.dataset.src || img.src):missingImage;schedule();}).observe(featured,{childList:true,subtree:true,attributes:true,attributeFilter:['src']}); if(typeof ResizeObserver!=='undefined') new ResizeObserver(schedule).observe(shell.parentElement);else window.addEventListener('resize',schedule); if(document.fonts) document.fonts.ready.then(schedule); // Shared editor context for the authenticated office news form. editor.grmhSetContext=function(context) { if(!context || typeof context!=='object') return false; if(typeof context.design==='string') { var restored; try {restored=JSON.parse(context.design);} catch(e) {return false;} if(!restored ||!['auto','manual','ready'].includes(restored.mode)|| typeof restored.custom_title!=='string' || !Array.isArray(restored.blocks) || restored.blocks.length>8 || restored.blocks.some(function(b){return !b || typeof b.text!=='string';})) return false; cancelReadyGesture();readyColorTemplate=null;clearTextSelection();state=restored;data.design=state;selected=-1;lastGoodState=null;hasLayoutIssue=false; editor.querySelectorAll('[data-grmh-field]').forEach(function(input){input.value=state[input.dataset.grmhField];}); buildList();sync(false);resetHistory(); } if(typeof context.title==='string') {data.title=context.title;lastTitle=context.title;} if(typeof context.image==='string') image.src=context.image||missingImage; if(typeof context.category==='string') data.category=context.category; schedule();return true; }; var readyControls=document.createElement('section');readyControls.className='grmh-ready-controls'; var readyHelp=document.createElement('p');readyHelp.textContent='Bir şablona dokunun. Satır bölmek için manşette Enter tuşunu kullanın; yazı boyutu otomatik ayarlanır.'; var readyGallery=document.createElement('div');readyGallery.className='grmh-ready-gallery'; readyGallery.setAttribute('aria-label','Hazır manşet şablonları'); var readyColors=document.createElement('div');readyColors.className='grmh-ready-colors'; var readyColorTemplate=null; var titleLabel=editor.querySelector('.grmh-custom-title'),titleInput=titleLabel.querySelector('textarea'); var titleLabelText=titleLabel.firstChild,titleLabelOriginal=titleLabelText.textContent; titleLabel.after(readyControls);readyControls.append(readyHelp,readyGallery,readyColors); var readyCards=GRMH.readyTemplates.map(function(preset,i){ var button=document.createElement('button');button.type='button';button.className='grmh-ready-card'; var photo=document.createElement('img');photo.alt=''; var frame=document.createElement('span');frame.className='grmh-ready-thumb'; var root=document.createElement('span');root.className='grmh-stage'; var name=document.createElement('strong');name.textContent=(preset.number||i+1)+'. '+preset.name; frame.append(photo,root);button.append(frame,name); var holder=document.createElement('div');holder.className='grmh-ready-item'; var star=action('☆',function(){ var next=clone(shelf),index=next.favorites.indexOf(preset.id); if(index<0) next.favorites.push(preset.id);else next.favorites.splice(index,1); if(saveShelf(next)) {refreshFavorites();report('Favori listesi güncellendi.');} },'grmh-favorite'); holder.append(button,star);readyGallery.appendChild(holder); button.addEventListener('click',function(){ if(GRMH.readyConfig(data).template!==preset.id) { state.ready={template:preset.id,colors:preset.colors.slice()};readyColorTemplate=null; } notice='';update(true); }); return {preset:preset,button:button,image:photo,root:root,holder:holder,star:star}; }); function refreshReady() { var active=state.mode==='ready';editor.classList.toggle('grmh-is-ready',active); if(active && readyGesture) return; titleLabelText.textContent=active?'Manşet ':titleLabelOriginal; refreshFavorites(); titleInput.rows=active?1:2; if(!active) {titleInput.style.height='';if(document.activeElement!==titleInput) titleInput.value=state.custom_title;return;} if(!state.custom_title && document.activeElement!==titleInput) titleInput.value=data.title||''; titleInput.style.height='auto';titleInput.style.height=Math.max(44,titleInput.scrollHeight)+'px'; var config=GRMH.readyConfig(data),definition=GRMH.readyTemplates.find(function(p){return p.id===config.template;}); if(readyColorTemplate!==config.template) { readyColors.replaceChildren();readyColorTemplate=config.template; definition.labels.forEach(function(name,i){ var input=document.createElement('input');input.type='color';input.value=config.colors[i]; input.className='grmh-ready-color';input.dataset.readyColor=String(i); input.addEventListener('input',function(){ state.ready=GRMH.readyConfig(data);state.ready.colors[i]=input.value;update(true); }); readyColors.appendChild(label(name,colorControl(input))); }); } readyCards.forEach(function(card){ var chosen=card.preset.id===config.template; card.button.setAttribute('aria-pressed',String(chosen));card.image.src=image.src; card.image.style.objectPosition=photoPosition(state); var sample=Object.assign({},data,{design:Object.assign({},state,{ready:chosen?config:{template:card.preset.id,colors:card.preset.colors}})}); var key=JSON.stringify([sample.title,sample.defaults,sample.design.custom_title,sample.design.ready,card.root.clientWidth,card.root.clientHeight]); if(card.renderKey!==key) {GRMH.renderReady(card.root,sample);card.renderKey=key;} }); } // Editor conveniences. Saved designs still use the existing WP metadata. var history=[],historyIndex=-1,historyLock=false,editKey=null,editAt=0,historyKey=null,historyAt=0,historyGesture=null; var shelfKey='grmh-personal-v1',shelf={version:1,favorites:[],templates:[]},shelfError=''; var extra=document.createElement('section');extra.className='grmh-extras'; var actions=document.createElement('div');actions.className='grmh-extra-actions'; function action(text,fn,cls) { var button=document.createElement('button');button.type='button';button.className='button '+(cls||''); button.textContent=text;button.addEventListener('click',fn);return button; } function report(text){notice=text;status.textContent=text;} var undoButton=action('↶ Geri al',function(){restoreHistory(-1);},'grmh-undo'); var redoButton=action('↷ İleri al',function(){restoreHistory(1);},'grmh-redo'); var fullscreenButton=action('⛶ Tam ekran ön izleme',openFullscreen,'grmh-fullscreen-open'); actions.append(undoButton,redoButton,fullscreenButton);extra.appendChild(actions); editor.querySelector('.grmh-toolbar').before(extra); editor.addEventListener('input',function(event){editKey=event.target;editAt=Date.now();},true); editor.addEventListener('click',function(event){if(event.target.closest('button')) editKey=null;},true); editor.addEventListener('pointerdown',function(event){ if(event.target.tagName==='BUTTON' || event.target.closest('button')) editKey=null; },true); stage.addEventListener('pointerdown',function(){if(!historyGesture)historyGesture={};},true); ['pointerup','pointercancel','lostpointercapture'].forEach(function(type){stage.addEventListener(type,function(){var key=historyGesture;queueMicrotask(function(){if(historyGesture===key && (!readyPointers || !readyPointers.size)) historyGesture=null;});});}); function historyButtons(){undoButton.disabled=historyIndex<=0;redoButton.disabled=historyIndex>=history.length-1;} function recordHistory() { if(historyLock || historyIndex<0) return; var value=JSON.stringify(state),now=Date.now(),key=historyGesture||(now-editAt<100?editKey:null); if(history[historyIndex]===value) return; var coalesce=key && historyIndex===history.length-1 && historyIndex>0 && key===historyKey && now-historyAt<800; history.splice(historyIndex+1); if(coalesce) history[historyIndex]=value; else {history.push(value);historyIndex++;if(history.length>60){history.shift();historyIndex--;}} historyKey=key;historyAt=now;historyButtons(); } function restoreDesign(design,save) { cancelReadyGesture();drag=null;clearTextSelection();state=clone(design);data.design=state;selected=-1; lastGoodState=null;hasLayoutIssue=true;readyColorTemplate=null; editor.querySelectorAll('[data-grmh-field]').forEach(function(input){input.value=state[input.dataset.grmhField]===undefined?'':state[input.dataset.grmhField];}); buildList();sync(save);schedule(); } function restoreHistory(direction) { var next=historyIndex+direction;if(next<0 || next>=history.length) return; historyIndex=next;historyLock=true;restoreDesign(JSON.parse(history[next]),true);historyLock=false; historyKey=null;editKey=null;historyButtons();report(direction<0?'Son değişiklik geri alındı.':'Değişiklik yeniden uygulandı.'); } function resetHistory(){history=[JSON.stringify(state)];historyIndex=0;historyKey=null;historyButtons();} function photoPosition(design) { var p=design.photo||{}; return GRMH.clamp(p.x===undefined?50:p.x,0,100)+'% '+GRMH.clamp(p.y===undefined?50:p.y,0,100)+'%'; } var photoPanel=document.createElement('details');photoPanel.className='grmh-photo-panel'; var photoSummary=document.createElement('summary');photoSummary.textContent='Fotoğrafı konumlandır'; var photoHelp=document.createElement('p');photoHelp.textContent='Kaydırıcılarla fotoğrafın görünen bölümünü ayarlayın. Hareket, fotoğrafın çerçeve dışında kalan kısmı kadar mümkündür.'; var photoFields=document.createElement('div');photoFields.className='grmh-photo-fields'; var photoInputs={}; ['x','y'].forEach(function(key){ var input=document.createElement('input');input.type='range';input.min='0';input.max='100';input.step='1'; input.className='grmh-photo-'+key;photoInputs[key]=input; var output=document.createElement('output');input.grmhOutput=output; input.addEventListener('input',function(){ var p=state.photo||{x:50,y:50};state.photo={x:p.x,y:p.y};state.photo[key]=Number(input.value); update(true,undefined,true); }); var holder=label(key==='x'?'Yatay konum':'Dikey konum',input);holder.appendChild(output);photoFields.appendChild(holder); }); var centerPhoto=action('Fotoğrafı ortala',function(){state.photo={x:50,y:50};update(true,undefined,true);},'grmh-photo-center'); photoPanel.append(photoSummary,photoHelp,photoFields,centerPhoto);extra.appendChild(photoPanel); function refreshPhoto() { var p=state.photo||{x:50,y:50};image.style.objectPosition=photoPosition(state); ['x','y'].forEach(function(key){var value=GRMH.clamp(p[key]===undefined?50:p[key],0,100);photoInputs[key].value=value;photoInputs[key].grmhOutput.textContent=Math.round(value)+'%';}); } // A modal preview uses the same renderer and a separate stage, never a clone of editor controls. var fullscreenDialog=null,fullscreenFrame=null,fullscreenStage=null,fullscreenImage=null,fullscreenClose=null,previousFocus=null,oldOverflow=''; function refreshFullscreen() { if(!fullscreenDialog || !fullscreenDialog.open) return; var nativeWidth=Number(device.value)||390,scale=Math.min(1,Math.max(1,fullscreenFrame.parentElement.clientWidth-32)/nativeWidth); fullscreenFrame.style.width=(nativeWidth*scale)+'px';fullscreenFrame.style.height=(290*scale)+'px'; var surface=fullscreenStage.parentElement;surface.style.width=nativeWidth+'px';surface.style.transform='scale('+scale+')'; fullscreenImage.src=image.src;fullscreenImage.style.objectPosition=photoPosition(state); GRMH.render(fullscreenStage,data,data.category,undefined,{strict:true}); } function closeFullscreen(){if(fullscreenDialog && fullscreenDialog.open) fullscreenDialog.close();} function openFullscreen() { if(!fullscreenDialog) { fullscreenDialog=document.createElement('dialog');fullscreenDialog.className='grmh-editor grmh-fullscreen-dialog'; fullscreenDialog.setAttribute('aria-label','Manşet tam ekran ön izlemesi'); fullscreenClose=action('Kapat',closeFullscreen,'grmh-fullscreen-close'); var heading=document.createElement('h2');heading.textContent='Manşet ön izlemesi'; var top=document.createElement('div');top.className='grmh-fullscreen-bar';top.append(heading,fullscreenClose); var body=document.createElement('div');body.className='grmh-fullscreen-body'; fullscreenFrame=document.createElement('div');fullscreenFrame.className='grmh-fullscreen-frame'; var surface=document.createElement('div');surface.className='grmh-preview'; fullscreenImage=document.createElement('img');fullscreenImage.className='grmh-preview-image';fullscreenImage.alt=''; fullscreenStage=document.createElement('div');fullscreenStage.className='grmh-stage'; surface.append(fullscreenImage,fullscreenStage);fullscreenFrame.appendChild(surface);body.appendChild(fullscreenFrame); fullscreenDialog.append(top,body);document.body.appendChild(fullscreenDialog); fullscreenDialog.addEventListener('close',function(){document.body.style.overflow=oldOverflow;if(previousFocus && previousFocus.isConnected) previousFocus.focus();}); fullscreenDialog.addEventListener('click',function(event){if(event.target===fullscreenDialog) closeFullscreen();}); window.addEventListener('resize',refreshFullscreen); } previousFocus=fullscreenButton;oldOverflow=document.body.style.overflow; if(typeof fullscreenDialog.showModal!=='function'){report('Bu tarayıcı tam ekran ön izlemeyi desteklemiyor. Güncel Chrome kullanın.');return;} fullscreenDialog.showModal();document.body.style.overflow='hidden';refreshFullscreen();fullscreenClose.focus(); } function validShelf(value) { if(!value || value.version!==1 || !Array.isArray(value.favorites) || !Array.isArray(value.templates) || value.templates.length>30) return false; var ids=GRMH.readyTemplates.map(function(p){return p.id;}); if(value.favorites.length>ids.length || value.favorites.some(function(id){return !ids.includes(id);})) return false; var seen={}; return value.templates.every(function(item){ if(!item || typeof item.id!=='string' || !/^custom-[a-z0-9-]{1,60}$/.test(item.id) || seen[item.id] || typeof item.name!=='string' || !item.name.trim() || item.name.length>60) return false; seen[item.id]=true; var d=item.design;if(!d || !['manual','ready'].includes(d.mode) || !Array.isArray(d.blocks) || d.blocks.length>8) return false; if(typeof d.custom_title!=='string' || d.custom_title.length>600 || JSON.stringify(d).length>24000) return false; if(d.mode==='ready' && (!d.ready || !ids.includes(d.ready.template))) return false; if(d.mode==='manual' && !d.blocks.length) return false; var enums={style:['inherit','hurriyet','sabah','gazetem'],font:Object.keys(fonts),case:Object.keys(cases)}; if(Object.keys(enums).some(function(key){return !enums[key].includes(d[key]);})) return false; if(d.blocks.some(function(b){ if(!b || typeof b.text!=='string' || Array.from(b.text).length>300 || !/^#(?:[0-9a-f]{3}){1,2}$/i.test(b.color)) return true; if(!Object.keys(fonts).includes(b.font) || !Object.keys(cases).includes(b.case) || !['left','center','right'].includes(b.align)) return true; return [['size',12,72],['x',0,100],['y',0,100],['width',10,100]].some(function(rule){return !Number.isFinite(b[rule[0]]) || b[rule[0]]rule[2];}); })) return false; return !item.lines || (Array.isArray(item.lines) && item.lines.length<=8 && item.lines.every(function(n){return Number.isInteger(n) && n>=1 && n<=30;})); }); } try {var loaded=JSON.parse(localStorage.getItem(shelfKey)||'null');if(loaded && validShelf(loaded)) shelf=loaded;} catch(e) {shelfError='Tarayıcıdaki kişisel şablon kaydı okunamadı.';} function saveShelf(next) { try {localStorage.setItem(shelfKey,JSON.stringify(next));shelf=next;return true;} catch(e){report('Tarayıcı kayda izin vermedi. Kişisel şablonlar değişmedi. Gizli moddan çıkın veya tarayıcı depolama ayarını kontrol edin.');return false;} } var personal=document.createElement('details');personal.className='grmh-personal'; var personalSummary=document.createElement('summary');personalSummary.textContent='Kendi şablonlarım'; var personalHelp=document.createElement('p');personalHelp.textContent='Favoriler ve kişisel şablonlar bu tarayıcıda ve bu site adresinde saklanır. Başka telefona veya haber paneline taşımak için dışa / içe aktarın. Haberin tasarımı ayrıca Güncelle / Yayımla ile kaydedilir.'; var personalName=document.createElement('input');personalName.type='text';personalName.maxLength=60;personalName.placeholder='Örneğin: Sarı ekonomi';personalName.className='grmh-template-name'; personalName.addEventListener('keydown',function(event){if(event.key==='Enter'){event.preventDefault();savePersonal();}}); var saveTemplate=action('Bu tasarımı şablon olarak kaydet',savePersonal,'grmh-template-save'); var transfer=document.createElement('div');transfer.className='grmh-extra-actions'; var exportButton=action('Şablonları dışa aktar',exportShelf,'grmh-template-export'); var importButton=action('Şablonları içe aktar',function(){importInput.click();},'grmh-template-import'); var importInput=document.createElement('input');importInput.type='file';importInput.accept='.json,application/json';importInput.hidden=true; var personalList=document.createElement('div');personalList.className='grmh-personal-gallery'; personal.append(personalSummary,personalHelp,label('Şablon adı',personalName),saveTemplate,transfer,personalList); transfer.append(exportButton,importButton,importInput);extra.after(personal); var personalCards=[],shelfRevision=0,paintedShelfRevision=-1,personalPreviewKey=''; function savePersonal() { if(!['manual','ready'].includes(state.mode) || (state.mode==='manual' && !state.blocks.length)) {report('Şablon kaydetmek için Hazır veya Manuel tasarım modunu kullanın.');return;} if(hasLayoutIssue) {report('Şablonu kaydetmeden önce görsele sığmayan blokları düzeltin.');return;} var name=personalName.value.trim();if(!name){report('Önce şablona bir ad yazın.');personalName.focus();return;} if(shelf.templates.length>=30){report('En fazla 30 kişisel şablon saklanabilir. Önce kullanmadığınız bir şablonu silin.');return;} var design=clone(state),lines=design.blocks.map(function(b){return Math.min(30,b.text.split('\n').length);}); design.custom_title='';delete design.photo; if(design.ready){delete design.ready.highlight_text;delete design.ready.highlights;} design.blocks.forEach(function(b){b.text='';b.highlights=[];}); var item={id:'custom-'+Date.now().toString(36)+'-'+Math.random().toString(36).slice(2,9),name:name,design:design,lines:lines}; var next=clone(shelf);next.templates.push(item); if(saveShelf(next)){personalName.value='';shelfRevision++;refreshPersonal();report('Şablon kaydedildi. Yeni haberde seçtiğinizde o haberin başlığı kullanılır.');} } function personalDesign(item) { var design=clone(item.design),title=state.custom_title.trim()||data.title||''; design.photo=clone(state.photo||{x:50,y:50});design.custom_title=state.custom_title; if(design.mode==='manual') { var groups=GRMH.split(title,design.blocks.length); design.blocks.forEach(function(b,i){ b.text=GRMH.split(groups[i]||'',item.lines && item.lines[i] || 1).join('\n');b.highlights=[]; }); } return design; } function exportShelf() { var blob=new Blob([JSON.stringify(shelf,null,2)],{type:'application/json'}),url=URL.createObjectURL(blob),a=document.createElement('a'); a.href=url;a.download='gazetem-kisisel-mansetler.json';document.body.appendChild(a);a.click();a.remove();setTimeout(function(){URL.revokeObjectURL(url);},1000); } importInput.addEventListener('change',function(){ var file=importInput.files[0];importInput.value='';if(!file) return; if(file.size>1000000){report('Şablon dosyası 1 MB sınırını aşıyor.');return;} file.text().then(function(text){ var value;try{value=JSON.parse(text);}catch(e){report('Dosya geçerli bir şablon JSON dosyası değil.');return;} if(!validShelf(value)){report('Şablon dosyasının yapısı uygun değil. Mevcut şablonlar korundu.');return;} var next=clone(shelf);next.favorites=Array.from(new Set(next.favorites.concat(value.favorites))); value.templates.forEach(function(item){if(!next.templates.some(function(old){return old.id===item.id;})) next.templates.push(item);}); if(next.templates.length>30){report('İçe aktarma toplamı 30 şablonu aşıyor. Önce kullanmadıklarınızı silin.');return;} if(saveShelf(next)){shelfRevision++;refreshPersonal();schedule();report('Şablonlar ve favoriler içe aktarıldı.');} }).catch(function(){report('Şablon dosyası okunamadı.');}); }); function refreshPersonal() { if(paintedShelfRevision!==shelfRevision) { personalList.replaceChildren();personalCards=[];paintedShelfRevision=shelfRevision;personalPreviewKey=''; if(!shelf.templates.length){var empty=document.createElement('p');empty.textContent='Henüz kişisel şablon kaydetmediniz.';personalList.appendChild(empty);} shelf.templates.forEach(function(item){ var holder=document.createElement('div');holder.className='grmh-personal-item'; var button=action('',function(){ var design=personalDesign(item); if(design.blocks.some(function(b){return Array.from(b.text).length>300;})){report('Başlık bir blokta 300 karakteri aşıyor. Önce özel mobil başlığı kısaltın veya daha fazla bloklu bir şablon seçin.');return;} restoreDesign(design,true);report('Kişisel şablon uygulandı. Manuel bloklar uzun başlıkta düzenleme gerektirebilir.'); },'grmh-ready-card'); var thumb=document.createElement('span');thumb.className='grmh-ready-thumb'; var photo=document.createElement('img');photo.alt='';var root=document.createElement('span');root.className='grmh-stage'; var title=document.createElement('strong');title.textContent=item.name;thumb.append(photo,root);button.append(thumb,title); var remove=action('Sil',function(){ if(!window.confirm('“'+item.name+'” şablonu silinsin mi?')) return; var next=clone(shelf);next.templates=next.templates.filter(function(t){return t.id!==item.id;}); if(saveShelf(next)){shelfRevision++;refreshPersonal();} },'grmh-template-delete'); holder.append(button,remove);personalList.appendChild(holder);personalCards.push({item:item,image:photo,root:root}); }); } var key=JSON.stringify([state.custom_title,data.title,image.src,state.photo,personalList.clientWidth]); if(!personal.open || key===personalPreviewKey) return; personalPreviewKey=key; personalCards.forEach(function(card){ var d=personalDesign(card.item);card.image.src=image.src;card.image.style.objectPosition=photoPosition(state); GRMH.render(card.root,Object.assign({},data,{design:d}),data.category,undefined,{editor:true,strict:true}); }); } personal.addEventListener('toggle',function(){personalPreviewKey='';refreshPersonal();}); var favoriteOrderKey=null; function refreshFavorites() { var orderKey=JSON.stringify(shelf.favorites);if(favoriteOrderKey===orderKey) return;favoriteOrderKey=orderKey; var sorted=readyCards.slice().sort(function(a,b){return Number(shelf.favorites.includes(b.preset.id))-Number(shelf.favorites.includes(a.preset.id));}); sorted.forEach(function(card){ var favorite=shelf.favorites.includes(card.preset.id); card.star.textContent=favorite?'★':'☆';card.star.setAttribute('aria-pressed',String(favorite)); card.star.setAttribute('aria-label',card.preset.name+(favorite?' favorilerden çıkar':' favorilere ekle')); readyGallery.appendChild(card.holder); }); } refreshPersonal();if(shelfError) report(shelfError); // Ready templates: one text group, independent band, native text selection. var readyPointers=new Map(),readyGesture=null; var bandTool=action('Bandı düzenle',function(){ if(state.mode!=='ready') return; if(layout && layout.band && !layout.band.enabled) setReadyBand({enabled:true}); setToolMode('band'); },'grmh-tool-band'); colorTool.after(bandTool); var readyPanel=document.createElement('div');readyPanel.className='grmh-ready-adjustments'; var readyHelpText=document.createElement('p');readyHelpText.textContent='Taşı / Boyutlandır: tek parmakla taşıyın, iki parmakla küçültüp büyütün; köşe tutamacı da kullanılabilir. Kelime seçmek için Metni seç / Renklendir moduna geçin. Bant ayrı düzenlenir.'; var readyRanges={}; function readyRange(key,title,min,max,step,fn) { var input=document.createElement('input');input.type='range';input.min=min;input.max=max;input.step=step; input.className='grmh-ready-'+key; var out=document.createElement('output');var holder=label(title,input);holder.appendChild(out); input.addEventListener('input',function(){fn(Number(input.value));}); readyRanges[key]={input:input,out:out};return holder; } var textAdjust=document.createElement('div');textAdjust.className='grmh-ready-adjust-grid'; textAdjust.append(readyRange('zoom','Yazı grubu boyutu (%)',20,300,1,function(value){ var g=layout && layout.readyGeometry;if(!g) return; var zoom=GRMH.clamp(value/100,.2,g.maxScale),width=g.base.width*zoom,height=g.base.height*zoom; setReadyBox(zoom,g.box.x+(g.box.width-width)/2,g.box.y+(g.box.height-height)/2); }),readyRange('shade','Fotoğraf üzerindeki gölge koyuluğu (%)',0,100,1,function(value){readyState().shade=value;update(true);})); var resetText=action('Yazının boyutunu ve konumunu sıfırla',function(){delete readyState().adjust;update(true);},'grmh-ready-reset-text'); var clearReadyColors=action('Kelime renklerini temizle',function(){delete readyState().highlights;delete readyState().highlight_text;clearTextSelection();update(true);},'grmh-ready-clear-colors'); var bandDetails=document.createElement('details');bandDetails.className='grmh-ready-band-panel'; var bandSummary=document.createElement('summary');bandSummary.textContent='Bant rengi, boyutu ve şeffaflığı'; var bandEnabled=document.createElement('input');bandEnabled.type='checkbox';bandEnabled.className='grmh-ready-band-enabled'; bandEnabled.addEventListener('change',function(){setReadyBand({enabled:bandEnabled.checked});}); var bandColor=document.createElement('input');bandColor.type='color';bandColor.value='#ffd600';bandColor.className='grmh-ready-band-color'; bandColor.addEventListener('input',function(){setReadyBand({color:bandColor.value});}); var bandFields=document.createElement('div');bandFields.className='grmh-ready-adjust-grid'; bandFields.append(label('Vurgu bandını göster',bandEnabled),label('Bant rengi',colorControl(bandColor)), readyRange('band-opacity','Bant opaklığı (%) — 0 tamamen şeffaf',0,100,1,function(value){setReadyBand({opacity:value});}), readyRange('band-width','Bant genişliği (%)',1,100,.5,function(value){setReadyBand({width:value});}), readyRange('band-height','Bant yüksekliği (%)',.5,100,.5,function(value){setReadyBand({height:value});})); var resetBand=action('Bandı şablonun ilk haline getir',function(){delete readyState().band;update(true);},'grmh-ready-reset-band'); bandDetails.append(bandSummary,bandFields,resetBand); readyPanel.append(readyHelpText,textAdjust,resetText,clearReadyColors,bandDetails);shell.after(readyPanel); function readyState(){if(!state.ready) state.ready=GRMH.readyConfig(data);return state.ready;} function setReadyBox(zoom,x,y) { var g=layout && layout.readyGeometry;if(!g) return; zoom=GRMH.clamp(zoom,Math.min(.2,g.maxScale),g.maxScale); var width=g.base.width*zoom,height=g.base.height*zoom,side=g.width*.015; readyState().adjust={scale:zoom,x:GRMH.clamp(x,side,Math.max(side,g.width-side-width))/g.width*100,y:GRMH.clamp(y,0,Math.max(0,g.height-height))/g.height*100}; update(true); } function setReadyBand(patch) { if(!layout || !layout.band) return; var b=Object.assign({},layout.band,patch); b.width=GRMH.clamp(b.width,1,100);b.height=GRMH.clamp(b.height,.5,100); b.x=GRMH.clamp(b.x,0,100-b.width);b.y=GRMH.clamp(b.y,0,100-b.height); readyState().band=b;update(true); } function readyGuide(box,kind,scale) { var guide=document.createElement('div');guide.className='grmh-ready-guide grmh-ready-guide-'+kind; Object.assign(guide.style,{left:box.x+'px',top:box.y+'px',width:box.width+'px',height:box.height+'px'}); var handle=document.createElement('button');handle.type='button';handle.className='grmh-ready-resize';handle.dataset.readyResize=kind;handle.textContent='↔'; handle.setAttribute('aria-label',kind==='band'?'Bandın genişliğini ve yüksekliğini değiştir':'Yazı grubunu büyüt veya küçült'); var size=44/scale,g=layout.readyGeometry; Object.assign(handle.style,{width:size+'px',height:size+'px',fontSize:(20/scale)+'px',left:GRMH.clamp(box.width-size,-box.x,g.width-box.x-size)+'px',top:GRMH.clamp(box.height-size,-box.y,g.height-box.y-size)+'px'}); guide.appendChild(handle);stage.appendChild(guide); } function refreshReadyEditor(scale) { var active=state.mode==='ready';readyPanel.hidden=!active;bandTool.hidden=!active; editor.classList.toggle('grmh-ready-move',active && toolMode==='move');editor.classList.toggle('grmh-ready-band-mode',active && toolMode==='band'); bandTool.setAttribute('aria-pressed',String(active && toolMode==='band')); if(!active || !layout || !layout.readyGeometry) return; var g=layout.readyGeometry,b=layout.band; readyRanges.zoom.input.max=Math.floor(g.maxScale*100);readyRanges.zoom.input.value=Math.round(g.scale*100);readyRanges.zoom.out.textContent=Math.round(g.scale*100)+'%'; readyRanges.shade.input.value=readyState().shade===undefined?100:readyState().shade;readyRanges.shade.out.textContent=readyRanges.shade.input.value+'%'; bandEnabled.checked=b.enabled;if(bandColor.value.toLowerCase()!==b.color.toLowerCase()){bandColor.value=b.color;if(bandColor.grmhRefreshColor) bandColor.grmhRefreshColor();} ['opacity','width','height'].forEach(function(key){var r=readyRanges['band-'+key];r.input.value=b[key];r.out.textContent=Math.round(b[key]*10)/10+'%';}); if(toolMode==='move') readyGuide(g.box,'text',scale); if(toolMode==='band' && b.enabled) readyGuide({x:b.x/100*g.width,y:b.y/100*g.height,width:b.width/100*g.width,height:b.height/100*g.height},'band',scale); showTextSelection(); } function readReadySelection() { var selection=window.getSelection();if(!selection || selection.isCollapsed || !selection.rangeCount) return; var range=selection.getRangeAt(0); function rowOf(node){var el=node.nodeType===3?node.parentElement:node;return el && el.closest?el.closest('.grmh-ready-line'):null;} var first=rowOf(range.startContainer),last=rowOf(range.endContainer),title=GRMH.readyText(data); if(!first || !last || !stage.contains(first) || !stage.contains(last) || first.dataset.grmhReadyText!==title || last.dataset.grmhReadyText!==title) return; function offset(row,node,end){var r=document.createRange();r.selectNodeContents(row);r.setEnd(node,end);return r.toString().length;} var start=offset(first,range.startContainer,range.startOffset),end=offset(last,range.endContainer,range.endOffset); var a=first.grmhSourceMap,b=last.grmhSourceMap;if(!a || !b || !a.length || !b.length) return; var sourceStart=a[start]===undefined && start===a.length?a[a.length-1]+1:a[start]; var sourceEnd=end===0?b[0]:(b[end-1]===undefined?undefined:b[end-1]+1); if(sourceStart===undefined || sourceEnd===undefined) return; saveReadySelection(sourceStart,sourceEnd,title); } function saveReadySelection(start,end,title) { if(end<=start) return; textSelection={kind:'ready',start:start,end:end,text:title,source:'ready'};showTextSelection(); } function readyTitleSelection() { if(state.mode!=='ready' || toolMode!=='color' || titleInput.selectionEnd<=titleInput.selectionStart) return; var raw=titleInput.value,title=GRMH.readyText(data),trim=Array.from(raw.slice(0,raw.length-raw.trimStart().length)).length; var start=Array.from(raw.slice(0,titleInput.selectionStart)).length-trim,end=Array.from(raw.slice(0,titleInput.selectionEnd)).length-trim; saveReadySelection(Math.max(0,start),Math.min(Array.from(title).length,end),title); } ['select','keyup','pointerup'].forEach(function(type){titleInput.addEventListener(type,readyTitleSelection);}); function point(event) { var r=stage.getBoundingClientRect(),g=layout.readyGeometry; return {x:(event.clientX-r.left)/r.width*g.width,y:(event.clientY-r.top)/r.height*g.height}; } function rebaseReadyGesture(resize) { if(!readyPointers.size || !layout || !layout.readyGeometry) return; if(pending) draw(); var points=Array.from(readyPointers.values()),a=points[0],b=points[1]; readyGesture={kind:toolMode==='band'?'band':'text',resize:resize,points:points.map(function(p){return {x:p.x,y:p.y};}),geometry:clone(layout.readyGeometry),band:clone(layout.band), distance:b?Math.hypot(b.x-a.x,b.y-a.y):0,center:b?{x:(a.x+b.x)/2,y:(a.y+b.y)/2}:a}; } function cancelReadyGesture() { if(!readyPointers) return; var ids=Array.from(readyPointers.keys());readyPointers.clear();readyGesture=null; ids.forEach(function(id){try{if(stage.hasPointerCapture(id))stage.releasePointerCapture(id);}catch(e){}}); if(ids.length) schedule(); } stage.addEventListener('pointerdown',function(event){ if(state.mode!=='ready' || toolMode==='color' || !layout || !layout.readyGeometry || (event.pointerType==='mouse' && event.button!==0)) return; if(toolMode==='band' && !layout.band.enabled) return; if(readyPointers.size>=2) return; event.preventDefault();readyPointers.set(event.pointerId,point(event)); try{stage.setPointerCapture(event.pointerId);}catch(e){} rebaseReadyGesture(!!event.target.closest('[data-ready-resize]')); }); stage.addEventListener('pointermove',function(event){ if(!readyGesture || !readyPointers.has(event.pointerId)) return; event.preventDefault();readyPointers.set(event.pointerId,point(event)); var start=readyGesture,points=Array.from(readyPointers.values()),a=points[0],b=points[1],g=start.geometry; var dx=a.x-start.points[0].x,dy=a.y-start.points[0].y; if(start.kind==='text') { var zoom=g.scale,x=g.box.x+dx,y=g.box.y+dy; if(b && start.distance>1) { zoom=GRMH.clamp(g.scale*Math.hypot(b.x-a.x,b.y-a.y)/start.distance,.2,g.maxScale); var ratio=zoom/g.scale,c={x:(a.x+b.x)/2,y:(a.y+b.y)/2}; x=c.x+(g.box.x-start.center.x)*ratio;y=c.y+(g.box.y-start.center.y)*ratio; } else if(start.resize) {zoom=g.scale*(1+(dx+dy)/Math.max(1,g.box.width+g.box.height));x=g.box.x;y=g.box.y;} setReadyBox(zoom,x,y); } else { var band=start.band,patch; if(b && start.distance>1) { var ratio=Math.hypot(b.x-a.x,b.y-a.y)/start.distance,c={x:(a.x+b.x)/2,y:(a.y+b.y)/2}; var width=GRMH.clamp(band.width*ratio,1,100),height=GRMH.clamp(band.height*ratio,.5,100); patch={width:width,height:height,x:(c.x+(band.x/100*g.width-start.center.x)*(width/band.width))/g.width*100,y:(c.y+(band.y/100*g.height-start.center.y)*(height/band.height))/g.height*100}; } else if(start.resize) patch={width:band.width+dx/g.width*100,height:band.height+dy/g.height*100}; else patch={x:band.x+dx/g.width*100,y:band.y+dy/g.height*100}; setReadyBand(patch); } }); function endReadyPointer(event) { if(!readyPointers.has(event.pointerId)) return; readyPointers.delete(event.pointerId); try{if(stage.hasPointerCapture(event.pointerId)) stage.releasePointerCapture(event.pointerId);}catch(e){} if(event.type==='pointercancel') {cancelReadyGesture();return;} if(readyPointers.size) rebaseReadyGesture(false);else {readyGesture=null;schedule();} } ['pointerup','pointercancel','lostpointercapture'].forEach(function(type){stage.addEventListener(type,endReadyPointer);}); /* Hazır şablonlar için sabit dokunma yüzeyi. */ var grPhone=document.createElement('div'); grPhone.className='grmh-ready-phone-surface'; grPhone.setAttribute('aria-label','Manşeti tek parmakla taşı, iki parmakla boyutlandır'); Object.assign(grPhone.style,{position:'absolute',inset:'0',zIndex:'60',background:'transparent'}); grPhone.style.setProperty('touch-action','none','important'); grPhone.style.setProperty('user-select','none','important'); grPhone.style.setProperty('-webkit-user-select','none','important'); preview.appendChild(grPhone); if(!document.getElementById('grmh-phone-surface-style')) { var grPhoneStyle=document.createElement('style'); grPhoneStyle.id='grmh-phone-surface-style'; grPhoneStyle.textContent= '.grmh-ready-phone-surface{display:none!important;pointer-events:none!important}'+ '.grmh-editor.grmh-is-ready:not(.grmh-select-text) .grmh-ready-phone-surface{display:block!important;pointer-events:auto!important}'; document.head.appendChild(grPhoneStyle); } var grNativeTouch='ontouchstart' in window; function grPhoneActive() { return state.mode==='ready' && toolMode!=='color'; } function grPhoneStop(event) { if(event.cancelable) event.preventDefault(); event.stopImmediatePropagation(); } function grPhonePoint(x,y) { var rect=grPhone.getBoundingClientRect(),g=layout.readyGeometry; return { x:(x-rect.left)/Math.max(1,rect.width)*g.width, y:(y-rect.top)/Math.max(1,rect.height)*g.height }; } function grPhoneCheck() { if(pending) draw(); if(!layout || !layout.readyGeometry) { notice='Boyutlandırma için core.js dosyasının son sürümü gerekli. Dosyayı güncelleyip bu ekranı yeniden açın.'; status.textContent=notice; return false; } return !(toolMode==='band' && !layout.band.enabled); } function grPhoneRebase(resize) { if(!readyPointers.size || !grPhoneCheck()) return; var points=Array.from(readyPointers.values()); var a=points[0],b=points[1]; readyGesture={ kind:toolMode==='band'?'band':'text', resize:!!resize, points:clone(points), geometry:clone(layout.readyGeometry), band:clone(layout.band), distance:b?Math.hypot(b.x-a.x,b.y-a.y):0, center:b?{x:(a.x+b.x)/2,y:(a.y+b.y)/2}:{x:a.x,y:a.y} }; } function grPhoneBegin(id,x,y) { if(!grPhoneActive() || !grPhoneCheck() || readyPointers.size>=2) return; if(!readyPointers.size) historyGesture={}; readyPointers.set(id,grPhonePoint(x,y)); var handle=stage.querySelector('[data-ready-resize="'+(toolMode==='band'?'band':'text')+'"]'); var resize=false; if(handle && readyPointers.size===1) { var r=handle.getBoundingClientRect(); resize=x>=r.left-4 && x<=r.right+4 && y>=r.top-4 && y<=r.bottom+4; } grPhoneRebase(resize); } function grPhoneMove() { if(!grPhoneActive() || !readyGesture || !readyPointers.size) return; var start=readyGesture,g=start.geometry; var points=Array.from(readyPointers.values()),a=points[0],b=points[1]; var dx=a.x-start.points[0].x,dy=a.y-start.points[0].y; if(start.kind==='text') { var zoom=g.scale,x=g.box.x+dx,y=g.box.y+dy; if(b && start.distance>1) { zoom=GRMH.clamp(g.scale*Math.hypot(b.x-a.x,b.y-a.y)/start.distance,.2,g.maxScale); var ratio=zoom/g.scale; x=(a.x+b.x)/2+(g.box.x-start.center.x)*ratio; y=(a.y+b.y)/2+(g.box.y-start.center.y)*ratio; } else if(start.resize) { zoom=g.scale*(1+(dx+dy)/Math.max(1,g.box.width+g.box.height)); x=g.box.x;y=g.box.y; } setReadyBox(zoom,x,y); } else { var band=start.band,patch; if(b && start.distance>1) { var ratio=Math.hypot(b.x-a.x,b.y-a.y)/start.distance; var width=GRMH.clamp(band.width*ratio,1,100); var height=GRMH.clamp(band.height*ratio,.5,100); patch={ width:width,height:height, x:((a.x+b.x)/2+(band.x/100*g.width-start.center.x)*(width/band.width))/g.width*100, y:((a.y+b.y)/2+(band.y/100*g.height-start.center.y)*(height/band.height))/g.height*100 }; } else if(start.resize) { patch={width:band.width+dx/g.width*100,height:band.height+dy/g.height*100}; } else { patch={x:band.x+dx/g.width*100,y:band.y+dy/g.height*100}; } setReadyBand(patch); } } function grPhoneEnd(ids,cancelled) { ids.forEach(function(id){readyPointers.delete(id);}); if(cancelled) readyPointers.clear(); if(readyPointers.size) grPhoneRebase(false); else { readyGesture=null;historyGesture=null;historyKey=null; schedule(); } } grPhone.addEventListener('touchstart',function(event){ if(!grPhoneActive()) return; grPhoneStop(event); Array.from(event.changedTouches).forEach(function(t){ grPhoneBegin('t'+t.identifier,t.clientX,t.clientY); }); },{passive:false}); grPhone.addEventListener('touchmove',function(event){ if(!grPhoneActive() || !readyGesture) return; grPhoneStop(event); Array.from(event.touches).forEach(function(t){ var id='t'+t.identifier; if(readyPointers.has(id)) readyPointers.set(id,grPhonePoint(t.clientX,t.clientY)); }); grPhoneMove(); },{passive:false}); ['touchend','touchcancel'].forEach(function(type){ grPhone.addEventListener(type,function(event){ if(!grPhoneActive()) return; grPhoneStop(event); grPhoneEnd(Array.from(event.changedTouches).map(function(t){return 't'+t.identifier;}),type==='touchcancel'); },{passive:false}); }); grPhone.addEventListener('pointerdown',function(event){ if(!grPhoneActive()) return; if(event.pointerType==='touch' && grNativeTouch) {event.stopImmediatePropagation();return;} if(event.pointerType==='mouse' && event.button!==0) return; grPhoneStop(event); grPhoneBegin('p'+event.pointerId,event.clientX,event.clientY); try{grPhone.setPointerCapture(event.pointerId);}catch(e){} }); grPhone.addEventListener('pointermove',function(event){ var id='p'+event.pointerId; if(!grPhoneActive() || !readyPointers.has(id) || !readyGesture) return; grPhoneStop(event); readyPointers.set(id,grPhonePoint(event.clientX,event.clientY)); grPhoneMove(); }); ['pointerup','pointercancel','lostpointercapture'].forEach(function(type){ grPhone.addEventListener(type,function(event){ var id='p'+event.pointerId; if(!readyPointers.has(id)) return; grPhoneStop(event); grPhoneEnd([id],type==='pointercancel'); try{if(grPhone.hasPointerCapture(event.pointerId))grPhone.releasePointerCapture(event.pointerId);}catch(e){} }); }); buildList();sync(false);draw();resetHistory(); }); })();