Commit f5d9a42e by ramdayalmunda

added custom dropdown feature and handled heading sections

parent 9db9b45e
......@@ -84,6 +84,7 @@ canvas:focus-visible {
opacity: 1;
pointer-events: auto;
z-index: 10;
animation: shineAnimation 1s infinite alternate;
}
.toolbar .item:hover {
......@@ -120,16 +121,14 @@ canvas:focus-visible {
overflow-y: hidden;
}
.content-area .left-sidebar {
width: 200px;
background-color: #408640;
padding: 5px;
}
.content-area .left-sidebar,
.content-area .right-sidebar {
max-width: 200px;
width: 200px;
background-color: #f5c468;
background-color: #408640;
padding: 5px;
white-space: nowrap; /* Prevent text wrapping */
text-overflow: ellipsis; /* Add ellipsis ( ... ) */
}
.content-area .left-sidebar,
......@@ -138,7 +137,7 @@ canvas:focus-visible {
flex-shrink: 0;
height: 100%;
overflow-x: hidden;
overflow-y: auto;
overflow-y: hidden;
text-wrap: nowrap;
transition: 0.5s;
margin-top: 0;
......@@ -156,8 +155,6 @@ canvas:focus-visible {
.left-sidebar .content,
.right-sidebar .content {
opacity: 1;
position: relative;
left: 0%;
transition: 0.5s;
}
......@@ -179,6 +176,7 @@ canvas:focus-visible {
background: #858585;
gap: 20px;
align-items: center;
overflow-x: hidden;
}
.page-list canvas {
......@@ -198,31 +196,49 @@ canvas:focus-visible {
width: 100%;
background-color: red;
}
.toolbar .item ul.dropdown {
position: absolute;
max-height: 300px;
width: max-content;
min-width: 100px;
padding: 0;
border: 1px #000 solid;
overflow-y: auto;
overflow-x: hidden;
list-style-type: none;
z-index: 2;
display: none;
background: white;
}
.toolbar .item ul.dropdown.show
{
display: block;
}
.toolbar .item ul.dropdown li{
padding: 5pt;
width: 100%;
}
.toolbar .item ul.dropdown li:hover,
.toolbar .item ul.dropdown li.selected {
background: #09f;
}
li.init {
cursor: pointer;
}
a#submit {
z-index: 1;
}
@keyframes shineAnimation {
0% {
background: #fff;
}
50% {
background: #ddd;
}
100% {
background: #fff;
background: #eee;
}
}
\ No newline at end of file
*::-webkit-scrollbar {
background: transparent;
}
*::-webkit-scrollbar-track {
background-color: #00000022;
border-radius: 5px;
}
*::-webkit-scrollbar-thumb {
background: #7dbbb3;
border-radius: 5px;
}
\ No newline at end of file
......@@ -9,15 +9,20 @@ var ADocEditor = function (customConfig) {
const letters = { "0": "a", "1": "b", "2": "c", "3": "d", "4": "e", "5": "f", "6": "g", "7": "h", "8": "i", "9": "j", "a": "k", "b": "l", "c": "m", "d": "n", "e": "o", "f": "p", "g": "q", "h": "r", "i": "s", "j": "t", "k": "u", "l": "v", "m": "w", "n": "x", "o": "y", "p": "z" }
const romanNumerals = [["I", "IV", "V", "IX"], ["X", "XL", "L", "XC"], ["C", "CD", "D", "CM"], ["M"]];
const styleList = [
{ name: "Normal Text", fontFamily: "Calibri", fontSize: 11, fontColor: "#f00", bold: false, italic: false },
{ name: "Title", fontFamily: "Calibri", fontSize: 26, fontColor: "#0f0", bold: false, italic: false },
{ name: "Subtitle", fontFamily: "Calibri", fontSize: 15, fontColor: "#555", bold: false, italic: false },
{ name: "Heading 1", fontFamily: "Calibri", fontSize: 20, fontColor: "#00f", bold: false, italic: false },
const textStyleList = [
{ type: "Normal Text", fontFamily: "Calibri", fontSize: 11, fontColor: "#000", bold: false, italic: false, spaces: 10 },
{ type: "Title", fontFamily: "Calibri", fontSize: 26, fontColor: "#000", bold: false, italic: false, spaces: 0 },
{ type: "Subtitle", fontFamily: "Calibri", fontSize: 15, fontColor: "#555", bold: false, italic: false, spaces: 4 },
{ type: "Heading 1", fontFamily: "Calibri", fontSize: 20, fontColor: "#000", bold: false, italic: false, spaces: 2 },
]
const styleName = {};
textStyleList.forEach((sty, s) => { styleName[sty.type] = s })
const listStyles = [
{ type: "Number", value: 0 },
{ type: "Bullet", value: 1 },
]
const styleName = { };
styleList.forEach( (sty, s)=> { styleName[sty.name] = s } )
var defaultConfig = {
pageSetup: { size: "A4" }, zoom: 1,
......@@ -28,11 +33,12 @@ var ADocEditor = function (customConfig) {
tabWidth: 10, // mm
},
style: {
fontSize: 11, // this is in pt // 1pt = 1/72 inch // 1pt = 254/72 mm
fontFamily: 'Calibri',
bold: false,
italic: false,
fontColor: "#f01"
type: textStyleList[0].type,
// fontSize: 11, // this is in pt // 1pt = 1/72 inch // 1pt = 254/72 mm
// fontFamily: 'Calibri',
// bold: false,
// italic: false,
// fontColor: "#f01",
},
}
config = JSON.parse(JSON.stringify(defaultConfig))
......@@ -97,31 +103,21 @@ var ADocEditor = function (customConfig) {
</div>
<div class="toolbar">
<select class="item" adc="font-select"></select>
<div class="item" adc="list-handler" adc-target="list-popover">
<span>L</span>
<div class="popover" adc="list-popover" adc-type="popover">
<div class="option" adc-toggle="popover" value="1">•&nbsp;&nbsp;Bullets&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div>
<div class="option" adc-toggle="popover" value="0">1. Numbers</div>
</div>
</div>
<div class="item" adc="font-family"></div>
<div class="item" adc="list-style"></div>
<div class="item">
<button adc="font-size-change" class="small-btn" value="-1">-</button>
<input type="number" adc="font-size-input" class="small-input">
<button adc="font-size-change" class="small-btn" value="+1">+</button>
</div>
<div class="item" adc="style-handler" adc-target="style-popover" style="width: 150px;">
<span>Normal Text</span>
<div class="popover" adc="style-popover" adc-type="popover">
<div class="option" adc-toggle="popover" value="1">Normal Text</div>
<div class="option" adc-toggle="popover" value="0">Header 1</div>
</div>
</div>
<div class="item" adc="style-handler"></div>
</div>
</div>
<div class="content-area">
<div class="left-sidebar hide">
<div class="left-sidebar">
<button class="toggle-btn" adc="toggle-left-sidebar">X</button>
<div class="content" adc="left-sidebar-content"></div>
</div>
......@@ -194,19 +190,6 @@ var ADocEditor = function (customConfig) {
})()
!(function fontSelectHandle() {
let fontSelect = shadow.querySelector('[adc="font-select"]')
let caretStyle = getFullStyle(caretData.style)
fontSelect.value = caretStyle.fontFamily
fontSelect.addEventListener('change', (e) => {
if (e.target.value){
caretData.style = {
...caretStyle,
fontFamily: e.target.value,
}
delete caretData.style.type
focusOnPage()
}
})
addFonts(["./assets/fonts/Afacad-VariableFont_wght.woff2", "./assets/fonts/Afacad-VariableFont_wght.ttf"], 'Afacad')
addFonts(["./assets/fonts/ArchitectsDaughter-Regular.woff2", "./assets/fonts/ArchitectsDaughter-Regular.ttf"], 'Architects Daughter')
addFonts(["./assets/fonts/Assistant-VariableFont_wght.woff2", "./assets/fonts/Assistant-VariableFont_wght.ttf"], 'Assistant')
......@@ -216,26 +199,42 @@ var ADocEditor = function (customConfig) {
})()
!(function handleList() {
let listItems = shadow.querySelectorAll('[adc-toggle="popover"]')
let popover = shadow.querySelector('[adc-type="popover"]')
for (let i = 0; i < listItems.length; i++) {
listItems[i].addEventListener('click', (e) => {
let value = Number(e.target.getAttribute('value'))
value = value ? value : 0
// handle list
let listStyleElem = shadow.querySelector('[adc="list-style"]')
listStyleElem.innerHTML = ""
let selection = document.createElement('span')
selection.setAttribute('value', null)
selection.setAttribute('adc-type', 'selection')
selection.innerHTML = "[List-Style]"
listStyleElem.append(selection)
let ul = document.createElement('ul')
ul.setAttribute('class', 'dropdown')
listStyleElem.append(ul)
listStyles.forEach(item => {
let option = document.createElement('li')
option.setAttribute('value', item.value)
option.innerHTML = item.type
ul.append(option)
option.addEventListener('click', (e) => {
if (caretData.activeData) {
caretData.activeData.type = (caretData.activeData.type == 1 && caretData.activeData.listStyle == value) ? 0 : 1
caretData.activeData.type = (caretData.activeData.type == 1 && caretData.activeData.listStyle == item.value) ? 0 : 1
if (caretData.activeData.type == 1) {
caretData.activeData.listStyle = value
caretData.activeData.listStyle = item.value
} else {
e.stopPropagation()
ul.classList.remove('show')
selection.innerHTML = "[List-Style]"
}
changeListStyle()
caretData.blink = false
reRenderCanvas()
popover.classList.remove('show')
focusOnPage()
}
})
}
})
})()
!(function fontSizeHandler() {
......@@ -245,11 +244,18 @@ var ADocEditor = function (customConfig) {
let fontSizeChangers = shadow.querySelectorAll('[adc="font-size-change"]')
fontSizeChangers.forEach(btn => {
btn.addEventListener('click', (e) => {
let caretStyle = getFullStyle(caretData.style)
let change = Number(e.target.getAttribute('value'))
change = change ? change : 0
change = caretData.style.fontSize + change
change = change ? change : config.style.fontSize
caretData.style.fontSize = change
change = caretStyle.fontSize + change
change = change ? change : caretStyle.fontSize
caretData.style = {
...caretStyle,
fontSize: change,
}
delete caretData.style.type
fontSizeInput.value = change
focusOnPage()
})
......@@ -257,8 +263,13 @@ var ADocEditor = function (customConfig) {
function changeFontEvent(e) {
let value = Number(e.target.value)
let caretStyle = getFullStyle(caretData.style)
value = value ? value : config.style.fontSize
caretData.style.fontSize = value
caretData.style = {
...caretStyle,
fontSize: value,
}
delete caretData.style.type
if (e?.key == 'Enter') focusOnPage()
}
fontSizeInput.addEventListener('keydown', changeFontEvent)
......@@ -293,33 +304,49 @@ var ADocEditor = function (customConfig) {
.addEventListener('click', printDoc)
})()
!(function styleHandler(){
let stylePopup = shadow.querySelector('[adc="style-popover"]')
stylePopup.innerHTML = ""
styleList.forEach( (style, s)=>{
let option = document.createElement('div')
option.setAttribute('class', 'option')
option.setAttribute('adc-toggle', "popover")
option.append(style.name)
!(function styleHandler() {
let textStyleElem = shadow.querySelector('[adc="style-handler"]')
textStyleElem.innerHTML = ""
let selectionElem = document.createElement('span')
selectionElem.setAttribute('adc-type', 'selection')
if (caretData.style.type) selectionElem.innerHTML = caretData.style.type
else selectionElem.innerHTML = "[CUSTOM]"
textStyleElem.append(selectionElem)
let ul = document.createElement('ul')
ul.setAttribute('class', 'dropdown')
textStyleElem.append(ul)
textStyleList.forEach((style, s) => {
let option = document.createElement('li')
option.setAttribute('value', style.type)
option.append(style.type)
option.style.fontFamily = style.fontFamily
option.style.fontSize = `${style.fontSize}pt`
option.style.color = style.fontColor
stylePopup.append(option)
option.addEventListener('click', (e)=>{
stylePopup.classList.remove('show')
if (caretData.activeData){
caretData.activeData.style = { ...style }
ul.append(option)
option.addEventListener('click', (e) => {
if (caretData.activeData) {
caretData.activeData.style = { type: style.type }
for (let c = 0; c < caretData.activeData.formatedText.length; c++) {
caretData.activeData.formatedText[c].style = { type: style.type }
}
reRenderCanvas()
focusOnPage()
caretData.style = { type: style.type }
caretData.blink = false
renderCaret(true)
}
setupHeaders()
})
})
} )
})()
!(function sidebarsHandlers(){
!(function sidebarsHandlers() {
let leftSidebar = shadow.querySelector('.left-sidebar')
let toggleLeft = shadow.querySelector('[adc="toggle-left-sidebar"]')
toggleLeft.addEventListener('click', ()=>{
toggleLeft.addEventListener('click', () => {
leftSidebar.classList.toggle('hide')
})
......@@ -336,6 +363,8 @@ var ADocEditor = function (customConfig) {
reRenderCanvas()
addGlobalEvents()
}
function reConfigure(newConfig) {
if (newConfig?.size && paperSizes[newConfig?.size]) { config.pageSetup = { ...paperSizes[newConfig.size], size: newConfig.size } }
else if (newConfig?.width && newConfig?.height) {
......@@ -387,6 +416,7 @@ var ADocEditor = function (customConfig) {
lines = []
setupHeaders(); // this is async function //
calculateTextSizeAndPosition()
renderLines()
caretData.previousCaret = null
......@@ -396,7 +426,7 @@ var ADocEditor = function (customConfig) {
let d = 0, c = 0;
function getLineObj() {
let newLineObj = {
...config.style,
...getFullStyle(config.style),
x: 0, // this is the starting point x; it will change based on the tabNumber
y: 0, // this is the starting y coordinate; it will change based on the max font size
plainContent: "",
......@@ -667,6 +697,7 @@ var ADocEditor = function (customConfig) {
dataObj.plainContent = caretData.activeData.plainContent.slice(caretData.index)
caretData.activeData.plainContent = caretData.activeData.plainContent.slice(0, caretData.index)
dataObj.formatedText = caretData.activeData.formatedText.splice(caretData.index)
let activeDataIndex = dataList.findIndex(item => item.id == caretData.activeData.id)
dataList.splice(activeDataIndex + 1, 0, dataObj)
......@@ -674,6 +705,10 @@ var ADocEditor = function (customConfig) {
caretData.index = 0
caretData.activeData = dataObj
if (dataObj.type == 0) dataObj.tabCount = 0
if (!dataObj.formatedText.length){
caretData.style = { type: textStyleList[0].type }
caretData.activeData.style = { type: textStyleList[0].type }
}
// dataList.push(dataObj)
}
else if (e.key.length == 1 && !e.ctrlKey && !e.metaKey) { // displayable text
......@@ -681,8 +716,8 @@ var ADocEditor = function (customConfig) {
e.preventDefault()
caretData.activeData.plainContent = caretData.activeData.plainContent.slice(0, caretData.index) + e.key + caretData.activeData.plainContent.slice(caretData.index)
let style = caretData.style
style = style?style:null
caretData.activeData.formatedText.splice(caretData.index, 0, { style : style, dimension: {} })
style = style ? style : null
caretData.activeData.formatedText.splice(caretData.index, 0, { style: style, dimension: {} })
++caretData.index
}
else if (e.key == 'ArrowLeft') {
......@@ -764,13 +799,15 @@ var ADocEditor = function (customConfig) {
const pxY = (e.clientY - rect.top) * config.pageSetup.pxHeight / rect.height;
placeCaret({ x: pxX, y: pxY })
let style = caretData.activeData.formatedText[caretData.index]?.style
if (style) caretData.style = {
...caretData.style,
fontSize: style.fontSize,
}
if (style){
caretData.style = { ...style }
let fullStyle = getFullStyle(style)
let fontInput = shadow.querySelector('[adc="font-size-input"]')
if (caretData?.style?.fontSize) fontInput.value = caretData.style.fontSize
else if (style?.fontSize) fontInput.value = style.fontSize
if (caretData?.style?.fontSize) fontInput.value = fullStyle.fontSize
else if (style?.fontSize) fontInput.value = fullStyle.fontSize
caretData.blink = false
renderCaret(true)
}
}
}
function onFocusHandler(e) {
......@@ -888,24 +925,39 @@ var ADocEditor = function (customConfig) {
}
function reRenderFontDropdown() {
let fontFamilyDropdown = shadow.querySelector('[adc="font-select"]')
let fontFamilyDropdown = shadow.querySelector('[adc="font-family"]')
if (fontFamilyDropdown) {
fontFamilyDropdown.innerHTML = ""
let selectionOption = document.createElement('span')
selectionOption.setAttribute('adc-type', 'selection')
let caretStyle = getFullStyle(caretData.style)
selectionOption.innerHTML = caretStyle.fontFamily
fontFamilyDropdown.append(selectionOption)
let ul = document.createElement('ul')
ul.setAttribute('class', 'dropdown')
fontFamilyDropdown.append(ul)
fontList.forEach((font, i) => {
let optionTag = document.createElement('option')
let optionTag = document.createElement('li')
optionTag.setAttribute('value', font.name)
optionTag.style.fontFamily = font.name
optionTag.innerText = font.name
fontFamilyDropdown.append(optionTag)
ul.append(optionTag)
optionTag.addEventListener('click', () => {
let caretStyle = getFullStyle(caretData.style)
caretData.style = {
...caretStyle,
fontFamily: font.name,
}
delete caretData.style.type
focusOnPage()
// selectionOption.style.fontFamily = font.name
})
})
// selectionOption.style.fontFamily = caretStyle.fontFamily
}
changeFontFamily()
}
function changeFontFamily() {
let fontFamilyDropdown = shadow.querySelector('[adc="font-select"]')
let caretStyle = getFullStyle(caretData.style)
if (fontFamilyDropdown) fontFamilyDropdown.value = caretStyle.fontFamily
}
}
......@@ -917,50 +969,65 @@ var ADocEditor = function (customConfig) {
function addGlobalEvents(e) {
shadow.querySelector('[adc="page-list"]').addEventListener('wheel', onMouseWheelHandler)
shadow.addEventListener('mousedown', globalMouseDownHandler)
// shadow.addEventListener('mousedown', globalMouseDownHandler)
shadow.addEventListener('click', globalClickDownHandler)
shadow.addEventListener('mouseover', globalMouseOverHandler)
}
function globalMouseDownHandler(e) {
var elem = e.target
var targetId = elem.getAttribute('adc-target')
if (elem.getAttribute('adc-type') == 'popover') { return }
while (!targetId && elem) {
elem = elem.parentNode
if (elem?.getAttribute?.('adc-type') == 'popover') return
targetId = elem?.getAttribute?.('adc-target')
function globalClickDownHandler(e) {
// these is to handle the dropdown items
let target;
let elem = e.target
let selection
if (elem?.tagName == 'LI') {
selection = elem?.textContent
}
while (elem) {
if (elem?.tagName == 'DIV' && elem?.classList?.contains('item')) {
target = elem.querySelector('ul.dropdown');
break;
}
elem = elem?.parentNode
}
if (target) {
if (selection) {
let selectionOption = elem.querySelector('[adc-type="selection"]')
selectionOption.innerHTML = selection
}
let allPopovers = shadow.querySelectorAll('[adc-type="popover"]')
allPopovers.forEach(item => {
if (item.getAttribute('adc') == targetId) item.classList.toggle('show')
else item.classList.remove('show')
target?.classList?.toggle('show')
}
let ulElem = shadow.querySelectorAll('ul.dropdown')
ulElem.forEach(item => {
if (target != item) item?.classList?.remove('show')
})
}
function globalMouseOverHandler(e){
function globalMouseOverHandler(e) {
let menuItems = shadow.querySelectorAll('[adc-type="menu-item"]')
menuItems.forEach( item => item.classList.remove('hover') )
menuItems.forEach(item => item.classList.remove('hover'))
let hoverElem
let elem = e?.target
while(elem){
if (elem?.getAttribute?.('adc-type')=='menu-item' ){
while (elem) {
if (elem?.getAttribute?.('adc-type') == 'menu-item') {
hoverElem = elem;
break
}
elem = elem.parentNode
}
if (hoverElem){
if (hoverElem) {
hoverElem.classList.add('hover')
}
}
function getFullStyle(refStyle){
let style = { }
if (refStyle.type){
style = { ...styleList[styleName[refStyle.type] ] }
function getFullStyle(refStyle) {
let style = {}
if (refStyle.type) {
style = { ...textStyleList[styleName[refStyle.type]] }
}
style = { ...style, ...refStyle }
style = JSON.parse( JSON.stringify(style) )
style = JSON.parse(JSON.stringify(style))
if (Object.keys(style).length > 1) delete style.type
return style
}
......@@ -1222,6 +1289,26 @@ var ADocEditor = function (customConfig) {
link.click();
}
async function setupHeaders(){
let headerList = shadow.querySelector('[adc="left-sidebar-content"]')
headerList.innerHTML = ""
for(let d=0; d<dataList.length; d++){
let styleIndex = textStyleList.findIndex( item => item.type == dataList[d]?.style?.type )
if (styleIndex>0 && dataList[d].plainContent.length){
let headingItem = document.createElement('div')
headingItem.innerHTML = dataList[d].plainContent
headingItem.innerHTML = "&nbsp;".repeat(textStyleList[styleIndex].spaces)+headingItem.innerHTML
headerList.append(headingItem)
let headingStyle = getFullStyle(dataList[d].style)
headingItem.style.fontSize = `${headingStyle.fontSize/1.2}pt`
headingItem.style.width = '100%'
headingItem.style.whiteSpace = 'nowrap'
headingItem.style.overflow = "hidden"
headingItem.style.textOverflow = "ellipsis"
}
}
}
var returnObj = {
getDocumentData() {
return compressDocJSON()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment