Docs: Difference between revisions

From Our World of Text Wiki
Jump to navigation Jump to search
m (Added page to Documentation category.)
 
(36 intermediate revisions by 4 users not shown)
Line 1: Line 1:
=Our World Of Text=
=Our World Of Text=
This page contains documentation of the OWOT codebase, examples, and code locations.
If you want to talk about this page, go to [[Talk:Docs]]
If you want to talk about this page, go to [[Talk:Docs]]
===Code Documentation===
===Code Documentation===
Line 5: Line 7:
==OWOT.js==
==OWOT.js==


===Functions:===
=== Event Listeners: ===
{| class="wikitable"
{| class="wikitable"
|+
|+
!Name
!Object
!Description
!Listen Event
!Functions/Events Fired
!Emits
!Example Usage
!Example Usage
!Code In Use
!Related Code
|-
|-
|window
|load
|
|
|"clientLoaded"
|
|
|<syntaxhighlight lang="javascript" line="1" start="187">
window.addEventListener("load", function() {
w.emit("clientLoaded");
});
</syntaxhighlight>
|-
|
|
|hash change
|manageCoordHash();
|
|
|https://ourworldoftext.com/#x:10,y:20
|<syntaxhighlight lang="javascript" line="1" start="5639">
window.onhashchange = function(e) {
manageCoordHash();
}
</syntaxhighlight>
|-
|-
|
|
|before unload
|if(writeBuffer.length) flushWrites();
|
|
|
|
|<syntaxhighlight lang="javascript" line="1" start="5643">
window.onbeforeunload = function() {
if(writeBuffer.length) flushWrites();
}
</syntaxhighlight>
|-
|
|
|resize
|event_resize
|("resize", ratio)
|
|<syntaxhighlight lang="javascript" line="1" start="1192">
window.addEventListener("resize", event_resize);
</syntaxhighlight>
|-
|-
|document
|select start
|self
|
|
|
|
|<syntaxhighlight lang="javascript" line="1" start="5647">
document.onselectstart = function(e) {
var target = e.target;
if(closest(target, getChatfield()) || target == elm.chatbar || closest(target, elm.confirm_js_code) || closest(target, elm.announce_text)) {
return true;
}
return Modal.isOpen;
}
</syntaxhighlight>
|-
|
|
|key down
|
|
|}
* keydown_regionSelect
 
* event_keydown_copy_char
===Variables:===
* event_keydown_copy_color
{| class="wikitable mw-collapsible"
* event_keydown
|+
|
!Name
|
!Description
|<syntaxhighlight lang="javascript" line="1" start="525">
!Example Usage
document.addEventListener("keydown", keydown_regionSelect);
!Code In Use
</syntaxhighlight><syntaxhighlight lang="javascript" line="1" start="1344">
document.addEventListener("keydown", event_keydown_copy_char);
</syntaxhighlight><syntaxhighlight lang="javascript" line="1" start="1371">
document.addEventListener("keydown", event_keydown_copy_color);
</syntaxhighlight><syntaxhighlight lang="javascript" line="1" start="2955">
document.addEventListener("keydown", event_keydown);
</syntaxhighlight>
|-
|
|key up
|event_keyup
|("keyUp", e);
|
|<syntaxhighlight lang="javascript" line="1" start="2957">
function event_keyup(e) {
w.emit("keyUp", e);
}
</syntaxhighlight>
|-
|-
|YourWorld
|
|An object containing the users current text color, cell background color, and chat nick name.
|mouse move
|<syntaxhighlight lang="javascript">
|
//Sets the users color to a random one.
* mousemove_tileProtectAuto
YourWorld.Color = Math.round((Math.random()*16777215));
* mousemove_linkAuto
</syntaxhighlight>
* event_mousemove
|<syntaxhighlight lang="javascript" line="1">
|("mouseMove", {
var YourWorld = {
tileX: tileX,
Color: window.localStorage ? +localStorage.getItem("color") : 0,
 
BgColor: -1,
tileY: tileY,
Nickname: state.userModel.username
 
};
charX: charX,
 
charY: charY,
 
pageX: pageX,
 
pageY: pageY
 
})
|
|<syntaxhighlight lang="javascript" line="1" start="945">
document.addEventListener("mousemove", mousemove_tileProtectAuto);
</syntaxhighlight><syntaxhighlight lang="javascript" line="1" start="1075">
document.addEventListener("mousemove", mousemove_linkAuto);
</syntaxhighlight><syntaxhighlight lang="javascript" line="1" start="3321">
document.addEventListener("mousemove", event_mousemove);
</syntaxhighlight>
</syntaxhighlight>
|-
|-
|owot
|
|The DOM canvas element
|mouse down
|<syntaxhighlight lang="javascript">
|event_mousedown
//Hides the owot canvas.
|("mouseDown", {
owot.style.opacity = 0;
tileX: pos[0],
 
tileY: pos[1],
 
charX: pos[2],
 
charY: pos[3],
 
pageX: pageX,
 
pageY: pageY
 
});
|
|<syntaxhighlight lang="javascript" line="1" start="1771">
document.addEventListener("mousedown", event_mousedown);
</syntaxhighlight>
</syntaxhighlight>
|<syntaxhighlight lang="javascript" line="1" start="12">
|-
owot = document.getElementById("owot");
|
|mouse up
|event_mouseup
|
|
|<syntaxhighlight lang="javascript" line="1" start="1947">
document.addEventListener("mouseup", event_mouseup);
</syntaxhighlight>
</syntaxhighlight>
|-
|-
|owotCtx
|
|The CanvasRenderingContext2D of the owot canvas
|mouse enter
|<syntaxhighlight lang="javascript">
|event_mouseenter
//Clears all the rendered tiles from the view.
|("mouseEnter", e)
owotCtx.clearRect(0, 0, owotWidth, owotHeight);
|
|<syntaxhighlight lang="javascript" line="1" start="1958">
document.addEventListener("mouseenter", event_mouseenter);
</syntaxhighlight>
</syntaxhighlight>
|<syntaxhighlight lang="javascript" line="1" start="15">
|-
owotCtx = owot.getContext("2d");
|
|touch start
|event_touchstart
|
|
|<syntaxhighlight lang="javascript" line="1" start="3452">
document.addEventListener("touchstart", event_touchstart);
</syntaxhighlight>
</syntaxhighlight>
|-
|-
|textInput
|
|The DOM textarea element used for writing to the owot canvas.
|touch end
|<syntaxhighlight lang="javascript">
|event_touchend
//Paste "hello world" at the current cursor position.
|
textInput.value = `hello world`;
|
</syntaxhighlight>
|<syntaxhighlight lang="javascript" line="1" start="3453">
|<syntaxhighlight lang="javascript" line="1" start="16">
document.addEventListener("touchend", event_touchend);
textInput = document.getElementById("textInput");
</syntaxhighlight>
</syntaxhighlight>
|-
|-
|linkElm
|
|The DOM link element used for user link clicks.
|touch move
|<syntaxhighlight lang="javascript">
|event_touchmove
//logs to the console whether or not the link is a javascript link.
|
linkElm.addEventListener(`click`,function(){
|
console.log(linkParams.protocol === `javascript`);                 
|<syntaxhighlight lang="javascript" line="1" start="3454">
})
document.addEventListener("touchmove", event_touchmove, { passive: false });
</syntaxhighlight>
|<syntaxhighlight lang="javascript" line="1" start="18">
linkElm = elm.link_element;
</syntaxhighlight>
</syntaxhighlight>
|-
|-
|link_div
|
|The DOM link div element used to scale the linkElm to the same size as a cell within the owot canvas.
|wheel
|<syntaxhighlight lang="javascript">
|
//Highlights the URL being hovered over.
* event_wheel
linkDiv.style.background = `rgba(255,255,0,0.5)`
* event_wheel_zoom
|("scroll", {
deltaX: -deltaX,
 
deltaY: -deltaY
 
});
|
|<syntaxhighlight lang="javascript" line="1" start="3487">
document.addEventListener("wheel", event_wheel);
</syntaxhighlight><syntaxhighlight lang="javascript" line="1" start="3537">
document.addEventListener("wheel", event_wheel_zoom, {
passive: false
});
</syntaxhighlight>
</syntaxhighlight>
|<syntaxhighlight lang="javascript" line="1" start="19">
|-
linkDiv = elm.link_div;
|document.body
|key down
|
* keydown_tileProtectAuto
* keydown_linkAuto
|
|
|<syntaxhighlight lang="javascript" line="1" start="1012">
document.body.addEventListener("keydown", keydown_tileProtectAuto);
</syntaxhighlight><syntaxhighlight lang="javascript" line="1" start="1138">
document.body.addEventListener("keydown", keydown_linkAuto);
</syntaxhighlight>
</syntaxhighlight>
|-
|-
|colorInput, colorInputBg
|
|The DOM color inputs to select text and cell background color.
|key up
|<syntaxhighlight lang="javascript">
|onKeyUp
//Generate a random color on the text color input field.
|
const randomColor = Math.floor(Math.random()*16777215).toString(16).toUpperCase();
|
colorInput.jscolor.fromString(`#${randomColor}`);
|<syntaxhighlight lang="javascript" line="1" start="1164">
document.body.addEventListener("keyup", onKeyUp);
</syntaxhighlight>
</syntaxhighlight>
|<syntaxhighlight lang="javascript" line="1" start="5718">
|-
colorInputBg = modal.addEntry("Cell color", "color").input;
|w
</syntaxhighlight><syntaxhighlight lang="javascript" line="1" start="5766">
|cursor Move
colorInput = modal.addEntry("Text color", "color").input;
|updateCoordDisplay
|
|
|<syntaxhighlight lang="javascript" line="1" start="280">
w.on("cursorMove", updateCoordDisplay);
</syntaxhighlight>
</syntaxhighlight>
|-
|-
|colorShortcuts, colorShortcutsBg
|
|A DOM div container used as a color pallet for quick access.
|cursor Hide
|<syntaxhighlight lang="javascript">
|updateCoordDisplay
//Randomize all color palette colors.
|
const colorButtons = colorShortcuts.querySelectorAll('.color_btn');
|
  colorButtons.forEach(button => {
|<syntaxhighlight lang="javascript" line="1" start="281">
    if (button.title !== 'Random color') {
w.on("cursorHide", updateCoordDisplay);
    const randomColor = `#${Math.floor(Math.random()*16777215).toString(16).toUpperCase()}`;
      button.style.backgroundColor = randomColor;
      button.title = randomColor;
    }
  });
 
</syntaxhighlight>
|<syntaxhighlight lang="javascript" line="1" start="330">
for(var i = 0; i < colors.length; i++) {
var color = colors[i];
colorShortcuts.appendChild(createColorButton(color));
}
</syntaxhighlight>
</syntaxhighlight>
|-
|-
|enums
|
|An unused object created to store position and write edits.
|tiles Rendered
|<syntaxhighlight lang="javascript">
|self
//Use enums.position as a template for creating an updatedPosition object
|
const newCoord = [7, 5, 3, 1];
|
const updatedPosition = { ...enums.position };
|<syntaxhighlight lang="javascript" line="1" start="4747">
for (const key in updatedPosition) {
w.on("tilesRendered", function() {
  if (updatedPosition.hasOwnProperty(key)) {
for(var i = 0; i < regionSelections.length; i++) {
    const positionIndex = updatedPosition[key];
var reg = regionSelections[i];
    updatedPosition[key] = newCoord[positionIndex];
if(reg.regionCoordA && reg.regionCoordB) reg.setSelection(reg.regionCoordA, reg.regionCoordB);
  }
}
}
});
</syntaxhighlight>
</syntaxhighlight>
|<syntaxhighlight lang="javascript" line="1" start="54">
|-
enums.edit = makeEnum(["tileY", "tileX", "charY", "charX", "time", "char", "id", "color"]);
|
enums.position = makeEnum(["tileX", "tileY", "charX", "charY"]);
|cursor Move
|setClientGuestCursorPosition
|
|
|<syntaxhighlight lang="javascript" line="1" start="4754">
w.on("cursorMove", function(pos) {
setClientGuestCursorPosition(pos.tileX, pos.tileY, pos.charX, pos.charY);
});
</syntaxhighlight>
</syntaxhighlight>
|-
|-
|ws_path
|
|Stores the pages' websocket path.
|cursor Hide
|<syntaxhighlight lang="javascript">
|setClientGuestCursorPosition
//Change the socket, refreshing the client ID
|
w.changeSocket(ws_path, true);
|
|<syntaxhighlight lang="javascript" line="1" start="4758">
w.on("cursorHide", function() {
setClientGuestCursorPosition(0, 0, 0, 0, true);
});
</syntaxhighlight>
</syntaxhighlight>
|<syntaxhighlight lang="javascript" line="1" start="57">
|-
var ws_path = createWsPath();
|elm.textInput
 
|
* keydown
* input
|
* stabilizeTextInput
* event_input
|
|
|<syntaxhighlight lang="javascript" line="1" start="2618">
elm.textInput.addEventListener("keydown", stabilizeTextInput);
elm.textInput.addEventListener("input", event_input);
</syntaxhighlight>
</syntaxhighlight>
|-
|-
|menu,
|elm.owot
w.menu,
|context menu
Menu
|self
|An object containing all of the DOM elements and functions of the menu.
|
|<syntaxhighlight lang="javascript">
|
//Adds a button to the menu that alerts "Hello World" when clicked.
|<syntaxhighlight lang="javascript" line="1" start="5628">
menu.addOption("alert", function(){alert("Hello World")});
elm.owot.oncontextmenu = function() {
</syntaxhighlight>
if(ignoreCanvasContext) {
|<syntaxhighlight lang="javascript" line="1" start="4490">
ignoreCanvasContext = false;
menu = new Menu(elm.menu_elm, elm.nav_elm);
elm.owot.style.pointerEvents = "none";
w.menu = menu;
setTimeout(function() {
ignoreCanvasContext = true;
elm.owot.style.pointerEvents = "";
}, 1);
}
}
</syntaxhighlight>
</syntaxhighlight>
|-
|-
|menuStyle
|elm.coords
|A temporary style element created and used to style the menu.
|click
|<syntaxhighlight lang="javascript">
|self
//Generate a random set of colors for the menu each time the menu is hovered over.
|
elm.menu_elm.addEventListener("mouseover", function() {
|
  if (menuStyle) {
|<syntaxhighlight lang="javascript" line="1" start="283">
    document.head.removeChild(menuStyle)
elm.coords.onclick = function() {
  }
showCursorCoordinates = !showCursorCoordinates;
function makeRandom (){
if(showCursorCoordinates) {
    return Math.floor(Math.random() * 16777215).toString(16).toUpperCase();
elm.cursor_coords.style.display = "";
}
updateCoordDisplay();
  menuStyle = document.createElement("style");
} else {
  const randomColor = makeRandom();
elm.cursor_coords.style.display = "none";
  const randomColorBG = makeRandom();
updateCoordDisplay();
  const randomColorBorder = makeRandom();
}
 
}
  menuStyle.innerHTML = `
</syntaxhighlight>
#menu.hover,#nav {background: #${randomColorBG};border-color: #${randomColorBorder};color: #${randomColor};}
|}
#nav li {border-top-color: #${randomColorBorder};}
#nav li.hover {background-color: #${randomColorBG};}
#coords {background-color: #${randomColorBG};color: #${randomColor};}`
  document.head.appendChild(menuStyle);
})


===Functions:===
{| class="wikitable"
|+
!Name
!Description
!Example Usage
!Code In Use
|-
|init_dom()
|
|
|<syntaxhighlight lang="javascript" line="1" start="11">
function init_dom() {
owot = document.getElementById("owot");
owot.style.display = "block";
owot.style.cursor = defaultCursor;
owotCtx = owot.getContext("2d");
textInput = document.getElementById("textInput");
textInput.value = "";
linkElm = elm.link_element;
linkDiv = elm.link_div;
updateCoordDisplay();
initTextDecoBar();
defineElements({
owot: owot,
textInput: textInput
});
}
</syntaxhighlight>
</syntaxhighlight>
|<syntaxhighlight lang="javascript" line="1" start="1529">
|-
menuStyle.innerHTML = "#menu.hover, #nav {" +
|getWndWidth()
"background: " + color + ";" +
|
"border-color: " + bColor + ";" +
|
"color: " + tColor + ";" +
|<syntaxhighlight lang="javascript" line="1" start="27">
"}\n" +
function getWndWidth() {
"#nav li {" +
return document.body.clientWidth || window.innerWidth;
"border-top-color: " + bColor + ";" +
"}\n" +
"#nav li.hover {" +
"background-color: " + hColor + ";" +
"}\n" +
"#coords {" +
"background-color: " + bColor + ";" +
"color: " + tColor + ";" +
"}";
}
}
</syntaxhighlight>
</syntaxhighlight>
|-
|-
|styles
|getWndHeight()
|An object which controls the colors used within a world.
|
|<syntaxhighlight lang="javascript">
|
//Sets the public tile color to red.
|
styles.public = "red";
renderTiles(true);
</syntaxhighlight>
|<syntaxhighlight lang="javascript" line="1" start="60">
var styles = defaultStyles();
</syntaxhighlight>
|-
|-
|nextObjId
|decimal(percentage)
|An integer used to track edits.
|
|<syntaxhighlight lang="javascript">
|
//Writes the character "█" at the cursorCoords location, then updates the nextObjId id
|
const [tileX, tileY, charX, charY] = cursorCoords;
console.log(currentPosition)
const editArray = [tileY, tileX, charY, charX, getDate(),"█", nextObjId]
writeBuffer.push(editArray);
nextObjId++;
</syntaxhighlight>
|<syntaxhighlight lang="javascript" line="1" start="61">
var nextObjId = 1;
</syntaxhighlight>
|-
|-
|owotWidth,
|normFontSize(size)
owotHeight
|
|The current width and height of the DOM window.
|
|<syntaxhighlight lang="javascript">
|
//Estimate the total number of fully visible cells that could exist on the screen
|-
const cellAmount = Math.floor(owotHeight/cellH * owotWidth/cellW);
|deviceRatio()
</syntaxhighlight>
|
|<syntaxhighlight lang="javascript" line="1" start="1170">
|
owotWidth = Math.round(window_width * ratio);
|
owotHeight = Math.round(window_height * ratio);
</syntaxhighlight>
|-
|-
|js_alert_active
|makeEnum(vars)
|A bool stating if the javascript alert window is open.
|
|
|
|
|<syntaxhighlight lang="javascript" line="1" start="64">
var js_alert_active = false;
</syntaxhighlight>
|-
|-
|worldFocused
|setRGBColorPicker(r, g, b)
|A bool stating if the owot canvas is in focus.
|
|<syntaxhighlight lang="javascript">
|
//check every 100ms if the owot canvas was last clicked, if it was then randomly change the public tile color.
|
setInterval(function() {
|-
  if (worldFocused) {
|setRGBBgColorPicker(r, g, b)
    styles.public = "#" + Math.floor(Math.random() * 16777215).toString(16).toUpperCase();
|
    w.redraw()
|
  }
|
}, 100)
 
</syntaxhighlight>
|<syntaxhighlight lang="javascript" line="1" start="1737">
if(closest(target, getChatfield()) || target == elm.chatbar || target == elm.confirm_js_code) {
worldFocused = false;
} else {
worldFocused = true;
}
</syntaxhighlight>
|-
|-
|chatResizing
|setColorPickerRandom()
|A bool stating if the chat window is being resized.
|
|<syntaxhighlight lang="javascript">
|
//check every 100ms if the chat is resizing, if it is, change the public tile color
|
setInterval(function() {
|-
  if (chatResizing) {
|updateColorPicker()
    styles.public = "#" + Math.floor(Math.random() * 16777215).toString(16).toUpperCase();
|
    w.redraw()
|
  }
|
}, 100)
 
</syntaxhighlight>
|<syntaxhighlight lang="javascript" line="1" start="441">
draggable_element(elm.chat_window, null, [
elm.chatbar, elm.chatsend, elm.chat_close, elm.chat_page_tab, elm.chat_global_tab, elm.page_chatfield, elm.global_chatfield
], function() {
if(chatResizing) {
return -1;
}
});
</syntaxhighlight>
|-
|-
|tiles
|updateBgColorPicker()
|An object containing all the loaded tiles.
|
|<syntaxhighlight lang="javascript">
|
//Return any visible links
|
const [X,Y] = cursorCoords;
|-
tiles[`${X},${Y}`].properties.cell_props
|updateCoordDisplay()
</syntaxhighlight>
|
|<syntaxhighlight lang="javascript" line="1" start="1416">
|
Tile.set = function(tileX, tileY, data) {
|
var str = tileY + "," + tileX;
if(!(str in tiles)) {
w.tile.count++;
}
tiles[str] = data;
expandLocalBoundary(tileX, tileY);
return data;
}
</syntaxhighlight>
|-
|-
|images,
|createColorButton(color, isHighlight)
keysPressed,
|
imgPatterns
|
|Empty, unused objects.
|
|
|<syntaxhighlight lang="javascript" line="1" start="68">
var images = {};
var keysPressed = {};
</syntaxhighlight>
|-
|-
|previousErase
|addColorShortcuts()
|An integer of the last date the erase function was utilised.
|
|<syntaxhighlight lang="javascript">
|
//Logs the previous erase time in a human-readable way.
|
function readPreviousErase() {
|-
  if (previousErase == 0) {
|draggable_element(dragger, dragged, exclusions, onDrag)
    return
|
  }
|
  const date = new Date(previousErase);
|
  const options = {
|-
    year: 'numeric',
|resizeChat(width, height)
    month: 'long',
|
    day: 'numeric',
|
    hour: '2-digit',
|
    minute: '2-digit',
|-
    second: '2-digit',
|getStoredNickname()
    timeZoneName: 'short'
|
  };
|
  console.log("last Erased at:", date.toLocaleString(undefined, options));
|
}
|-
</syntaxhighlight>
|storeNickname()
|<syntaxhighlight lang="javascript" line="1" start="2608">
|
function event_input(e) {
|
if(e.inputType == "deleteContentBackward") {
|
if(getDate() - previousErase > 25 || !previousErase) {
moveCursor("left", true);
writeChar("\x08", true, null, false, 1);
}
previousErase = getDate();
}
}
</syntaxhighlight>
|-
|-
|verticalEnterPos
|getStoredConfig()
|A 2D array coordinate of the position to go when pressing enter.
|
|<syntaxhighlight lang="javascript">
|
//Stair-step the return position on "enter"
|
textInput.addEventListener("input", function(e) {
  if (e.inputType === "insertLineBreak") {
    const [X, x] = verticalEnterPos;
    verticalEnterPos = [X, (x + 1) % 16]
  }
})
</syntaxhighlight>
|<syntaxhighlight lang="javascript" line="1" start="2352">
if(noVertPos) {
coords.tileX = 0;
coords.charX = 0;
} else {
coords.tileX = verticalEnterPos[0];
coords.charX = verticalEnterPos[1];
}
</syntaxhighlight>
|-
|-
|textColorOverride
|storeConfig()
|public-member-owner bitfield used to modify the text color in fields.
|
|
|
|
|<syntaxhighlight lang="javascript" line="1" start="1477">
if(styles.public_text != "#000" && styles.public_text != "#000000") {
textColorOverride |= public;
} else {
textColorOverride &= textColorOverride ^ public;
}
</syntaxhighlight>
|-
|-
|writeBuffer
|loadBackgroundData(cb, timeout_cb)
|An object holding data waiting to be rendered to the canvas.
|
|<syntaxhighlight lang="javascript">
|
//Writes the character "█" at the cursorCoords location
|
const [tileX, tileY, charX, charY] = cursorCoords;
|-
const editArray = [tileY, tileX, charY, charX, getDate(), "█", nextObjId++]
|keydown_regionSelect(e)
writeBuffer.push(editArray);
|
</syntaxhighlight>
|
|<syntaxhighlight lang="javascript" line="1" start="2179">
|
tellEdit.push(editArray); // track local changes
|-
writeBuffer.push(editArray); // send edits to server
|handleRegionSelection(coordA, coordB, regWidth, regHeight)  
nextObjId++;
|
</syntaxhighlight>
|
|
|-
|-
|highlightFlash
|buildFontTemplate(set)
|An object containing cell coordinates of cells to be highlighted.
|
|<syntaxhighlight lang="javascript">
|
//Flashes a random color on all visible cells
|
function flashRandom() {
  const visibleTiles = getVisibleTiles();
  const color = [Math.floor(Math.random() * 256), Math.floor(Math.random() * 256), Math.floor(Math.random() * 256)];
  const positions = [];
 
  // Generate the positions array
  for (const [tileX, tileY] of visibleTiles) {
    for (let charY = 0; charY < 8; charY++) {
      for (let charX = 0; charX < 16; charX++) {
        positions.push([tileX, tileY, charX, charY]);
      }
    }
  }
 
  // Update highlightFlash based on positions
  for (const [tileX, tileY, charX, charY] of positions) {
    const tileKey = `${tileY},${tileX}`;
    highlightFlash[tileKey] ??= {};
    highlightFlash[tileKey][charY] ??= {};
 
    if (!highlightFlash[tileKey][charY][charX]) {
      highlightFlash[tileKey][charY][charX] = [getDate(), color, [...color]];
      highlightCount++;
    }
  }
}
</syntaxhighlight>
|<syntaxhighlight lang="javascript" line="1" start="3988">
if(!highlightFlash[tileY + "," + tileX]) {
highlightFlash[tileY + "," + tileX] = {};
}
</syntaxhighlight>
|-
|-
|highlightCount
|rebuildFontTemplates()
|An iterator used to limit the amount of highlights rendered to the canvas.
|
|<syntaxhighlight lang="javascript">
//Prevents the user from seeing highlights
highlightCount = Infinity;
</syntaxhighlight>
|<syntaxhighlight lang="javascript" line="1" start="3987">
if(highlightCount > highlightLimit && !unlimited) return;
</syntaxhighlight>
|-
|coloredChars
|An object holding all of the highlighted characters.
|
|
|<syntaxhighlight lang="javascript" line="1" start="4071">
var container = coloredChars[tileY + "," + tileX];
if(!container) {
container = {};
coloredChars[tileY + "," + tileX] = container;
}
</syntaxhighlight>
|-
|shiftOptState
|An object used to store the viewport values
|
|
|<syntaxhighlight lang="javascript" line="1" start="79">
var shiftOptState = { prevX: 0, prevY: 0, x1: 0, y1: 0, x2: 0, y2: 0, prevZoom: -1 };
</syntaxhighlight>
|-
|-
|backgroundImage
|updateScaleConsts()
|
|
|
|
|
|
|-
|-
|backgroundPattern
|setupTextRenderCtx()
|
|
|
|
|-
|reloadRenderer()
|
|
|
|
|
|
|-
|-
|backgroundPatternSize
|updateRendererZoom(percentage)
|
|
|
|
|
|
|-
|-
|guestCursorsByTile
|zoomGarbageCollect()
|
|
|
|
|
|
|
|-
|-
|guestCursors
|changeZoom(percentage, isPartial)
|
|
|
|
|
|
|-
|-
|clientGuestCursorPos
|setZoombarValue()
|
|
|
|
|
|
|
|-
|-
|disconnectTimeout
|fromLogZoom(val)
|
|
|
|
|
|
|-
|-
|menuOptions
|toLogZoom(val)
|
|
|
|
|
|
|
|-
|-
|undoBuffer
|browserZoomAdjust(initial)
|
|
|
|
|
|
|-
|-
|textDecorationOffset
|updateAutoProg()
|
|
|
|
|
|
|
|-
|-
|textDecorationModes
|mousemove_tileProtectAuto()
|
|
|
|
|
|
|-
|-
|fontTemplate
|keydown_tileProtectAuto(e)
|
|
|
|
|
|
|
|-
|-
|specialFontTemplate
|mousemove_linkAuto()
|
|
|
|
|
|
|-
|-
|fontOrder
|keydown_linkAuto(e)
|
|
|
|
|
|
|
|-
|-
|specialFontOrder
|onKeyUp(e)
|
|
|
|
|
|
|-
|-
|initiallyFetched
|adjust_scaling_DOM(ratio)
|
|
|
|
|
|
|
|-
|-
|lastLinkHover
|event_resize()
|
|
|
|
|
|
|-
|-
|lastTileHover
|getChar(tileX, tileY, charX, charY)
|
|
|
|
|
|
|
|-
|-
|regionSelections
|getCharColor(tileX, tileY, charX, charY)
|
|
|
|
|
|
|-
|-
|specialClientHooks
|getCharBgColor(tileX, tileY, charX, charY)
|
|
|
|
|-
|getCharProtection(tileX, tileY, charX, charY)
|
|
|
|
|
|
|-
|-
|specialClientHookMap
|getCharDecoration(tileX, tileY, charX, charY)
|
|
|
|
|
|
|-
|-
|bgImageHasChanged
|getCharInfo(tileX, tileY, charX, charY)
|
|
|
|
|
|
|
|-
|-
|remoteBoundary
|getCharInfoXY(x, y)
|
|
|
|
|
|
|-
|-
|boundaryStatus
|getLink(tileX, tileY, charX, charY)
|
|
|
|
|
|
|
|-
|-
|positionX
|getLinkXY(x, y)
|
|
|
|
|
|
|-
|-
|positionY
|event_keydown_copy_char(e)
|
|
|
|
|
|
|
|-
|-
|coordSizeX
|event_keydown_copy_color(e)
|
|
|
|
|
|
|-
|-
|coordSizeY
|resolveColorValue(val)
|
|
|
|
|
|
|
|-
|-
|gridEnabled
|isTileStale(tileX, tileY)
|
|
|
|
|
|
|-
|-
|subgridEnabled
|checkTextColorOverride()
|
|
|
|
|
|
|
|-
|-
|linksEnabled
|menu_color(color)
|
|
|
|
|
|
|-
|-
|linksRendered
|defaultStyles()
|
|
|
|
|
|
|
|-
|-
|colorsEnabled
|manageCoordHash()
|
|
|
|
|
|
|-
|-
|backgroundEnabled
|getWorldProps(world, type, cb)
|
|
|
|
|
|
|
|-
|-
|scrollingEnabled
|stopLinkUI()
|
|
|
|
|
|
|-
|-
|zoomRatio
|removeTileProtectHighlight()
|
|
|
|
|
|
|-
|-
|protectPrecision
|stopTileUI()
|
|
|
|
|
|
|-
|-
|checkTileFetchInterval
|doLink()
|
|
|
|
|
|
|
|-
|-
|zoom
|doProtect()
|
|
|
|
|
|
|-
|-
|userZoom
|triggerUIClick()
|
|
|
|
|
|
|-
|-
|unloadTilesAuto
|event_mousedown(e, arg_pageX, arg_pageY)
|
|
|
|
|
|
|
|-
|-
|useHighlight
|renderCursor(coords)
|
|
|
|
|
|
|-
|-
|highlightLimit
|removeCursor()
|
|
|
|
|
|
|-
|-
|ansiBlockFill
|stopDragging()
|
|
|
|
|
|
|
|-
|-
|colorizeLinks
|event_mouseup(e, arg_pageX, arg_pageY)
|
|
|
|
|
|
|-
|-
|brBlockFill
|event_mouseleave(e)
|
|
|
|
|
|
|-
|-
|tileFetchOffsetX
|event_mouseenter(e)
|
|
|
|
|
|
|
|-
|-
|tileFetchOffsetY
|is_link(tileX, tileY, charX, charY)
|
|
|
|
|
|
|-
|-
|ignoreCanvasContext
|flushWrites()
|
|
|
|
|
|
|-
|-
|elementSnapApprox
|setWriteInterval()
|
|
|
|
|
|
|
|-
|-
|mSpecRendering
|moveCursor(direction, preserveVertPos, amount)
|
|
|
|
|
|
|-
|-
|combiningCharsEnabled
|markCharacterAsUndoable(tileX, tileY, charX, charY)
|
|
|
|
|
|
|-
|-
|surrogateCharsEnabled
|isCharLatestInUndoBuffer(tileX, tileY, charX, charY)
|
|
|
|
|
|
|
|-
|-
|defaultCoordLinkColor
|writeCharTo(char, charColor, tileX, tileY, charX, charY, undoFlags, undoOffset, charBgColor, dB, dI, dU, dS)
|
|
|
|
|
|
|-
|-
|defaultURLLinkColor
|undoWrite()
|
|
|
|
|
|
|-
|-
|defaultHighlightColor
|redoWrite()
|
|
|
|
|
|
|
|-
|-
|secureJSLink
|writeCharToXY(char, charColor, x, y, charBgColor, dB, dI, dU, dS)
|
|
|
|
|
|
|-
|-
|secureLink
|writeChar(char, doNotMoveCursor, color, noNewline, undoCursorOffset, bgColor, dB, dI, dU, dS)
|
|
|
|
|
|
|-
|-
|pasteDirRight
|coordinateAdd(tileX1, tileY1, charX1, charY1, tileX2, tileY2, charX2, charY2)
|
|
|
|
|
|
|
|-
|-
|pasteDirDown
|propagatePosition(coords, char, noEnter, noVertPos)
|
|
|
|
|
|
|-
|-
|defaultCursor
|textcode_parser(value, coords, defaultColor, defaultBgColor)
|
|
|
|
|
|
|-
|-
|defaultDragCursor
|stabilizeTextInput()
|
|
|
|
|
|
|
|-
|-
|fetchClientMargin
|event_input(e)
|
|
|
|
|
|
|-
|-
|classicTileProcessing
|stopPasting()
|
|
|
|
|
|
|-
|-
|unloadedPatternPanning
|autoArrowKeyMoveStart(dir)
|
|
|
|
|
|
|
|-
|-
|cursorRenderingEnabled
|autoArrowKeyMoveStop(dir)
|
|
|
|
|
|
|-
|-
|guestCursorsEnabled
|event_keydown(e)
|
|
|
|
|
|
|-
|-
|showMyGuestCursor
|event_keyup(e)
|
|
|
|
|
|
|
|-
|-
|unobstructCursor
|isMainPage()
|
|
|
|
|
|
|-
|-
|shiftOptimization
|alertJS(data, restrict)
|
|
|
|
|
|
|-
|-
|transparentBackground
|closeJSAlert()
|
|
|
|
|
|
|
|-
|-
|writeFlushRate
|executeJS(code)
|
|
|
|
|
|
|-
|-
|bufferLargeChars
|confirmRunJSLink(data)
|
|
|
|
|
|
|-
|-
|cursorOutlineEnabled
|runJSLink(data, restrict)
|
|
|
|
|
|
|-
|-
|showCursorCoordinates
|coord_link_click(evt)
|
|
|
|
|
|
|-
|-
|textDecorationsEnabled
|url_link_click(evt)
|
|
|
|
|
|
|-
|-
|keyConfig
|updateHoveredLink(mouseX, mouseY, evt, safe)
|
|
|
|
|
|
|-
|-
|draggable_element_mousemove
|event_mousemove(e, arg_pageX, arg_pageY)
|
|
|
|
|
|
|-
|-
|draggable_element_mouseup
|getCenterTouchPosition(touches)
|
|
|
|
|
|
|
|-
|-
|defaultSizes
|event_touchstart(e)
|
|
|
|
|
|
|
|-
|-
|cellWidthPad
|event_touchend(e)
|
|
|
|
|
|
|
|-
|-
|tileW
|event_touchmove(e)
|
|
|
|
|-
|touch_pagePos(e)
|
|
|
|
|
|
|-
|-
|tileH
|event_wheel(e)
|
|
|
|
|
|
|
|-
|-
|cellW
|event_wheel_zoom(e)
|
|
|
|
|
|
|
|-
|-
|cellH
|convertKeyCode(key)
|
|
|
|
|
|
|
|-
|-
|font
|checkKeyPress(e, combination)
|
|
|
|
|
|
|
|-
|-
|specialCharFont
|checkKeyPatterns(combination)
|
|
|
|
|
|
|
|-
|-
|tileC
|createWsPath()
|
|
|
|
|
|
|
|-
|-
|tileR
|createSocket(getChatHist)
|
|
|
|
|
|
|
|-
|-
|tileArea
|cullRanges(map, width, height)
|
|
|
|
|
|
|
|-
|-
|tileWidth
|updateRemoteBoundary()
|
|
|
|
|
|
|
|-
|-
|tileHeight
|clearRemoteBoundary()
|
|
|
|
|
|
|
|-
|-
|dTileW
|expandLocalBoundary(x, y)
|
|
|
|
|
|
|
|-
|-
|dTileH
|getAndFetchTiles()
|
|
|
|
|
|
|
|-
|-
|textRenderCanvas
|clearTiles(all)
|
|
|
|
|
|
|
|-
|-
|textRenderCtx
|clearVisibleTiles()
|
|
|
|
|
|
|
|-
|-
|tileProtectAuto
|highlight(positions, unlimited, color)
|
|
|
|
|
|
|
|-
|-
|linkAuto
|blankTile()
|
|
|
|
|
|
|
|-
|-
|autoTotal
|colorChar(tileX, tileY, charX, charY, colorClass)
|
|
|
|
|
|
|
|-
|-
|cursorCoords
|uncolorChar(tileX, tileY, charX, charY, colorClass)
|
|
|
|
|
|
|
|-
|-
|cursorCoordsCurrent
|decodeCharProt(str)
|
|
|
|
|
|
|
|-
|-
|currentPosition
|encodeCharProt(array, encoding)
|
|
|
|
|
|
|
|-
|-
|currentPositionInitted
|getCharTextDecorations(char)
|
|
|
|
|
|
|
|-
|-
|currentMousePosition
|setCharTextDecorations(char, bold, italic, under, strike)
|
|
|
|
|
|
|
|-
|-
|Tile
|resolveCharEmojiCombinations(char)
|
|
|
|
|
|
|
|-
|-
|poolCleanupInterval
|detectCharEmojiCombinations(char)
|
|
|
|
|
|
|
|-
|-
|dragStartX
|clearCharTextDecorations(char)
|
|
|
|
|
|
|
|-
|-
|dragStartY
|clearAllGuestCursors()
|
|
|
|
|
|
|
|-
|-
|dragPosX
|renderLoop()
|
|
|
|
|
|
|
|-
|-
|dragPosY
|protectPrecisionOption(option)
|
|
|
|
|-
|toggleTextDecoBar()
|
|
|
|
|
|
|-
|-
|isDragging
|initTextDecoBar()
|
|
|
|
|
|
|
|-
|-
|hasDragged
|protectSelectionStart(start, end, width, height)
|
|
|
|
|
|
|
|-
|-
|draggingEnabled
|protectSelectionCancel()
|
|
|
|
|
|
|
|-
|-
|cursorEnabled
|protectSelection()
|
|
|
|
|
|
|
|-
|-
|writeInterval
|buildMenu()
|
|
|
|
|
|
|
|-
|-
|write_busy
|updateMenuEntryVisiblity()
|
|
|
|
|
|
|
|-
|-
|pasteInterval
|regionSelectionsActive()
|
|
|
|
|
|
|
|-
|-
|linkQueue
|RegionSelection()
|
|
|
|
|
|
|
|-
|-
|autoArrowKeyMoveInterval
|setClientGuestCursorPosition(tileX, tileY, charX, charY, hidden)
|
|
|
|
|
|
|
|-
|-
|autoArrowKeyMoveActive
|sendCursorPosition()
|
|
|
|
|
|
|
|-
|-
|autoArrowKeyMoveState
|disableBgColorPicker()
|
|
|
|
|
|
|
|-
|-
|linkParams
|enableBgColorPicker()
|
|
|
|
|
|
|
|-
|-
|currentSelectedLink
|makeCoordLinkModal()
|
|
|
|
|
|
|
|-
|-
|currentSelectedLinkCoords
|makeCoordGotoModal()
|
|
|
|
|
|
|
|-
|-
|touchInitZoom
|makeURLModal()
|
|
|
|
|
|
|
|-
|-
|touchInitDistance
|buildBackgroundColorModal(modal)
|
|
|
|
|
|
|
|-
|-
|touchPrev
|resetColorModalVisibility()
|
|
|
|
|
|
|
|-
|-
|fetchInterval
|makeColorModal()
|
|
|
|
|
|
|
|-
|-
|timesConnected
|makeSelectionModal()
|
|
|
|
|
|
|
|-
|-
|colorClasses
|searchTellEdit(tileX, tileY, charX, charY)
|
|
|
|
|
|
|
|-
|-
|isTileLoaded
|tile_offset_object(data, tileOffX, tileOffY)
|
|
|
|
|
|
|
|-
|-
|isTileVisible
|begin()
|
|
|
|
|
|
|
|}
===Variables:===
{| class="wikitable mw-collapsible"
|+
!Name
!Description
!Example Usage
!Code In Use
|-
|-
|networkHTTP
|YourWorld
|
|An object containing the users current text color, cell background color, and chat nick name.
|
|<syntaxhighlight lang="javascript">
|
//Sets the users color to a random one.
|
YourWorld.Color = Math.round((Math.random()*16777215));
</syntaxhighlight>
|<syntaxhighlight lang="javascript" line="1">
var YourWorld = {
Color: window.localStorage ? +localStorage.getItem("color") : 0,
BgColor: -1,
Nickname: state.userModel.username
};
</syntaxhighlight>
|-
|-
|network
|owot
|
|The DOM canvas element
|
|<syntaxhighlight lang="javascript">
|
//Hides the owot canvas.
|
owot.style.opacity = 0;
</syntaxhighlight>
|<syntaxhighlight lang="javascript" line="1" start="12">
owot = document.getElementById("owot");
</syntaxhighlight>
|-
|-
|w
|owotCtx
|
|The CanvasRenderingContext2D of the owot canvas
|
|<syntaxhighlight lang="javascript">
|
//Clears all the rendered tiles from the view.
|
owotCtx.clearRect(0, 0, owotWidth, owotHeight);
</syntaxhighlight>
|<syntaxhighlight lang="javascript" line="1" start="15">
owotCtx = owot.getContext("2d");
</syntaxhighlight>
|-
|-
|tellEdit
|textInput
|
|The DOM textarea element used for writing to the owot canvas.
|
|<syntaxhighlight lang="javascript">
|
//Paste "hello world" at the current cursor position.
|
textInput.value = `hello world`;
</syntaxhighlight>
|<syntaxhighlight lang="javascript" line="1" start="16">
textInput = document.getElementById("textInput");
</syntaxhighlight>
|-
|-
|ws_functions
|linkElm
|
|The DOM link element used for user link clicks.
|
|<syntaxhighlight lang="javascript">
|
//logs to the console whether or not the link is a javascript link.
linkElm.addEventListener(`click`,function(){
console.log(linkParams.protocol === `javascript`);                 
})
</syntaxhighlight>
|<syntaxhighlight lang="javascript" line="1" start="18">
linkElm = elm.link_element;
</syntaxhighlight>
|-
|link_div
|The DOM link div element used to scale the linkElm to the same size as a cell within the owot canvas.
|<syntaxhighlight lang="javascript">
//Highlights the URL being hovered over.
linkDiv.style.background = `rgba(255,255,0,0.5)`
</syntaxhighlight>
|<syntaxhighlight lang="javascript" line="1" start="19">
linkDiv = elm.link_div;
</syntaxhighlight>
|-
|colorInput, colorInputBg
|The DOM color inputs to select text and cell background color.
|<syntaxhighlight lang="javascript">
//Generate a random color on the text color input field.
const randomColor = Math.floor(Math.random()*16777215).toString(16).toUpperCase();
colorInput.jscolor.fromString(`#${randomColor}`);
</syntaxhighlight>
|<syntaxhighlight lang="javascript" line="1" start="5718">
colorInputBg = modal.addEntry("Cell color", "color").input;
</syntaxhighlight><syntaxhighlight lang="javascript" line="1" start="5766">
colorInput = modal.addEntry("Text color", "color").input;
</syntaxhighlight>
|-
|colorShortcuts, colorShortcutsBg
|A DOM div container used as a color pallet for quick access.
|<syntaxhighlight lang="javascript">
//Randomize all color palette colors.
const colorButtons = colorShortcuts.querySelectorAll('.color_btn');
  colorButtons.forEach(button => {
    if (button.title !== 'Random color') {
    const randomColor = `#${Math.floor(Math.random()*16777215).toString(16).toUpperCase()}`;
      button.style.backgroundColor = randomColor;
      button.title = randomColor;
    }
  });
 
</syntaxhighlight>
|<syntaxhighlight lang="javascript" line="1" start="330">
for(var i = 0; i < colors.length; i++) {
var color = colors[i];
colorShortcuts.appendChild(createColorButton(color));
}
</syntaxhighlight>
|-
|enums
|An unused object created to store position and write edits.
|<syntaxhighlight lang="javascript">
//Use enums.position as a template for creating an updatedPosition object
const newCoord = [7, 5, 3, 1];
const updatedPosition = { ...enums.position };
for (const key in updatedPosition) {
  if (updatedPosition.hasOwnProperty(key)) {
    const positionIndex = updatedPosition[key];
    updatedPosition[key] = newCoord[positionIndex];
  }
}
</syntaxhighlight>
|<syntaxhighlight lang="javascript" line="1" start="54">
enums.edit = makeEnum(["tileY", "tileX", "charY", "charX", "time", "char", "id", "color"]);
enums.position = makeEnum(["tileX", "tileY", "charX", "charY"]);
</syntaxhighlight>
|-
|ws_path
|Stores the pages' websocket path.
|<syntaxhighlight lang="javascript">
//Change the socket, refreshing the client ID
w.changeSocket(ws_path, true);
</syntaxhighlight>
|<syntaxhighlight lang="javascript" line="1" start="57">
var ws_path = createWsPath();
 
</syntaxhighlight>
|-
|menu,
w.menu,
Menu
|An object containing all of the DOM elements and functions of the menu.
|<syntaxhighlight lang="javascript">
//Adds a button to the menu that alerts "Hello World" when clicked.
menu.addOption("alert", function(){alert("Hello World")});
</syntaxhighlight>
|<syntaxhighlight lang="javascript" line="1" start="4490">
menu = new Menu(elm.menu_elm, elm.nav_elm);
w.menu = menu;
</syntaxhighlight>
|-
|menuStyle
|A temporary style element created and used to style the menu.
|<syntaxhighlight lang="javascript">
//Generate a random set of colors for the menu each time the menu is hovered over.
elm.menu_elm.addEventListener("mouseover", function() {
  if (menuStyle) {
    document.head.removeChild(menuStyle)
  }
function makeRandom (){
    return Math.floor(Math.random() * 16777215).toString(16).toUpperCase();
}
  menuStyle = document.createElement("style");
  const randomColor = makeRandom();
  const randomColorBG = makeRandom();
  const randomColorBorder = makeRandom();
 
  menuStyle.innerHTML = `
#menu.hover,#nav {background: #${randomColorBG};border-color: #${randomColorBorder};color: #${randomColor};}
#nav li {border-top-color: #${randomColorBorder};}
#nav li.hover {background-color: #${randomColorBG};}
#coords {background-color: #${randomColorBG};color: #${randomColor};}`
  document.head.appendChild(menuStyle);
})
 
</syntaxhighlight>
|<syntaxhighlight lang="javascript" line="1" start="1529">
menuStyle.innerHTML = "#menu.hover, #nav {" +
"background: " + color + ";" +
"border-color: " + bColor + ";" +
"color: " + tColor + ";" +
"}\n" +
"#nav li {" +
"border-top-color: " + bColor + ";" +
"}\n" +
"#nav li.hover {" +
"background-color: " + hColor + ";" +
"}\n" +
"#coords {" +
"background-color: " + bColor + ";" +
"color: " + tColor + ";" +
"}";
}
</syntaxhighlight>
|-
|styles
|An object which controls the colors used within a world.
|<syntaxhighlight lang="javascript">
//Sets the public tile color to red.
styles.public = "red";
renderTiles(true);
</syntaxhighlight>
|<syntaxhighlight lang="javascript" line="1" start="60">
var styles = defaultStyles();
</syntaxhighlight>
|-
|nextObjId
|An integer used to track edits.
|<syntaxhighlight lang="javascript">
//Writes the character "█" at the cursorCoords location, then updates the nextObjId id
const [tileX, tileY, charX, charY] = cursorCoords;
console.log(currentPosition)
const editArray = [tileY, tileX, charY, charX, getDate(),"█", nextObjId]
writeBuffer.push(editArray);
nextObjId++;
</syntaxhighlight>
|<syntaxhighlight lang="javascript" line="1" start="61">
var nextObjId = 1;
</syntaxhighlight>
|-
|owotWidth,
owotHeight
|The current width and height of the DOM window.
|<syntaxhighlight lang="javascript">
//Estimate the total number of fully visible cells that could exist on the screen
const cellAmount = Math.floor(owotHeight/cellH * owotWidth/cellW);
</syntaxhighlight>
|<syntaxhighlight lang="javascript" line="1" start="1170">
owotWidth = Math.round(window_width * ratio);
owotHeight = Math.round(window_height * ratio);
</syntaxhighlight>
|-
|js_alert_active
|A bool stating if the javascript alert window is open.
|
|
|<syntaxhighlight lang="javascript" line="1" start="64">
var js_alert_active = false;
</syntaxhighlight>
|-
|worldFocused
|A bool stating if the owot canvas is in focus.
|<syntaxhighlight lang="javascript">
//check every 100ms if the owot canvas was last clicked, if it was then randomly change the public tile color.
setInterval(function() {
  if (worldFocused) {
    styles.public = "#" + Math.floor(Math.random() * 16777215).toString(16).toUpperCase();
    w.redraw()
  }
}, 100)
</syntaxhighlight>
|<syntaxhighlight lang="javascript" line="1" start="1737">
if(closest(target, getChatfield()) || target == elm.chatbar || target == elm.confirm_js_code) {
worldFocused = false;
} else {
worldFocused = true;
}
</syntaxhighlight>
|-
|chatResizing
|A bool stating if the chat window is being resized.
|<syntaxhighlight lang="javascript">
//check every 100ms if the chat is resizing, if it is, change the public tile color
setInterval(function() {
  if (chatResizing) {
    styles.public = "#" + Math.floor(Math.random() * 16777215).toString(16).toUpperCase();
    w.redraw()
  }
}, 100)
</syntaxhighlight>
|<syntaxhighlight lang="javascript" line="1" start="441">
draggable_element(elm.chat_window, null, [
elm.chatbar, elm.chatsend, elm.chat_close, elm.chat_page_tab, elm.chat_global_tab, elm.page_chatfield, elm.global_chatfield
], function() {
if(chatResizing) {
return -1;
}
});
</syntaxhighlight>
|-
|tiles
|An object containing all the loaded tiles.
|<syntaxhighlight lang="javascript">
//Return any visible links
const [X,Y] = cursorCoords;
tiles[`${X},${Y}`].properties.cell_props
</syntaxhighlight>
|<syntaxhighlight lang="javascript" line="1" start="1416">
Tile.set = function(tileX, tileY, data) {
var str = tileY + "," + tileX;
if(!(str in tiles)) {
w.tile.count++;
}
tiles[str] = data;
expandLocalBoundary(tileX, tileY);
return data;
}
</syntaxhighlight>
|-
|images,
keysPressed,
imgPatterns
|Empty, unused objects.
|
|<syntaxhighlight lang="javascript" line="1" start="68">
var images = {};
var keysPressed = {};
</syntaxhighlight>
|-
|previousErase
|An integer of the last date the erase function was utilised.
|<syntaxhighlight lang="javascript">
//Logs the previous erase time in a human-readable way.
function readPreviousErase() {
  if (previousErase == 0) {
    return
  }
  const date = new Date(previousErase);
  const options = {
    year: 'numeric',
    month: 'long',
    day: 'numeric',
    hour: '2-digit',
    minute: '2-digit',
    second: '2-digit',
    timeZoneName: 'short'
  };
  console.log("last Erased at:", date.toLocaleString(undefined, options));
}
</syntaxhighlight>
|<syntaxhighlight lang="javascript" line="1" start="2608">
function event_input(e) {
if(e.inputType == "deleteContentBackward") {
if(getDate() - previousErase > 25 || !previousErase) {
moveCursor("left", true);
writeChar("\x08", true, null, false, 1);
}
previousErase = getDate();
}
}
</syntaxhighlight>
|-
|verticalEnterPos
|A 2D array coordinate of the position to go when pressing enter.
|<syntaxhighlight lang="javascript">
//Stair-step the return position on "enter"
textInput.addEventListener("input", function(e) {
  if (e.inputType === "insertLineBreak") {
    const [X, x] = verticalEnterPos;
    verticalEnterPos = [X, (x + 1) % 16]
  }
})
</syntaxhighlight>
|<syntaxhighlight lang="javascript" line="1" start="2352">
if(noVertPos) {
coords.tileX = 0;
coords.charX = 0;
} else {
coords.tileX = verticalEnterPos[0];
coords.charX = verticalEnterPos[1];
}
</syntaxhighlight>
|-
|textColorOverride
|public-member-owner bitfield used to modify the text color in fields.
|
|<syntaxhighlight lang="javascript" line="1" start="1477">
if(styles.public_text != "#000" && styles.public_text != "#000000") {
textColorOverride |= public;
} else {
textColorOverride &= textColorOverride ^ public;
}
</syntaxhighlight>
|-
|writeBuffer
|An object holding data waiting to be rendered to the canvas.
|<syntaxhighlight lang="javascript">
//Writes the character "█" at the cursorCoords location
const [tileX, tileY, charX, charY] = cursorCoords;
const editArray = [tileY, tileX, charY, charX, getDate(), "█", nextObjId++]
writeBuffer.push(editArray);
</syntaxhighlight>
|<syntaxhighlight lang="javascript" line="1" start="2179">
tellEdit.push(editArray); // track local changes
writeBuffer.push(editArray); // send edits to server
nextObjId++;
</syntaxhighlight>
|-
|highlightFlash
|An object containing cell coordinates of cells to be highlighted.
|<syntaxhighlight lang="javascript">
//Flashes a random color on all visible cells
function flashRandom() {
  const visibleTiles = getVisibleTiles();
  const color = [Math.floor(Math.random() * 256), Math.floor(Math.random() * 256), Math.floor(Math.random() * 256)];
  const positions = [];
  // Generate the positions array
  for (const [tileX, tileY] of visibleTiles) {
    for (let charY = 0; charY < 8; charY++) {
      for (let charX = 0; charX < 16; charX++) {
        positions.push([tileX, tileY, charX, charY]);
      }
    }
  }
  // Update highlightFlash based on positions
  for (const [tileX, tileY, charX, charY] of positions) {
    const tileKey = `${tileY},${tileX}`;
    highlightFlash[tileKey] ??= {};
    highlightFlash[tileKey][charY] ??= {};
    if (!highlightFlash[tileKey][charY][charX]) {
      highlightFlash[tileKey][charY][charX] = [getDate(), color, [...color]];
      highlightCount++;
    }
  }
}
</syntaxhighlight>
|<syntaxhighlight lang="javascript" line="1" start="3988">
if(!highlightFlash[tileY + "," + tileX]) {
highlightFlash[tileY + "," + tileX] = {};
}
</syntaxhighlight>
|-
|highlightCount
|An iterator used to limit the amount of highlights rendered to the canvas.
|<syntaxhighlight lang="javascript">
//Prevents the user from seeing highlights
highlightCount = Infinity;
</syntaxhighlight>
|<syntaxhighlight lang="javascript" line="1" start="3987">
if(highlightCount > highlightLimit && !unlimited) return;
</syntaxhighlight>
|-
|coloredChars
|An object holding all of the highlighted characters.
|
|<syntaxhighlight lang="javascript" line="1" start="4071">
var container = coloredChars[tileY + "," + tileX];
if(!container) {
container = {};
coloredChars[tileY + "," + tileX] = container;
}
</syntaxhighlight>
|-
|shiftOptState
|An object used to store the viewport values
|
|<syntaxhighlight lang="javascript" line="1" start="79">
var shiftOptState = { prevX: 0, prevY: 0, x1: 0, y1: 0, x2: 0, y2: 0, prevZoom: -1 };
</syntaxhighlight>
|-
|backgroundImage
|
|
|
|-
|backgroundPattern
|
|
|
|
|-
|backgroundPatternSize
|
|
|
|-
|guestCursorsByTile
|
|
|
|
|-
|guestCursors
|
|
|
|-
|clientGuestCursorPos
|
|
|
|
|-
|disconnectTimeout
|
|
|
|-
|menuOptions
|
|
|
|
|-
|undoBuffer
|
|
|
|-
|textDecorationOffset
|
|
|
|
|-
|textDecorationModes
|
|
|
|-
|fontTemplate
|
|
|
|
|-
|specialFontTemplate
|
|
|
|-
|fontOrder
|
|
|
|
|-
|specialFontOrder
|
|
|
|-
|initiallyFetched
|
|
|
|
|-
|lastLinkHover
|
|
|
|-
|lastTileHover
|
|
|
|
|-
|regionSelections
|
|
|
|-
|specialClientHooks
|
|
|
|
|-
|specialClientHookMap
|
|
|
|-
|bgImageHasChanged
|
|
|
|
|-
|remoteBoundary
|
|
|
|-
|boundaryStatus
|
|
|
|
|-
|positionX
|
|
|
|-
|positionY
|
|
|
|
|-
|coordSizeX
|
|
|
|-
|coordSizeY
|
|
|
|
|-
|gridEnabled
|
|
|
|-
|subgridEnabled
|
|
|
|
|-
|linksEnabled
|
|
|
|-
|linksRendered
|
|
|
|
|-
|colorsEnabled
|
|
|
|-
|backgroundEnabled
|
|
|
|
|-
|scrollingEnabled
|
|
|
|-
|zoomRatio
|
|
|
|-
|protectPrecision
|
|
|
|-
|checkTileFetchInterval
|
|
|
|
|-
|zoom
|
|
|
|-
|userZoom
|
|
|
|-
|unloadTilesAuto
|
|
|
|
|-
|useHighlight
|
|
|
|-
|highlightLimit
|
|
|
|-
|ansiBlockFill
|
|
|
|
|-
|colorizeLinks
|
|
|
|-
|brBlockFill
|
|
|
|-
|tileFetchOffsetX
|
|
|
|
|-
|tileFetchOffsetY
|
|
|
|-
|ignoreCanvasContext
|
|
|
|-
|elementSnapApprox
|
|
|
|
|-
|mSpecRendering
|
|
|
|-
|combiningCharsEnabled
|
|
|
|-
|surrogateCharsEnabled
|
|
|
|
|-
|defaultCoordLinkColor
|
|
|
|-
|defaultURLLinkColor
|
|
|
|-
|defaultHighlightColor
|
|
|
|
|-
|secureJSLink
|
|
|
|-
|secureLink
|
|
|
|-
|pasteDirRight
|
|
|
|
|-
|pasteDirDown
|
|
|
|-
|defaultCursor
|
|
|
|-
|defaultDragCursor
|
|
|
|
|-
|fetchClientMargin
|
|
|
|-
|classicTileProcessing
|
|
|
|-
|unloadedPatternPanning
|
|
|
|
|-
|cursorRenderingEnabled
|
|
|
|-
|guestCursorsEnabled
|
|
|
|-
|showMyGuestCursor
|
|
|
|
|-
|unobstructCursor
|
|
|
|-
|shiftOptimization
|
|
|
|-
|transparentBackground
|
|
|
|
|-
|writeFlushRate
|
|
|
|-
|bufferLargeChars
|
|
|
|-
|cursorOutlineEnabled
|
|
|
|-
|showCursorCoordinates
|
|
|
|-
|textDecorationsEnabled
|
|
|
|-
|keyConfig
|
|
|
|-
|draggable_element_mousemove
|
|
|
|-
|draggable_element_mouseup
|
|
|
|
|-
|defaultSizes
|
|
|
|
|-
|cellWidthPad
|
|
|
|
|-
|tileW
|
|
|
|
|-
|tileH
|
|
|
|
|-
|cellW
|
|
|
|
|-
|cellH
|
|
|
|
|-
|font
|
|
|
|
|-
|specialCharFont
|
|
|
|
|-
|tileC
|
|
|
|
|-
|tileR
|
|
|
|
|-
|tileArea
|
|
|
|
|-
|tileWidth
|
|
|
|
|-
|tileHeight
|
|
|
|
|-
|dTileW
|
|
|
|
|-
|dTileH
|
|
|
|
|-
|textRenderCanvas
|
|
|
|
|-
|textRenderCtx
|
|
|
|
|-
|tileProtectAuto
|
|
|
|
|-
|linkAuto
|
|
|
|
|-
|autoTotal
|
|
|
|
|-
|cursorCoords
|
|
|
|
|-
|cursorCoordsCurrent
|
|
|
|
|-
|currentPosition
|
|
|
|
|-
|currentPositionInitted
|
|
|
|
|-
|currentMousePosition
|
|
|
|
|-
|Tile
|
|
|
|
|-
|poolCleanupInterval
|
|
|
|
|-
|dragStartX
|
|
|
|
|-
|dragStartY
|
|
|
|
|-
|dragPosX
|
|
|
|
|-
|dragPosY
|
|
|
|
|-
|isDragging
|
|
|
|
|-
|hasDragged
|
|
|
|
|-
|draggingEnabled
|
|
|
|
|-
|cursorEnabled
|
|
|
|
|-
|writeInterval
|
|
|
|
|-
|write_busy
|
|
|
|
|-
|pasteInterval
|
|
|
|
|-
|linkQueue
|
|
|
|
|-
|autoArrowKeyMoveInterval
|
|
|
|
|-
|autoArrowKeyMoveActive
|
|
|
|
|-
|autoArrowKeyMoveState
|
|
|
|
|-
|linkParams
|
|
|
|
|-
|currentSelectedLink
|
|
|
|
|-
|currentSelectedLinkCoords
|
|
|
|
|-
|touchInitZoom
|
|
|
|
|-
|touchInitDistance
|
|
|
|
|-
|touchPrev
|
|
|
|
|-
|fetchInterval
|
|
|
|
|-
|timesConnected
|
|
|
|
|-
|colorClasses
|
|
|
|
|-
|isTileLoaded
|
|
|
|
|-
|isTileVisible
|
|
|
|
|-
|networkHTTP
|
|
|
|
|-
|network
|
|
|
|
|-
|w
|
|
|
|
|-
|tellEdit
|
|
|
|
|-
|ws_functions
|
|
|
|
|}
== chat.js ==
=== Event listeners ===
{| class="wikitable"
!Object
!Listen Event
!Functions/Events Fired
!Emits
!Example Usage
!Related Code
|-
|elm.chatsend
|click
|sendChat()
|
|
|<syntaxhighlight lang="javascript" line="1" start="260">
elm.chatsend.addEventListener("click", function() {
sendChat();
});
</syntaxhighlight>
|-
|elm.chatbar
|keypress
|var keyCode = e.keyCode;
if(keyCode == 13) {
sendChat();
}
|
|
|<syntaxhighlight lang="javascript" line="1" start="264">
elm.chatbar.addEventListener("keypress", function(e) {
var keyCode = e.keyCode;
if(keyCode == 13) { // Enter
sendChat();
}
});
</syntaxhighlight>
|-
|elm.chatbar
|keydown
|var keyCode = e.keyCode;
// scroll through chat history that the client sent
if(keyCode == 38) { // up
// history modified
if(chatWriteHistoryIdx > -1 && elm.chatbar.value != chatWriteHistory[chatWriteHistory.length - chatWriteHistoryIdx - 1]) {
chatWriteHistory[chatWriteHistory.length - chatWriteHistoryIdx - 1] = elm.chatbar.value;
}
if(chatWriteHistoryIdx == -1 && elm.chatbar.value) {
chatWriteTmpBuffer = elm.chatbar.value;
}
chatWriteHistoryIdx++;
if(chatWriteHistoryIdx >= chatWriteHistory.length) chatWriteHistoryIdx = chatWriteHistory.length - 1;
var upVal = chatWriteHistory[chatWriteHistory.length - chatWriteHistoryIdx - 1];
if(!upVal) return;
elm.chatbar.value = upVal;
// pressing up will move the cursor all the way to the left by default
e.preventDefault();
moveCaretEnd(elm.chatbar);
} else if(keyCode == 40) { // down
// history modified
if(chatWriteHistoryIdx > -1 && elm.chatbar.value != chatWriteHistory[chatWriteHistory.length - chatWriteHistoryIdx - 1]) {
chatWriteHistory[chatWriteHistory.length - chatWriteHistoryIdx - 1] = elm.chatbar.value;
}
chatWriteHistoryIdx--;
if(chatWriteHistoryIdx < -1) {
chatWriteHistoryIdx = -1;
return;
}
var str = "";
if(chatWriteHistoryIdx != -1) {
str = chatWriteHistory[chatWriteHistory.length - chatWriteHistoryIdx - 1];
} else {
if(chatWriteTmpBuffer) {
str = chatWriteTmpBuffer;
e.preventDefault();
moveCaretEnd(elm.chatbar);
}
}
elm.chatbar.value = str;
e.preventDefault();
moveCaretEnd(elm.chatbar);
}
|
|
|<syntaxhighlight lang="javascript" line="1" start="283">
elm.chatbar.addEventListener("keydown", function(e) {
var keyCode = e.keyCode;
// scroll through chat history that the client sent
if(keyCode == 38) { // up
// history modified
if(chatWriteHistoryIdx > -1 && elm.chatbar.value != chatWriteHistory[chatWriteHistory.length - chatWriteHistoryIdx - 1]) {
chatWriteHistory[chatWriteHistory.length - chatWriteHistoryIdx - 1] = elm.chatbar.value;
}
if(chatWriteHistoryIdx == -1 && elm.chatbar.value) {
chatWriteTmpBuffer = elm.chatbar.value;
}
chatWriteHistoryIdx++;
if(chatWriteHistoryIdx >= chatWriteHistory.length) chatWriteHistoryIdx = chatWriteHistory.length - 1;
var upVal = chatWriteHistory[chatWriteHistory.length - chatWriteHistoryIdx - 1];
if(!upVal) return;
elm.chatbar.value = upVal;
// pressing up will move the cursor all the way to the left by default
e.preventDefault();
moveCaretEnd(elm.chatbar);
} else if(keyCode == 40) { // down
// history modified
if(chatWriteHistoryIdx > -1 && elm.chatbar.value != chatWriteHistory[chatWriteHistory.length - chatWriteHistoryIdx - 1]) {
chatWriteHistory[chatWriteHistory.length - chatWriteHistoryIdx - 1] = elm.chatbar.value;
}
chatWriteHistoryIdx--;
if(chatWriteHistoryIdx < -1) {
chatWriteHistoryIdx = -1;
return;
}
var str = "";
if(chatWriteHistoryIdx != -1) {
str = chatWriteHistory[chatWriteHistory.length - chatWriteHistoryIdx - 1];
} else {
if(chatWriteTmpBuffer) {
str = chatWriteTmpBuffer;
e.preventDefault();
moveCaretEnd(elm.chatbar);
}
}
elm.chatbar.value = str;
e.preventDefault();
moveCaretEnd(elm.chatbar);
}
});
</syntaxhighlight>
|-
|elm.chat_close
|click
|w.emit("chatClose");
elm.chat_window.style.display = "none";
elm.chat_open.style.display = "";
chatOpen = false;
|"chatClose"
|
|<syntaxhighlight lang="javascript" line="1" start="328">
elm.chat_close.addEventListener("click", function() {
w.emit("chatClose");
elm.chat_window.style.display = "none";
elm.chat_open.style.display = "";
chatOpen = false;
});
</syntaxhighlight>
|-
|elm.chat_open
|click
|elm.chat_window.style.display = "";
elm.chat_open.style.display = "none";
chatOpen = true;
if(selectedChatTab == 0) {
chatPageUnread = 0;
updateUnread();
if(!initPageTabOpen) {
initPageTabOpen = true;
elm.page_chatfield.scrollTop = elm.page_chatfield.scrollHeight;
}
} else {
chatGlobalUnread = 0;
updateUnread();
if(!initGlobalTabOpen) {
initGlobalTabOpen = true;
elm.global_chatfield.scrollTop = elm.global_chatfield.scrollHeight;
}
}
var chatWidth = chat_window.offsetWidth - 2;
var chatHeight = chat_window.offsetHeight - 2;
var screenRatio = window.devicePixelRatio;
if(!screenRatio) screenRatio = 1;
var virtWidth = owotWidth / screenRatio;
if(chatWidth > virtWidth) {
resizeChat(virtWidth - 2, chatHeight);
}
|"chatOpen"
|
|<syntaxhighlight lang="javascript" line="1" start="335">
elm.chat_open.addEventListener("click", function() {
w.emit("chatOpen");
elm.chat_window.style.display = "";
elm.chat_open.style.display = "none";
chatOpen = true;
if(selectedChatTab == 0) {
chatPageUnread = 0;
updateUnread();
if(!initPageTabOpen) {
initPageTabOpen = true;
elm.page_chatfield.scrollTop = elm.page_chatfield.scrollHeight;
}
} else {
chatGlobalUnread = 0;
updateUnread();
if(!initGlobalTabOpen) {
initGlobalTabOpen = true;
elm.global_chatfield.scrollTop = elm.global_chatfield.scrollHeight;
}
}
var chatWidth = chat_window.offsetWidth - 2;
var chatHeight = chat_window.offsetHeight - 2;
var screenRatio = window.devicePixelRatio;
if(!screenRatio) screenRatio = 1;
var virtWidth = owotWidth / screenRatio;
if(chatWidth > virtWidth) {
resizeChat(virtWidth - 2, chatHeight);
}
});
</syntaxhighlight>
|-
|elm.chat_page_tab
|click
|elm.chat_page_tab.classList.add("chat_tab_selected");
elm.chat_global_tab.classList.remove("chat_tab_selected");
elm.global_chatfield.style.display = "none";
elm.page_chatfield.style.display = "";
selectedChatTab = 0;
chatPageUnread = 0;
updateUnread();
if(!initPageTabOpen) {
initPageTabOpen = true;
elm.page_chatfield.scrollTop = elm.page_chatfield.scrollHeight;
}
|
|
|<syntaxhighlight lang="js" line="1" start="365">
elm.chat_page_tab.addEventListener("click", function() {
elm.chat_page_tab.classList.add("chat_tab_selected");
elm.chat_global_tab.classList.remove("chat_tab_selected");
elm.global_chatfield.style.display = "none";
elm.page_chatfield.style.display = "";
selectedChatTab = 0;
chatPageUnread = 0;
updateUnread();
if(!initPageTabOpen) {
initPageTabOpen = true;
elm.page_chatfield.scrollTop = elm.page_chatfield.scrollHeight;
}
});
</syntaxhighlight>
|-
|elm.chat_global_tab
|click
|elm.chat_global_tab.classList.add("chat_tab_selected");
elm.chat_page_tab.classList.remove("chat_tab_selected");
elm.global_chatfield.style.display = "";
elm.page_chatfield.style.display = "none";
selectedChatTab = 1;
chatGlobalUnread = 0;
updateUnread();
if(!initGlobalTabOpen) {
initGlobalTabOpen = true;
elm.global_chatfield.scrollTop = elm.global_chatfield.scrollHeight;
}
|
|
|<syntaxhighlight lang="js" line="1" start="380">
elm.chat_global_tab.addEventListener("click", function() {
elm.chat_global_tab.classList.add("chat_tab_selected");
elm.chat_page_tab.classList.remove("chat_tab_selected");
elm.global_chatfield.style.display = "";
elm.page_chatfield.style.display = "none";
selectedChatTab = 1;
chatGlobalUnread = 0;
updateUnread();
if(!initGlobalTabOpen) {
initGlobalTabOpen = true;
elm.global_chatfield.scrollTop = elm.global_chatfield.scrollHeight;
}
});
</syntaxhighlight>
|-
|chat_window
|mousemove
|if(isDown) return;
var posX = e.pageX - chat_window.offsetLeft;
var posY = e.pageY - chat_window.offsetTop;
var top = (posY) <= 4;
var left = (posX) <= 3;
var right = (chat_window.offsetWidth - posX) <= 4;
var bottom = (chat_window.offsetHeight - posY) <= 5;
var cursor = "";
if(left || right) cursor = "ew-resize";
if(top || bottom) cursor = "ns-resize";
if((top && left) || (right && bottom)) cursor = "nwse-resize";
if((bottom && left) || (top && right)) cursor = "nesw-resize";
chat_window.style.cursor = cursor;
state = bottom << 3 | right << 2 | left << 1 | top;
|
|
|<syntaxhighlight lang="js" line="1" start="404">
chat_window.addEventListener("mousemove", function(e) {
if(isDown) return;
var posX = e.pageX - chat_window.offsetLeft;
var posY = e.pageY - chat_window.offsetTop;
var top = (posY) <= 4;
var left = (posX) <= 3;
var right = (chat_window.offsetWidth - posX) <= 4;
var bottom = (chat_window.offsetHeight - posY) <= 5;
var cursor = "";
if(left || right) cursor = "ew-resize";
if(top || bottom) cursor = "ns-resize";
if((top && left) || (right && bottom)) cursor = "nwse-resize";
if((bottom && left) || (top && right)) cursor = "nesw-resize";
chat_window.style.cursor = cursor;
state = bottom << 3 | right << 2 | left << 1 | top;
});
</syntaxhighlight>
|-
|chat_window
|mousedown
|downX = e.pageX;
downY = e.pageY;
if(state) {
// subtract 2 for the borders
chatWidth = chat_window.offsetWidth - 2;
chatHeight = chat_window.offsetHeight - 2;
elmX = chat_window.offsetLeft;
elmY = chat_window.offsetTop;
isDown = true;
chatResizing = true;
}
|
|
|<syntaxhighlight lang="js" line="1" start="420">
chat_window.addEventListener("mousedown", function(e) {
downX = e.pageX;
downY = e.pageY;
if(state) {
// subtract 2 for the borders
chatWidth = chat_window.offsetWidth - 2;
chatHeight = chat_window.offsetHeight - 2;
elmX = chat_window.offsetLeft;
elmY = chat_window.offsetTop;
isDown = true;
chatResizing = true;
}
});
</syntaxhighlight>
|-
|document
|mouseup
|isDown = false;
chatResizing = false;
|
|
|<syntaxhighlight lang="js" line="1" start="433">
document.addEventListener("mouseup", function() {
isDown = false;
chatResizing = false;
});
</syntaxhighlight>
|-
|document
|mousemove
|if(!isDown) return;
var offX = e.pageX - downX;
var offY = e.pageY - downY;
var resize_bottom = state >> 3 & 1;
var resize_right = state >> 2 & 1;
var resize_left = state >> 1 & 1;
var resize_top = state & 1;
var width_delta = 0;
var height_delta = 0;
var abs_top = chat_window.offsetTop;
var abs_left = chat_window.offsetLeft;
var snap_bottom = chat_window.style.bottom == "0px";
var snap_right = chat_window.style.right == "0px";
if(resize_top) {
height_delta = -offY;
} else if(resize_bottom) {
height_delta = offY;
}
if(resize_left) {
width_delta = -offX;
} else if(resize_right) {
width_delta = offX;
}
var res = resizeChat(chatWidth + width_delta, chatHeight + height_delta);
if(resize_top && !snap_bottom) {
chat_window.style.top = (elmY + (chatHeight - res[1])) + "px";
}
if(resize_bottom && snap_bottom) {
chat_window.style.bottom = "";
chat_window.style.top = abs_top + "px";
}
if(resize_right && snap_right) {
chat_window.style.right = "";
chat_window.style.left = abs_left + "px";
}
if(resize_left && !snap_right) {
chat_window.style.left = (elmX + (chatWidth - res[0])) + "px";
}
|
|
|<syntaxhighlight lang="js" line="1" start="437">
document.addEventListener("mousemove", function(e) {
if(!isDown) return;
var offX = e.pageX - downX;
var offY = e.pageY - downY;
var resize_bottom = state >> 3 & 1;
var resize_right = state >> 2 & 1;
var resize_left = state >> 1 & 1;
var resize_top = state & 1;
var width_delta = 0;
var height_delta = 0;
var abs_top = chat_window.offsetTop;
var abs_left = chat_window.offsetLeft;
var snap_bottom = chat_window.style.bottom == "0px";
var snap_right = chat_window.style.right == "0px";
if(resize_top) {
height_delta = -offY;
} else if(resize_bottom) {
height_delta = offY;
}
if(resize_left) {
width_delta = -offX;
} else if(resize_right) {
width_delta = offX;
}
var res = resizeChat(chatWidth + width_delta, chatHeight + height_delta);
if(resize_top && !snap_bottom) {
chat_window.style.top = (elmY + (chatHeight - res[1])) + "px";
}
if(resize_bottom && snap_bottom) {
chat_window.style.bottom = "";
chat_window.style.top = abs_top + "px";
}
if(resize_right && snap_right) {
chat_window.style.right = "";
chat_window.style.left = abs_left + "px";
}
if(resize_left && !snap_right) {
chat_window.style.left = (elmX + (chatWidth - res[0])) + "px";
}
});
</syntaxhighlight>
|}
=== Functions ===
{| class="wikitable"
!Name
!Description
!Example usage
!Related code
|-
|api_chat_send(message,opts)
|Sends a chat message from the user running code
|<syntaxhighlight lang="js">
api_chat_send("Hello!",{nick:"nickname"});
</syntaxhighlight>
|<syntaxhighlight lang="js" line="1" start="75">
function api_chat_send(message, opts) {
if(!message) return;
if(!opts) opts = {};
var exclude_commands = opts.exclude_commands;
var nick = opts.nick || YourWorld.Nickname || state.userModel.username;
var location = opts.location ? opts.location : (selectedChatTab == 0 ? "page" : "global");
var msgLim = state.userModel.is_staff ? 3030 : 400;
message = message.trim();
if(!message.length) return;
message = message.slice(0, msgLim);
chatWriteHistory.push(message);
if(chatWriteHistory.length > chatWriteHistoryMax) {
chatWriteHistory.shift();
}
chatWriteHistoryIdx = -1;
chatWriteTmpBuffer = "";
var chatColor;
if(!opts.color) {
if(!YourWorld.Color) {
chatColor = assignColor(nick);
} else {
chatColor = "#" + ("00000" + YourWorld.Color.toString(16)).slice(-6);
}
} else {
chatColor = opts.color;
}
if(!exclude_commands && message.startsWith("/")) {
var args = message.substr(1).split(" ");
var command = args[0].toLowerCase();
args.shift();
if(client_commands.hasOwnProperty(command)) {
client_commands[command](args);
return;
}
}
network.chat(message, location, nick, chatColor);
}
</syntaxhighlight>
|-
|clientChatResponse(message)
|Creates a client-side message only visible to you
|<syntaxhighlight lang="js">
clientChatResponse("This is a client message.");
</syntaxhighlight>
|<syntaxhighlight lang="js" line="1" start="118">
function clientChatResponse(message) {
addChat(null, 0, "user", "[ Client ]", message, "Client", false, false, false, null, getDate());
}
</syntaxhighlight>
|-
|sendChat()
|Sends whatever is in the chat textbox to chat.
|<syntaxhighlight lang="js">
sendChat();
</syntaxhighlight>
|<syntaxhighlight lang="js" line="1" start="216">
function sendChat() {
var chatText = elm.chatbar.value;
elm.chatbar.value = "";
var opts = {};
if(defaultChatColor != null) {
opts.color = "#" + ("00000" + defaultChatColor.toString(16)).slice(-6);
}
api_chat_send(chatText, opts);
}
</syntaxhighlight>
|-
|updateUnread()
|Updates the unread messages counter when chat is closed.
|
|<syntaxhighlight lang="js" line="1" start="226">
function updateUnread() {
var total = elm.total_unread;
var page = elm.page_unread;
var global = elm.global_unread;
var totalCount = chatPageUnread + chatGlobalUnread;
total.style.display = "none";
global.style.display = "none";
page.style.display = "none";
if(totalCount) {
total.style.display = "";
total.innerText = totalCount > 99 ? "99+" : "(" + totalCount + ")";
}
if(chatPageUnread) {
page.style.display = "";
page.innerText = chatPageUnread > 99 ? "99+" : "(" + chatPageUnread + ")";
}
if(chatGlobalUnread) {
global.style.display = "";
global.innerText = chatGlobalUnread > 99 ? "99+" : "(" + chatGlobalUnread + ")";
}
}
</syntaxhighlight>
|-
|event_on_chat(data)
|Updates the unread messages counter for either global chat or the current page.
|
|<syntaxhighlight lang="js" line="1" start="248">
function event_on_chat(data) {
if((!chatOpen || selectedChatTab == 1) && data.location == "page") {
chatPageUnread++;
}
if((!chatOpen || selectedChatTab == 0) && data.location == "global" && !state.worldModel.no_chat_global) {
chatGlobalUnread++;
}
updateUnread();
addChat(data.location, data.id, data.type,
data.nickname, data.message, data.realUsername, data.op, data.admin, data.staff, data.color, data.date || Date.now(), data.dataObj);
}
</syntaxhighlight>
|-
|moveCaretEnd(elm)
|Moves the text cursor to the end of the chat message you want to type in the textbox.
|
|<syntaxhighlight lang="js" line="1" start="271">
function moveCaretEnd(elm) {
if(elm.selectionStart != void 0) {
elm.selectionStart = elm.value.length;
elm.selectionEnd = elm.value.length;
} else if(elm.createTextRange != void 0) {
elm.focus();
var range = elm.createTextRange();
range.collapse(false);
range.select();
}
}
</syntaxhighlight>
|-
|resizable_chat()
|Makes the chat resize on grabbing of corners or edges.
|
|<syntaxhighlight lang="js" line="1" start="395">
function resizable_chat() {
var state = 0;
var isDown = false;
var downX = 0;
var downY = 0;
var elmX = 0;
var elmY = 0;
var chatWidth = 0;
var chatHeight = 0;
chat_window.addEventListener("mousemove", function(e) {
if(isDown) return;
var posX = e.pageX - chat_window.offsetLeft;
var posY = e.pageY - chat_window.offsetTop;
var top = (posY) <= 4;
var left = (posX) <= 3;
var right = (chat_window.offsetWidth - posX) <= 4;
var bottom = (chat_window.offsetHeight - posY) <= 5;
var cursor = "";
if(left || right) cursor = "ew-resize";
if(top || bottom) cursor = "ns-resize";
if((top && left) || (right && bottom)) cursor = "nwse-resize";
if((bottom && left) || (top && right)) cursor = "nesw-resize";
chat_window.style.cursor = cursor;
state = bottom << 3 | right << 2 | left << 1 | top;
});
chat_window.addEventListener("mousedown", function(e) {
downX = e.pageX;
downY = e.pageY;
if(state) {
// subtract 2 for the borders
chatWidth = chat_window.offsetWidth - 2;
chatHeight = chat_window.offsetHeight - 2;
elmX = chat_window.offsetLeft;
elmY = chat_window.offsetTop;
isDown = true;
chatResizing = true;
}
});
document.addEventListener("mouseup", function() {
isDown = false;
chatResizing = false;
});
document.addEventListener("mousemove", function(e) {
if(!isDown) return;
var offX = e.pageX - downX;
var offY = e.pageY - downY;
var resize_bottom = state >> 3 & 1;
var resize_right = state >> 2 & 1;
var resize_left = state >> 1 & 1;
var resize_top = state & 1;
var width_delta = 0;
var height_delta = 0;
var abs_top = chat_window.offsetTop;
var abs_left = chat_window.offsetLeft;
var snap_bottom = chat_window.style.bottom == "0px";
var snap_right = chat_window.style.right == "0px";
if(resize_top) {
height_delta = -offY;
} else if(resize_bottom) {
height_delta = offY;
}
if(resize_left) {
width_delta = -offX;
} else if(resize_right) {
width_delta = offX;
}
var res = resizeChat(chatWidth + width_delta, chatHeight + height_delta);
if(resize_top && !snap_bottom) {
chat_window.style.top = (elmY + (chatHeight - res[1])) + "px";
}
if(resize_bottom && snap_bottom) {
chat_window.style.bottom = "";
chat_window.style.top = abs_top + "px";
}
if(resize_right && snap_right) {
chat_window.style.right = "";
chat_window.style.left = abs_left + "px";
}
if(resize_left && !snap_right) {
chat_window.style.left = (elmX + (chatWidth - res[0])) + "px";
}
});
}
</syntaxhighlight>
|}
=== Variables ===
== permissions.js ==
=== Variables ===
{| class="wikitable"
|+
!Name
!Description
!Related code
|-
|PERM
|Defines permission numbers for easier use instead of writing "Admin"
|<syntaxhighlight lang="js" line="1" start="1">
var PERM = {
ADMIN: 2,
MEMBERS: 1,
PUBLIC: 0
};
</syntaxhighlight>
|}
==== Permissions ====
Since <code>Permissions</code> is a very long dictionary variable, this table is divided into specific definitions in it.
{| class="wikitable"
|+
!Name
!Description
!Related definition
|-
|can_admin
|Checks if user is an admin.
|<syntaxhighlight lang="js" line="1" start="7">
can_admin: function(user) {
return user.is_owner;
},
</syntaxhighlight>
|-
|can_coordlink
|Checks if user can create coordinate links in the world they're in.
|<syntaxhighlight lang="js" line="1" start="10">
can_coordlink: function(user, world) {
return Permissions.user_matches_perm(user, world, world.feature_coord_link);
},
</syntaxhighlight>
|-
|can_edit_tile
|Checks if user can write in a tile / character (protections).
|<syntaxhighlight lang="js" line="1" start="13">
can_edit_tile: function(user, world, tile, charX, charY) {
if(!tile) {
throw new Error("Can't check perms on un-initted tile");
}
if(!Permissions.can_read(user, world)) {
return false;
}
var targetWritability;
if(tile.char) {
targetWritability = tile.char[charY * tileC + charX];
if(targetWritability == null) targetWritability = tile.writability; // inherit from tile
if(targetWritability == null) targetWritability = world.writability; // inherit from world
} else {
targetWritability = tile.writability;
if(targetWritability == null) targetWritability = world.writability;
}
return Permissions.user_matches_perm(user, world, targetWritability);
},
</syntaxhighlight>
|-
|can_go_to_coord
|Checks if user can teleport.
|<syntaxhighlight lang="js" line="1" start="31">
can_go_to_coord: function(user, world) {
return Permissions.user_matches_perm(user, world, world.feature_go_to_coord);
},
</syntaxhighlight>
|-
|can_paste
|Checks if user can paste.
|<syntaxhighlight lang="js" line="1" start="34">
can_paste: function(user, world) {
return Permissions.user_matches_perm(user, world, world.feature_paste);
},
</syntaxhighlight>
|-
|can_copy
|Checks if user can copy.
|<syntaxhighlight lang="js" line="1" start="37">
can_copy: function(user, world) {
if(user.is_owner || user.is_member) return true;
return !world.no_copy;
},
</syntaxhighlight>
|-
|can_protect_tiles
|Checks if user can protect tiles.
|<syntaxhighlight lang="js" line="1" start="41">
can_protect_tiles: function(user, world) {
if(user.is_owner) return true;
return world.feature_membertiles_addremove && user.is_member;
},
</syntaxhighlight>
|-
|can_erase
|Checks if user can use the built-in eraser.
|<syntaxhighlight lang="js" line="1" start="45">
can_erase: function(user, world) {
if(user.is_owner) return true;
return Permissions.user_matches_perm(user, world, world.quick_erase);
},
</syntaxhighlight>
|-
|can_read
|Checks if user can view the world.
|<syntaxhighlight lang="js" line="1" start="49">
can_read: function(user, world) {
return Permissions.user_matches_perm(user, world, world.readability);
},
</syntaxhighlight>
|-
|can_urllink
|Checks if user can create links leading to other URL's.
|<syntaxhighlight lang="js" line="1" start="52">
can_urllink: function(user, world) {
return Permissions.user_matches_perm(user, world, world.feature_url_link);
},
</syntaxhighlight>
|-
|can_write
|Checks if user can write on the world.
|<syntaxhighlight lang="js" line="1" start="55">
can_write: function(user, world) {
if(!Permissions.can_read(user, world)) {
return false;
}
return Permissions.user_matches_perm(user, world, world.writability);
},
</syntaxhighlight>
|-
|can_chat
|Checks if user can chat.
|<syntaxhighlight lang="js" line="1" start="61">
can_chat: function(user, world) {
return Permissions.user_matches_perm(user, world, world.chat_permission);
},
</syntaxhighlight>
|-
|can_show_cursor
|Checks if showing cursors is enabled for a user.
|<syntaxhighlight lang="js" line="1" start="64">
can_show_cursor: function(user, world) {
return Permissions.user_matches_perm(user, world, world.show_cursor);
},
</syntaxhighlight>
|-
|can_color_text
|Checks if user can change their text colour.
|<syntaxhighlight lang="js" line="1" start="67">
can_color_text: function(user, world) {
return Permissions.user_matches_perm(user, world, world.color_text);
},
</syntaxhighlight>
|-
|can_color_cell
|Checks if user can change their cell colour.
|<syntaxhighlight lang="js" line="1" start="70">
can_color_cell: function(user, world) {
return Permissions.user_matches_perm(user, world, world.color_cell);
},
</syntaxhighlight>
|-
|user_matches_perm
|Gets users permissions.
|<syntaxhighlight lang="js" line="1" start="73">
user_matches_perm: function(user, world, perm) {
if(perm == -1) { // no one
return false;
}
if(perm == PERM.PUBLIC) { // anyone
return true;
}
if(user.is_owner) {
return true;
}
if(perm == PERM.ADMIN) {
return false;
}
if(perm == PERM.MEMBERS && user.is_member) {
return true;
}
return false;
}
};
</syntaxhighlight>
|}
|}
[[Category:Articles nominated by Guest-1052]]
[[Category:Documentation]]

Latest revision as of 10:57, 3 April 2024

Our World Of Text

This page contains documentation of the OWOT codebase, examples, and code locations.

If you want to talk about this page, go to Talk:Docs

Code Documentation

OWOT.js

Event Listeners:

Object Listen Event Functions/Events Fired Emits Example Usage Related Code
window load "clientLoaded"
window.addEventListener("load", function() {
	w.emit("clientLoaded");
});
hash change manageCoordHash(); https://ourworldoftext.com/#x:10,y:20
window.onhashchange = function(e) {
	manageCoordHash();
}
before unload if(writeBuffer.length) flushWrites();
window.onbeforeunload = function() {
	if(writeBuffer.length) flushWrites();
}
resize event_resize ("resize", ratio)
window.addEventListener("resize", event_resize);
document select start self
document.onselectstart = function(e) {
	var target = e.target;
	if(closest(target, getChatfield()) || target == elm.chatbar || closest(target, elm.confirm_js_code) || closest(target, elm.announce_text)) {
		return true;
	}
	return Modal.isOpen;
}
key down
  • keydown_regionSelect
  • event_keydown_copy_char
  • event_keydown_copy_color
  • event_keydown
document.addEventListener("keydown", keydown_regionSelect);
document.addEventListener("keydown", event_keydown_copy_char);
document.addEventListener("keydown", event_keydown_copy_color);
document.addEventListener("keydown", event_keydown);
key up event_keyup ("keyUp", e);
function event_keyup(e) {
	w.emit("keyUp", e);
}
mouse move
  • mousemove_tileProtectAuto
  • mousemove_linkAuto
  • event_mousemove
("mouseMove", {

tileX: tileX,

tileY: tileY,

charX: charX,

charY: charY,

pageX: pageX,

pageY: pageY

})

document.addEventListener("mousemove", mousemove_tileProtectAuto);
document.addEventListener("mousemove", mousemove_linkAuto);
document.addEventListener("mousemove", event_mousemove);
mouse down event_mousedown ("mouseDown", {

tileX: pos[0],

tileY: pos[1],

charX: pos[2],

charY: pos[3],

pageX: pageX,

pageY: pageY

});

document.addEventListener("mousedown", event_mousedown);
mouse up event_mouseup
document.addEventListener("mouseup", event_mouseup);
mouse enter event_mouseenter ("mouseEnter", e)
document.addEventListener("mouseenter", event_mouseenter);
touch start event_touchstart
document.addEventListener("touchstart", event_touchstart);
touch end event_touchend
document.addEventListener("touchend", event_touchend);
touch move event_touchmove
document.addEventListener("touchmove", event_touchmove, { passive: false });
wheel
  • event_wheel
  • event_wheel_zoom
("scroll", {

deltaX: -deltaX,

deltaY: -deltaY

});

document.addEventListener("wheel", event_wheel);
document.addEventListener("wheel", event_wheel_zoom, {
	passive: false
});
document.body key down
  • keydown_tileProtectAuto
  • keydown_linkAuto
document.body.addEventListener("keydown", keydown_tileProtectAuto);
document.body.addEventListener("keydown", keydown_linkAuto);
key up onKeyUp
document.body.addEventListener("keyup", onKeyUp);
w cursor Move updateCoordDisplay
w.on("cursorMove", updateCoordDisplay);
cursor Hide updateCoordDisplay
w.on("cursorHide", updateCoordDisplay);
tiles Rendered self
w.on("tilesRendered", function() {
	for(var i = 0; i < regionSelections.length; i++) {
		var reg = regionSelections[i];
		if(reg.regionCoordA && reg.regionCoordB) reg.setSelection(reg.regionCoordA, reg.regionCoordB);
	}
});
cursor Move setClientGuestCursorPosition
w.on("cursorMove", function(pos) {
	setClientGuestCursorPosition(pos.tileX, pos.tileY, pos.charX, pos.charY);
});
cursor Hide setClientGuestCursorPosition
w.on("cursorHide", function() {
	setClientGuestCursorPosition(0, 0, 0, 0, true);
});
elm.textInput
  • keydown
  • input
  • stabilizeTextInput
  • event_input
elm.textInput.addEventListener("keydown", stabilizeTextInput);
elm.textInput.addEventListener("input", event_input);
elm.owot context menu self
elm.owot.oncontextmenu = function() {
	if(ignoreCanvasContext) {
		ignoreCanvasContext = false;
		elm.owot.style.pointerEvents = "none";
		setTimeout(function() {
			ignoreCanvasContext = true;
			elm.owot.style.pointerEvents = "";
		}, 1);
	}
}
elm.coords click self
elm.coords.onclick = function() {
	showCursorCoordinates = !showCursorCoordinates;
	if(showCursorCoordinates) {
		elm.cursor_coords.style.display = "";
		updateCoordDisplay();
	} else {
		elm.cursor_coords.style.display = "none";
		updateCoordDisplay();
	}
}

Functions:

Name Description Example Usage Code In Use
init_dom()
function init_dom() {
	owot = document.getElementById("owot");
	owot.style.display = "block";
	owot.style.cursor = defaultCursor;
	owotCtx = owot.getContext("2d");
	textInput = document.getElementById("textInput");
	textInput.value = "";
	linkElm = elm.link_element;
	linkDiv = elm.link_div;
	updateCoordDisplay();
	initTextDecoBar();
	defineElements({
		owot: owot,
		textInput: textInput
	});
}
getWndWidth()
function getWndWidth() {
	return document.body.clientWidth || window.innerWidth;
}
getWndHeight()
decimal(percentage)
normFontSize(size)
deviceRatio()
makeEnum(vars)
setRGBColorPicker(r, g, b)
setRGBBgColorPicker(r, g, b)
setColorPickerRandom()
updateColorPicker()
updateBgColorPicker()
updateCoordDisplay()
createColorButton(color, isHighlight)
addColorShortcuts()
draggable_element(dragger, dragged, exclusions, onDrag)
resizeChat(width, height)
getStoredNickname()
storeNickname()
getStoredConfig()
storeConfig()
loadBackgroundData(cb, timeout_cb)
keydown_regionSelect(e)
handleRegionSelection(coordA, coordB, regWidth, regHeight)
buildFontTemplate(set)
rebuildFontTemplates()
updateScaleConsts()
setupTextRenderCtx()
reloadRenderer()
updateRendererZoom(percentage)
zoomGarbageCollect()
changeZoom(percentage, isPartial)
setZoombarValue()
fromLogZoom(val)
toLogZoom(val)
browserZoomAdjust(initial)
updateAutoProg()
mousemove_tileProtectAuto()
keydown_tileProtectAuto(e)
mousemove_linkAuto()
keydown_linkAuto(e)
onKeyUp(e)
adjust_scaling_DOM(ratio)
event_resize()
getChar(tileX, tileY, charX, charY)
getCharColor(tileX, tileY, charX, charY)
getCharBgColor(tileX, tileY, charX, charY)
getCharProtection(tileX, tileY, charX, charY)
getCharDecoration(tileX, tileY, charX, charY)
getCharInfo(tileX, tileY, charX, charY)
getCharInfoXY(x, y)
getLink(tileX, tileY, charX, charY)
getLinkXY(x, y)
event_keydown_copy_char(e)
event_keydown_copy_color(e)
resolveColorValue(val)
isTileStale(tileX, tileY)
checkTextColorOverride()
menu_color(color)
defaultStyles()
manageCoordHash()
getWorldProps(world, type, cb)
stopLinkUI()
removeTileProtectHighlight()
stopTileUI()
doLink()
doProtect()
triggerUIClick()
event_mousedown(e, arg_pageX, arg_pageY)
renderCursor(coords)
removeCursor()
stopDragging()
event_mouseup(e, arg_pageX, arg_pageY)
event_mouseleave(e)
event_mouseenter(e)
is_link(tileX, tileY, charX, charY)
flushWrites()
setWriteInterval()
moveCursor(direction, preserveVertPos, amount)
markCharacterAsUndoable(tileX, tileY, charX, charY)
isCharLatestInUndoBuffer(tileX, tileY, charX, charY)
writeCharTo(char, charColor, tileX, tileY, charX, charY, undoFlags, undoOffset, charBgColor, dB, dI, dU, dS)
undoWrite()
redoWrite()
writeCharToXY(char, charColor, x, y, charBgColor, dB, dI, dU, dS)
writeChar(char, doNotMoveCursor, color, noNewline, undoCursorOffset, bgColor, dB, dI, dU, dS)
coordinateAdd(tileX1, tileY1, charX1, charY1, tileX2, tileY2, charX2, charY2)
propagatePosition(coords, char, noEnter, noVertPos)
textcode_parser(value, coords, defaultColor, defaultBgColor)
stabilizeTextInput()
event_input(e)
stopPasting()
autoArrowKeyMoveStart(dir)
autoArrowKeyMoveStop(dir)
event_keydown(e)
event_keyup(e)
isMainPage()
alertJS(data, restrict)
closeJSAlert()
executeJS(code)
confirmRunJSLink(data)
runJSLink(data, restrict)
coord_link_click(evt)
url_link_click(evt)
updateHoveredLink(mouseX, mouseY, evt, safe)
event_mousemove(e, arg_pageX, arg_pageY)
getCenterTouchPosition(touches)
event_touchstart(e)
event_touchend(e)
event_touchmove(e)
touch_pagePos(e)
event_wheel(e)
event_wheel_zoom(e)
convertKeyCode(key)
checkKeyPress(e, combination)
checkKeyPatterns(combination)
createWsPath()
createSocket(getChatHist)
cullRanges(map, width, height)
updateRemoteBoundary()
clearRemoteBoundary()
expandLocalBoundary(x, y)
getAndFetchTiles()
clearTiles(all)
clearVisibleTiles()
highlight(positions, unlimited, color)
blankTile()
colorChar(tileX, tileY, charX, charY, colorClass)
uncolorChar(tileX, tileY, charX, charY, colorClass)
decodeCharProt(str)
encodeCharProt(array, encoding)
getCharTextDecorations(char)
setCharTextDecorations(char, bold, italic, under, strike)
resolveCharEmojiCombinations(char)
detectCharEmojiCombinations(char)
clearCharTextDecorations(char)
clearAllGuestCursors()
renderLoop()
protectPrecisionOption(option)
toggleTextDecoBar()
initTextDecoBar()
protectSelectionStart(start, end, width, height)
protectSelectionCancel()
protectSelection()
buildMenu()
updateMenuEntryVisiblity()
regionSelectionsActive()
RegionSelection()
setClientGuestCursorPosition(tileX, tileY, charX, charY, hidden)
sendCursorPosition()
disableBgColorPicker()
enableBgColorPicker()
makeCoordLinkModal()
makeCoordGotoModal()
makeURLModal()
buildBackgroundColorModal(modal)
resetColorModalVisibility()
makeColorModal()
makeSelectionModal()
searchTellEdit(tileX, tileY, charX, charY)
tile_offset_object(data, tileOffX, tileOffY)
begin()

Variables:

Name Description Example Usage Code In Use
YourWorld An object containing the users current text color, cell background color, and chat nick name.
//Sets the users color to a random one.
YourWorld.Color = Math.round((Math.random()*16777215));
var YourWorld = {
	Color: window.localStorage ? +localStorage.getItem("color") : 0,
	BgColor: -1,
	Nickname: state.userModel.username
};
owot The DOM canvas element
//Hides the owot canvas.
owot.style.opacity = 0;
owot = document.getElementById("owot");
owotCtx The CanvasRenderingContext2D of the owot canvas
//Clears all the rendered tiles from the view.
owotCtx.clearRect(0, 0, owotWidth, owotHeight);
owotCtx = owot.getContext("2d");
textInput The DOM textarea element used for writing to the owot canvas.
//Paste "hello world" at the current cursor position.
textInput.value = `hello world`;
textInput = document.getElementById("textInput");
linkElm The DOM link element used for user link clicks.
//logs to the console whether or not the link is a javascript link.
linkElm.addEventListener(`click`,function(){
console.log(linkParams.protocol === `javascript`);                   
})
linkElm = elm.link_element;
link_div The DOM link div element used to scale the linkElm to the same size as a cell within the owot canvas.
//Highlights the URL being hovered over.
linkDiv.style.background = `rgba(255,255,0,0.5)`
linkDiv = elm.link_div;
colorInput, colorInputBg The DOM color inputs to select text and cell background color.
//Generate a random color on the text color input field.
const randomColor = Math.floor(Math.random()*16777215).toString(16).toUpperCase();
colorInput.jscolor.fromString(`#${randomColor}`);
	colorInputBg = modal.addEntry("Cell color", "color").input;
	colorInput = modal.addEntry("Text color", "color").input;
colorShortcuts, colorShortcutsBg A DOM div container used as a color pallet for quick access.
//Randomize all color palette colors.
const colorButtons = colorShortcuts.querySelectorAll('.color_btn');
  colorButtons.forEach(button => {
    if (button.title !== 'Random color') {
     const randomColor = `#${Math.floor(Math.random()*16777215).toString(16).toUpperCase()}`;
      button.style.backgroundColor = randomColor;
      button.title = randomColor;
    }
  });
	for(var i = 0; i < colors.length; i++) {
		var color = colors[i];
		colorShortcuts.appendChild(createColorButton(color));
	}
enums An unused object created to store position and write edits.
//Use enums.position as a template for creating an updatedPosition object
const newCoord = [7, 5, 3, 1];
const updatedPosition = { ...enums.position };
for (const key in updatedPosition) {
  if (updatedPosition.hasOwnProperty(key)) {
    const positionIndex = updatedPosition[key];
    updatedPosition[key] = newCoord[positionIndex];
  }
}
enums.edit = makeEnum(["tileY", "tileX", "charY", "charX", "time", "char", "id", "color"]);
enums.position = makeEnum(["tileX", "tileY", "charX", "charY"]);
ws_path Stores the pages' websocket path.
//Change the socket, refreshing the client ID
w.changeSocket(ws_path, true);
var ws_path = createWsPath();
menu,

w.menu, Menu

An object containing all of the DOM elements and functions of the menu.
//Adds a button to the menu that alerts "Hello World" when clicked.
menu.addOption("alert", function(){alert("Hello World")});
	menu = new Menu(elm.menu_elm, elm.nav_elm);
	w.menu = menu;
menuStyle A temporary style element created and used to style the menu.
//Generate a random set of colors for the menu each time the menu is hovered over.
elm.menu_elm.addEventListener("mouseover", function() {
  if (menuStyle) {
    document.head.removeChild(menuStyle)
  }
 function makeRandom (){
     return Math.floor(Math.random() * 16777215).toString(16).toUpperCase();
 }
  menuStyle = document.createElement("style");
  const randomColor = makeRandom();
  const randomColorBG = makeRandom();
  const randomColorBorder = makeRandom();

  menuStyle.innerHTML = `
#menu.hover,#nav {background: #${randomColorBG};border-color: #${randomColorBorder};color: #${randomColor};}
 #nav li {border-top-color: #${randomColorBorder};}
 #nav li.hover {background-color: #${randomColorBG};}
 #coords {background-color: #${randomColorBG};color: #${randomColor};}`
  document.head.appendChild(menuStyle);
})
	menuStyle.innerHTML = "#menu.hover, #nav {" +
			"background: " + color + ";" +
			"border-color: " + bColor + ";" +
			"color: " + tColor + ";" +
		"}\n" +
		"#nav li {" +
			"border-top-color: " + bColor + ";" +
		"}\n" +
		"#nav li.hover {" +
			"background-color: " + hColor + ";" +
		"}\n" +
		"#coords {" +
			"background-color: " + bColor + ";" +
			"color: " + tColor + ";" +
		"}";
}
styles An object which controls the colors used within a world.
//Sets the public tile color to red.
styles.public = "red";
renderTiles(true);
var styles = defaultStyles();
nextObjId An integer used to track edits.
//Writes the character "█" at the cursorCoords location, then updates the nextObjId id
const [tileX, tileY, charX, charY] = cursorCoords;
console.log(currentPosition)
const editArray = [tileY, tileX, charY, charX, getDate(),"█", nextObjId]
writeBuffer.push(editArray);
nextObjId++;
var nextObjId = 1;
owotWidth,

owotHeight

The current width and height of the DOM window.
//Estimate the total number of fully visible cells that could exist on the screen
const cellAmount = Math.floor(owotHeight/cellH * owotWidth/cellW);
	owotWidth = Math.round(window_width * ratio);
	owotHeight = Math.round(window_height * ratio);
js_alert_active A bool stating if the javascript alert window is open.
var js_alert_active = false;
worldFocused A bool stating if the owot canvas is in focus.
//check every 100ms if the owot canvas was last clicked, if it was then randomly change the public tile color.
setInterval(function() {
  if (worldFocused) {
    styles.public = "#" + Math.floor(Math.random() * 16777215).toString(16).toUpperCase();
    w.redraw()
  }
}, 100)
if(closest(target, getChatfield()) || target == elm.chatbar || target == elm.confirm_js_code) {
		worldFocused = false;
	} else {
		worldFocused = true;
	}
chatResizing A bool stating if the chat window is being resized.
//check every 100ms if the chat is resizing, if it is, change the public tile color
setInterval(function() {
  if (chatResizing) {
    styles.public = "#" + Math.floor(Math.random() * 16777215).toString(16).toUpperCase();
    w.redraw()
  }
}, 100)
draggable_element(elm.chat_window, null, [
	elm.chatbar, elm.chatsend, elm.chat_close, elm.chat_page_tab, elm.chat_global_tab, elm.page_chatfield, elm.global_chatfield
], function() {
	if(chatResizing) {
		return -1;
	}
});
tiles An object containing all the loaded tiles.
//Return any visible links
const [X,Y] = cursorCoords;
tiles[`${X},${Y}`].properties.cell_props
Tile.set = function(tileX, tileY, data) {
	var str = tileY + "," + tileX;
	if(!(str in tiles)) {
		w.tile.count++;
	}
	tiles[str] = data;
	expandLocalBoundary(tileX, tileY);
	return data;
}
images,

keysPressed, imgPatterns

Empty, unused objects.
var images = {};
var keysPressed = {};
previousErase An integer of the last date the erase function was utilised.
//Logs the previous erase time in a human-readable way.
function readPreviousErase() {
  if (previousErase == 0) {
    return
  }
  const date = new Date(previousErase);
  const options = {
    year: 'numeric',
    month: 'long',
    day: 'numeric',
    hour: '2-digit',
    minute: '2-digit',
    second: '2-digit',
    timeZoneName: 'short'
  };
  console.log("last Erased at:", date.toLocaleString(undefined, options));
}
function event_input(e) {
	if(e.inputType == "deleteContentBackward") {
		if(getDate() - previousErase > 25 || !previousErase) {
			moveCursor("left", true);
			writeChar("\x08", true, null, false, 1);
		}
		previousErase = getDate();
	}
}
verticalEnterPos A 2D array coordinate of the position to go when pressing enter.
//Stair-step the return position on "enter"
textInput.addEventListener("input", function(e) {
  if (e.inputType === "insertLineBreak") {
    const [X, x] = verticalEnterPos;
    verticalEnterPos = [X, (x + 1) % 16]
  }
})
		if(noVertPos) {
			coords.tileX = 0;
			coords.charX = 0;
		} else {
			coords.tileX = verticalEnterPos[0];
			coords.charX = verticalEnterPos[1];
		}
textColorOverride public-member-owner bitfield used to modify the text color in fields.
	if(styles.public_text != "#000" && styles.public_text != "#000000") {
		textColorOverride |= public;
	} else {
		textColorOverride &= textColorOverride ^ public;
	}
writeBuffer An object holding data waiting to be rendered to the canvas.
//Writes the character "█" at the cursorCoords location
const [tileX, tileY, charX, charY] = cursorCoords;
const editArray = [tileY, tileX, charY, charX, getDate(), "█", nextObjId++]
writeBuffer.push(editArray);
	tellEdit.push(editArray); // track local changes
	writeBuffer.push(editArray); // send edits to server
	nextObjId++;
highlightFlash An object containing cell coordinates of cells to be highlighted.
//Flashes a random color on all visible cells
function flashRandom() {
  const visibleTiles = getVisibleTiles();
  const color = [Math.floor(Math.random() * 256), Math.floor(Math.random() * 256), Math.floor(Math.random() * 256)];
  const positions = [];

  // Generate the positions array
  for (const [tileX, tileY] of visibleTiles) {
    for (let charY = 0; charY < 8; charY++) {
      for (let charX = 0; charX < 16; charX++) {
        positions.push([tileX, tileY, charX, charY]);
      }
    }
  }

  // Update highlightFlash based on positions
  for (const [tileX, tileY, charX, charY] of positions) {
    const tileKey = `${tileY},${tileX}`;
    highlightFlash[tileKey] ??= {};
    highlightFlash[tileKey][charY] ??= {};

    if (!highlightFlash[tileKey][charY][charX]) {
      highlightFlash[tileKey][charY][charX] = [getDate(), color, [...color]];
      highlightCount++;
    }
  }
}
		if(!highlightFlash[tileY + "," + tileX]) {
			highlightFlash[tileY + "," + tileX] = {};
		}
highlightCount An iterator used to limit the amount of highlights rendered to the canvas.
//Prevents the user from seeing highlights
highlightCount = Infinity;
		if(highlightCount > highlightLimit && !unlimited) return;
coloredChars An object holding all of the highlighted characters.
	var container = coloredChars[tileY + "," + tileX];
	if(!container) {
		container = {};
		coloredChars[tileY + "," + tileX] = container;
	}
shiftOptState An object used to store the viewport values
var shiftOptState = { prevX: 0, prevY: 0, x1: 0, y1: 0, x2: 0, y2: 0, prevZoom: -1 };
backgroundImage
backgroundPattern
backgroundPatternSize
guestCursorsByTile
guestCursors
clientGuestCursorPos
disconnectTimeout
menuOptions
undoBuffer
textDecorationOffset
textDecorationModes
fontTemplate
specialFontTemplate
fontOrder
specialFontOrder
initiallyFetched
lastLinkHover
lastTileHover
regionSelections
specialClientHooks
specialClientHookMap
bgImageHasChanged
remoteBoundary
boundaryStatus
positionX
positionY
coordSizeX
coordSizeY
gridEnabled
subgridEnabled
linksEnabled
linksRendered
colorsEnabled
backgroundEnabled
scrollingEnabled
zoomRatio
protectPrecision
checkTileFetchInterval
zoom
userZoom
unloadTilesAuto
useHighlight
highlightLimit
ansiBlockFill
colorizeLinks
brBlockFill
tileFetchOffsetX
tileFetchOffsetY
ignoreCanvasContext
elementSnapApprox
mSpecRendering
combiningCharsEnabled
surrogateCharsEnabled
defaultCoordLinkColor
defaultURLLinkColor
defaultHighlightColor
secureJSLink
secureLink
pasteDirRight
pasteDirDown
defaultCursor
defaultDragCursor
fetchClientMargin
classicTileProcessing
unloadedPatternPanning
cursorRenderingEnabled
guestCursorsEnabled
showMyGuestCursor
unobstructCursor
shiftOptimization
transparentBackground
writeFlushRate
bufferLargeChars
cursorOutlineEnabled
showCursorCoordinates
textDecorationsEnabled
keyConfig
draggable_element_mousemove
draggable_element_mouseup
defaultSizes
cellWidthPad
tileW
tileH
cellW
cellH
font
specialCharFont
tileC
tileR
tileArea
tileWidth
tileHeight
dTileW
dTileH
textRenderCanvas
textRenderCtx
tileProtectAuto
linkAuto
autoTotal
cursorCoords
cursorCoordsCurrent
currentPosition
currentPositionInitted
currentMousePosition
Tile
poolCleanupInterval
dragStartX
dragStartY
dragPosX
dragPosY
isDragging
hasDragged
draggingEnabled
cursorEnabled
writeInterval
write_busy
pasteInterval
linkQueue
autoArrowKeyMoveInterval
autoArrowKeyMoveActive
autoArrowKeyMoveState
linkParams
currentSelectedLink
currentSelectedLinkCoords
touchInitZoom
touchInitDistance
touchPrev
fetchInterval
timesConnected
colorClasses
isTileLoaded
isTileVisible
networkHTTP
network
w
tellEdit
ws_functions

chat.js

Event listeners

Object Listen Event Functions/Events Fired Emits Example Usage Related Code
elm.chatsend click sendChat()
elm.chatsend.addEventListener("click", function() {
	sendChat();
});
elm.chatbar keypress var keyCode = e.keyCode;

if(keyCode == 13) {

sendChat();

}

elm.chatbar.addEventListener("keypress", function(e) {
	var keyCode = e.keyCode;
	if(keyCode == 13) { // Enter
		sendChat();
	}
});
elm.chatbar keydown var keyCode = e.keyCode;

// scroll through chat history that the client sent

if(keyCode == 38) { // up

// history modified

if(chatWriteHistoryIdx > -1 && elm.chatbar.value != chatWriteHistory[chatWriteHistory.length - chatWriteHistoryIdx - 1]) {

chatWriteHistory[chatWriteHistory.length - chatWriteHistoryIdx - 1] = elm.chatbar.value;

}

if(chatWriteHistoryIdx == -1 && elm.chatbar.value) {

chatWriteTmpBuffer = elm.chatbar.value;

}

chatWriteHistoryIdx++;

if(chatWriteHistoryIdx >= chatWriteHistory.length) chatWriteHistoryIdx = chatWriteHistory.length - 1;

var upVal = chatWriteHistory[chatWriteHistory.length - chatWriteHistoryIdx - 1];

if(!upVal) return;

elm.chatbar.value = upVal;

// pressing up will move the cursor all the way to the left by default

e.preventDefault();

moveCaretEnd(elm.chatbar);

} else if(keyCode == 40) { // down

// history modified

if(chatWriteHistoryIdx > -1 && elm.chatbar.value != chatWriteHistory[chatWriteHistory.length - chatWriteHistoryIdx - 1]) {

chatWriteHistory[chatWriteHistory.length - chatWriteHistoryIdx - 1] = elm.chatbar.value;

}

chatWriteHistoryIdx--;

if(chatWriteHistoryIdx < -1) {

chatWriteHistoryIdx = -1;

return;

}

var str = "";

if(chatWriteHistoryIdx != -1) {

str = chatWriteHistory[chatWriteHistory.length - chatWriteHistoryIdx - 1];

} else {

if(chatWriteTmpBuffer) {

str = chatWriteTmpBuffer;

e.preventDefault();

moveCaretEnd(elm.chatbar);

}

}

elm.chatbar.value = str;

e.preventDefault();

moveCaretEnd(elm.chatbar);

}

elm.chatbar.addEventListener("keydown", function(e) {
	var keyCode = e.keyCode;
	// scroll through chat history that the client sent
	if(keyCode == 38) { // up
		// history modified
		if(chatWriteHistoryIdx > -1 && elm.chatbar.value != chatWriteHistory[chatWriteHistory.length - chatWriteHistoryIdx - 1]) {
			chatWriteHistory[chatWriteHistory.length - chatWriteHistoryIdx - 1] = elm.chatbar.value;
		}
		if(chatWriteHistoryIdx == -1 && elm.chatbar.value) {
			chatWriteTmpBuffer = elm.chatbar.value;
		}
		chatWriteHistoryIdx++;
		if(chatWriteHistoryIdx >= chatWriteHistory.length) chatWriteHistoryIdx = chatWriteHistory.length - 1;
		var upVal = chatWriteHistory[chatWriteHistory.length - chatWriteHistoryIdx - 1];
		if(!upVal) return;
		elm.chatbar.value = upVal;
		// pressing up will move the cursor all the way to the left by default
		e.preventDefault();
		moveCaretEnd(elm.chatbar);
	} else if(keyCode == 40) { // down
		// history modified
		if(chatWriteHistoryIdx > -1 && elm.chatbar.value != chatWriteHistory[chatWriteHistory.length - chatWriteHistoryIdx - 1]) {
			chatWriteHistory[chatWriteHistory.length - chatWriteHistoryIdx - 1] = elm.chatbar.value;
		}
		chatWriteHistoryIdx--;
		if(chatWriteHistoryIdx < -1) {
			chatWriteHistoryIdx = -1;
			return;
		}
		var str = "";
		if(chatWriteHistoryIdx != -1) {
			str = chatWriteHistory[chatWriteHistory.length - chatWriteHistoryIdx - 1];
		} else {
			if(chatWriteTmpBuffer) {
				str = chatWriteTmpBuffer;
				e.preventDefault();
				moveCaretEnd(elm.chatbar);
			}
		}
		elm.chatbar.value = str;
		e.preventDefault();
		moveCaretEnd(elm.chatbar);
	}
});
elm.chat_close click w.emit("chatClose");

elm.chat_window.style.display = "none";

elm.chat_open.style.display = "";

chatOpen = false;

"chatClose"
elm.chat_close.addEventListener("click", function() {
	w.emit("chatClose");
	elm.chat_window.style.display = "none";
	elm.chat_open.style.display = "";
	chatOpen = false;
});
elm.chat_open click elm.chat_window.style.display = "";

elm.chat_open.style.display = "none";

chatOpen = true;

if(selectedChatTab == 0) {

chatPageUnread = 0;

updateUnread();

if(!initPageTabOpen) {

initPageTabOpen = true;

elm.page_chatfield.scrollTop = elm.page_chatfield.scrollHeight;

}

} else {

chatGlobalUnread = 0;

updateUnread();

if(!initGlobalTabOpen) {

initGlobalTabOpen = true;

elm.global_chatfield.scrollTop = elm.global_chatfield.scrollHeight;

}

}

var chatWidth = chat_window.offsetWidth - 2;

var chatHeight = chat_window.offsetHeight - 2;

var screenRatio = window.devicePixelRatio;

if(!screenRatio) screenRatio = 1;

var virtWidth = owotWidth / screenRatio;

if(chatWidth > virtWidth) {

resizeChat(virtWidth - 2, chatHeight);

}

"chatOpen"
elm.chat_open.addEventListener("click", function() {
	w.emit("chatOpen");
	elm.chat_window.style.display = "";
	elm.chat_open.style.display = "none";
	chatOpen = true;
	if(selectedChatTab == 0) {
		chatPageUnread = 0;
		updateUnread();
		if(!initPageTabOpen) {
			initPageTabOpen = true;
			elm.page_chatfield.scrollTop = elm.page_chatfield.scrollHeight;
		}
	} else {
		chatGlobalUnread = 0;
		updateUnread();
		if(!initGlobalTabOpen) {
			initGlobalTabOpen = true;
			elm.global_chatfield.scrollTop = elm.global_chatfield.scrollHeight;
		}
	}
	var chatWidth = chat_window.offsetWidth - 2;
	var chatHeight = chat_window.offsetHeight - 2;
	var screenRatio = window.devicePixelRatio;
	if(!screenRatio) screenRatio = 1;
	var virtWidth = owotWidth / screenRatio;
	if(chatWidth > virtWidth) {
		resizeChat(virtWidth - 2, chatHeight);
	}
});
elm.chat_page_tab click elm.chat_page_tab.classList.add("chat_tab_selected");

elm.chat_global_tab.classList.remove("chat_tab_selected");

elm.global_chatfield.style.display = "none";

elm.page_chatfield.style.display = "";

selectedChatTab = 0;

chatPageUnread = 0;

updateUnread();

if(!initPageTabOpen) {

initPageTabOpen = true;

elm.page_chatfield.scrollTop = elm.page_chatfield.scrollHeight;

}

elm.chat_page_tab.addEventListener("click", function() {
	elm.chat_page_tab.classList.add("chat_tab_selected");
	elm.chat_global_tab.classList.remove("chat_tab_selected");

	elm.global_chatfield.style.display = "none";
	elm.page_chatfield.style.display = "";
	selectedChatTab = 0;
	chatPageUnread = 0;
	updateUnread();
	if(!initPageTabOpen) {
		initPageTabOpen = true;
		elm.page_chatfield.scrollTop = elm.page_chatfield.scrollHeight;
	}
});
elm.chat_global_tab click elm.chat_global_tab.classList.add("chat_tab_selected");

elm.chat_page_tab.classList.remove("chat_tab_selected");

elm.global_chatfield.style.display = "";

elm.page_chatfield.style.display = "none";

selectedChatTab = 1;

chatGlobalUnread = 0;

updateUnread();

if(!initGlobalTabOpen) {

initGlobalTabOpen = true;

elm.global_chatfield.scrollTop = elm.global_chatfield.scrollHeight;

}

elm.chat_global_tab.addEventListener("click", function() {
	elm.chat_global_tab.classList.add("chat_tab_selected");
	elm.chat_page_tab.classList.remove("chat_tab_selected");

	elm.global_chatfield.style.display = "";
	elm.page_chatfield.style.display = "none";
	selectedChatTab = 1;
	chatGlobalUnread = 0;
	updateUnread();
	if(!initGlobalTabOpen) {
		initGlobalTabOpen = true;
		elm.global_chatfield.scrollTop = elm.global_chatfield.scrollHeight;
	}
});
chat_window mousemove if(isDown) return;

var posX = e.pageX - chat_window.offsetLeft;

var posY = e.pageY - chat_window.offsetTop;

var top = (posY) <= 4;

var left = (posX) <= 3;

var right = (chat_window.offsetWidth - posX) <= 4;

var bottom = (chat_window.offsetHeight - posY) <= 5;

var cursor = "";

if(left || right) cursor = "ew-resize";

if(top || bottom) cursor = "ns-resize";

if((top && left) || (right && bottom)) cursor = "nwse-resize";

if((bottom && left) || (top && right)) cursor = "nesw-resize";

chat_window.style.cursor = cursor;

state = bottom << 3 | right << 2 | left << 1 | top;

chat_window.addEventListener("mousemove", function(e) {
		if(isDown) return;
		var posX = e.pageX - chat_window.offsetLeft;
		var posY = e.pageY - chat_window.offsetTop;
		var top = (posY) <= 4;
		var left = (posX) <= 3;
		var right = (chat_window.offsetWidth - posX) <= 4;
		var bottom = (chat_window.offsetHeight - posY) <= 5;
		var cursor = "";
		if(left || right) cursor = "ew-resize";
		if(top || bottom) cursor = "ns-resize";
		if((top && left) || (right && bottom)) cursor = "nwse-resize";
		if((bottom && left) || (top && right)) cursor = "nesw-resize";
		chat_window.style.cursor = cursor;
		state = bottom << 3 | right << 2 | left << 1 | top;
	});
chat_window mousedown downX = e.pageX;

downY = e.pageY;

if(state) {

// subtract 2 for the borders

chatWidth = chat_window.offsetWidth - 2;

chatHeight = chat_window.offsetHeight - 2;

elmX = chat_window.offsetLeft;

elmY = chat_window.offsetTop;

isDown = true;

chatResizing = true;

}

chat_window.addEventListener("mousedown", function(e) {
		downX = e.pageX;
		downY = e.pageY;
		if(state) {
			// subtract 2 for the borders
			chatWidth = chat_window.offsetWidth - 2;
			chatHeight = chat_window.offsetHeight - 2;
			elmX = chat_window.offsetLeft;
			elmY = chat_window.offsetTop;
			isDown = true;
			chatResizing = true;
		}
	});
document mouseup isDown = false;

chatResizing = false;

document.addEventListener("mouseup", function() {
		isDown = false;
		chatResizing = false;
	});
document mousemove if(!isDown) return;

var offX = e.pageX - downX;

var offY = e.pageY - downY;

var resize_bottom = state >> 3 & 1;

var resize_right = state >> 2 & 1;

var resize_left = state >> 1 & 1;

var resize_top = state & 1;

var width_delta = 0;

var height_delta = 0;

var abs_top = chat_window.offsetTop;

var abs_left = chat_window.offsetLeft;

var snap_bottom = chat_window.style.bottom == "0px";

var snap_right = chat_window.style.right == "0px";

if(resize_top) {

height_delta = -offY;

} else if(resize_bottom) {

height_delta = offY;

}

if(resize_left) {

width_delta = -offX;

} else if(resize_right) {

width_delta = offX;

}

var res = resizeChat(chatWidth + width_delta, chatHeight + height_delta);

if(resize_top && !snap_bottom) {

chat_window.style.top = (elmY + (chatHeight - res[1])) + "px";

}

if(resize_bottom && snap_bottom) {

chat_window.style.bottom = "";

chat_window.style.top = abs_top + "px";

}

if(resize_right && snap_right) {

chat_window.style.right = "";

chat_window.style.left = abs_left + "px";

}

if(resize_left && !snap_right) {

chat_window.style.left = (elmX + (chatWidth - res[0])) + "px";

}

document.addEventListener("mousemove", function(e) {
		if(!isDown) return;
		var offX = e.pageX - downX;
		var offY = e.pageY - downY;
		var resize_bottom = state >> 3 & 1;
		var resize_right = state >> 2 & 1;
		var resize_left = state >> 1 & 1;
		var resize_top = state & 1;

		var width_delta = 0;
		var height_delta = 0;
		var abs_top = chat_window.offsetTop;
		var abs_left = chat_window.offsetLeft;
		var snap_bottom = chat_window.style.bottom == "0px";
		var snap_right = chat_window.style.right == "0px";

		if(resize_top) {
			height_delta = -offY;
		} else if(resize_bottom) {
			height_delta = offY;
		}
		if(resize_left) {
			width_delta = -offX;
		} else if(resize_right) {
			width_delta = offX;
		}
		var res = resizeChat(chatWidth + width_delta, chatHeight + height_delta);
		if(resize_top && !snap_bottom) {
			chat_window.style.top = (elmY + (chatHeight - res[1])) + "px";
		}
		if(resize_bottom && snap_bottom) {
			chat_window.style.bottom = "";
			chat_window.style.top = abs_top + "px";
		}
		if(resize_right && snap_right) {
			chat_window.style.right = "";
			chat_window.style.left = abs_left + "px";
		}
		if(resize_left && !snap_right) {
			chat_window.style.left = (elmX + (chatWidth - res[0])) + "px";
		}
	});

Functions

Name Description Example usage Related code
api_chat_send(message,opts) Sends a chat message from the user running code
api_chat_send("Hello!",{nick:"nickname"});
function api_chat_send(message, opts) {
	if(!message) return;
	if(!opts) opts = {};
	var exclude_commands = opts.exclude_commands;
	var nick = opts.nick || YourWorld.Nickname || state.userModel.username;
	var location = opts.location ? opts.location : (selectedChatTab == 0 ? "page" : "global");

	var msgLim = state.userModel.is_staff ? 3030 : 400;

	message = message.trim();
	if(!message.length) return;
	message = message.slice(0, msgLim);
	chatWriteHistory.push(message);
	if(chatWriteHistory.length > chatWriteHistoryMax) {
		chatWriteHistory.shift();
	}
	chatWriteHistoryIdx = -1;
	chatWriteTmpBuffer = "";

	var chatColor;
	if(!opts.color) {
		if(!YourWorld.Color) {
			chatColor = assignColor(nick);
		} else {
			chatColor = "#" + ("00000" + YourWorld.Color.toString(16)).slice(-6);
		}
	} else {
		chatColor = opts.color;
	}

	if(!exclude_commands && message.startsWith("/")) {
		var args = message.substr(1).split(" ");
		var command = args[0].toLowerCase();
		args.shift();
		if(client_commands.hasOwnProperty(command)) {
			client_commands[command](args);
			return;
		}
	}

	network.chat(message, location, nick, chatColor);
}
clientChatResponse(message) Creates a client-side message only visible to you
clientChatResponse("This is a client message.");
function clientChatResponse(message) {
	addChat(null, 0, "user", "[ Client ]", message, "Client", false, false, false, null, getDate());
}
sendChat() Sends whatever is in the chat textbox to chat.
sendChat();
function sendChat() {
	var chatText = elm.chatbar.value;
	elm.chatbar.value = "";
	var opts = {};
	if(defaultChatColor != null) {
		opts.color = "#" + ("00000" + defaultChatColor.toString(16)).slice(-6);
	}
	api_chat_send(chatText, opts);
}
updateUnread() Updates the unread messages counter when chat is closed.
function updateUnread() {
	var total = elm.total_unread;
	var page = elm.page_unread;
	var global = elm.global_unread;
	var totalCount = chatPageUnread + chatGlobalUnread;
	total.style.display = "none";
	global.style.display = "none";
	page.style.display = "none";
	if(totalCount) {
		total.style.display = "";
		total.innerText = totalCount > 99 ? "99+" : "(" + totalCount + ")";
	}
	if(chatPageUnread) {
		page.style.display = "";
		page.innerText = chatPageUnread > 99 ? "99+" : "(" + chatPageUnread + ")";
	}
	if(chatGlobalUnread) {
		global.style.display = "";
		global.innerText = chatGlobalUnread > 99 ? "99+" : "(" + chatGlobalUnread + ")";
	}
}
event_on_chat(data) Updates the unread messages counter for either global chat or the current page.
function event_on_chat(data) {
	if((!chatOpen || selectedChatTab == 1) && data.location == "page") {
		chatPageUnread++;
	}
	if((!chatOpen || selectedChatTab == 0) && data.location == "global" && !state.worldModel.no_chat_global) {
		chatGlobalUnread++;
	}
	updateUnread();
	addChat(data.location, data.id, data.type,
		data.nickname, data.message, data.realUsername, data.op, data.admin, data.staff, data.color, data.date || Date.now(), data.dataObj);
}
moveCaretEnd(elm) Moves the text cursor to the end of the chat message you want to type in the textbox.
function moveCaretEnd(elm) {
	if(elm.selectionStart != void 0) {
		elm.selectionStart = elm.value.length;
		elm.selectionEnd = elm.value.length;
	} else if(elm.createTextRange != void 0) {
		elm.focus();
		var range = elm.createTextRange();
		range.collapse(false);
		range.select();
	}
}
resizable_chat() Makes the chat resize on grabbing of corners or edges.
function resizable_chat() {
	var state = 0;
	var isDown = false;
	var downX = 0;
	var downY = 0;
	var elmX = 0;
	var elmY = 0;
	var chatWidth = 0;
	var chatHeight = 0;
	chat_window.addEventListener("mousemove", function(e) {
		if(isDown) return;
		var posX = e.pageX - chat_window.offsetLeft;
		var posY = e.pageY - chat_window.offsetTop;
		var top = (posY) <= 4;
		var left = (posX) <= 3;
		var right = (chat_window.offsetWidth - posX) <= 4;
		var bottom = (chat_window.offsetHeight - posY) <= 5;
		var cursor = "";
		if(left || right) cursor = "ew-resize";
		if(top || bottom) cursor = "ns-resize";
		if((top && left) || (right && bottom)) cursor = "nwse-resize";
		if((bottom && left) || (top && right)) cursor = "nesw-resize";
		chat_window.style.cursor = cursor;
		state = bottom << 3 | right << 2 | left << 1 | top;
	});
	chat_window.addEventListener("mousedown", function(e) {
		downX = e.pageX;
		downY = e.pageY;
		if(state) {
			// subtract 2 for the borders
			chatWidth = chat_window.offsetWidth - 2;
			chatHeight = chat_window.offsetHeight - 2;
			elmX = chat_window.offsetLeft;
			elmY = chat_window.offsetTop;
			isDown = true;
			chatResizing = true;
		}
	});
	document.addEventListener("mouseup", function() {
		isDown = false;
		chatResizing = false;
	});
	document.addEventListener("mousemove", function(e) {
		if(!isDown) return;
		var offX = e.pageX - downX;
		var offY = e.pageY - downY;
		var resize_bottom = state >> 3 & 1;
		var resize_right = state >> 2 & 1;
		var resize_left = state >> 1 & 1;
		var resize_top = state & 1;

		var width_delta = 0;
		var height_delta = 0;
		var abs_top = chat_window.offsetTop;
		var abs_left = chat_window.offsetLeft;
		var snap_bottom = chat_window.style.bottom == "0px";
		var snap_right = chat_window.style.right == "0px";

		if(resize_top) {
			height_delta = -offY;
		} else if(resize_bottom) {
			height_delta = offY;
		}
		if(resize_left) {
			width_delta = -offX;
		} else if(resize_right) {
			width_delta = offX;
		}
		var res = resizeChat(chatWidth + width_delta, chatHeight + height_delta);
		if(resize_top && !snap_bottom) {
			chat_window.style.top = (elmY + (chatHeight - res[1])) + "px";
		}
		if(resize_bottom && snap_bottom) {
			chat_window.style.bottom = "";
			chat_window.style.top = abs_top + "px";
		}
		if(resize_right && snap_right) {
			chat_window.style.right = "";
			chat_window.style.left = abs_left + "px";
		}
		if(resize_left && !snap_right) {
			chat_window.style.left = (elmX + (chatWidth - res[0])) + "px";
		}
	});
}

Variables

permissions.js

Variables

Name Description Related code
PERM Defines permission numbers for easier use instead of writing "Admin"
var PERM = {
	ADMIN: 2,
	MEMBERS: 1,
	PUBLIC: 0
};

Permissions

Since Permissions is a very long dictionary variable, this table is divided into specific definitions in it.

Name Description Related definition
can_admin Checks if user is an admin.
can_admin: function(user) {
		return user.is_owner;
	},
can_coordlink Checks if user can create coordinate links in the world they're in.
can_coordlink: function(user, world) {
		return Permissions.user_matches_perm(user, world, world.feature_coord_link);
	},
can_edit_tile Checks if user can write in a tile / character (protections).
can_edit_tile: function(user, world, tile, charX, charY) {
		if(!tile) {
			throw new Error("Can't check perms on un-initted tile");
		}
		if(!Permissions.can_read(user, world)) {
			return false;
		}
		var targetWritability;
		if(tile.char) {
			targetWritability = tile.char[charY * tileC + charX];
			if(targetWritability == null) targetWritability = tile.writability; // inherit from tile
			if(targetWritability == null) targetWritability = world.writability; // inherit from world
		} else {
			targetWritability = tile.writability;
			if(targetWritability == null) targetWritability = world.writability;
		}
		return Permissions.user_matches_perm(user, world, targetWritability);
	},
can_go_to_coord Checks if user can teleport.
can_go_to_coord: function(user, world) {
		return Permissions.user_matches_perm(user, world, world.feature_go_to_coord);
	},
can_paste Checks if user can paste.
can_paste: function(user, world) {
		return Permissions.user_matches_perm(user, world, world.feature_paste);
	},
can_copy Checks if user can copy.
can_copy: function(user, world) {
		if(user.is_owner || user.is_member) return true;
		return !world.no_copy;
	},
can_protect_tiles Checks if user can protect tiles.
can_protect_tiles: function(user, world) {
		if(user.is_owner) return true;
		return world.feature_membertiles_addremove && user.is_member;
	},
can_erase Checks if user can use the built-in eraser.
can_erase: function(user, world) {
		if(user.is_owner) return true;
		return Permissions.user_matches_perm(user, world, world.quick_erase);
	},
can_read Checks if user can view the world.
can_read: function(user, world) {
		return Permissions.user_matches_perm(user, world, world.readability);
	},
can_urllink Checks if user can create links leading to other URL's.
can_urllink: function(user, world) {
		return Permissions.user_matches_perm(user, world, world.feature_url_link);
	},
can_write Checks if user can write on the world.
can_write: function(user, world) {
		if(!Permissions.can_read(user, world)) {
			return false;
		}
		return Permissions.user_matches_perm(user, world, world.writability);
	},
can_chat Checks if user can chat.
can_chat: function(user, world) {
		return Permissions.user_matches_perm(user, world, world.chat_permission);
	},
can_show_cursor Checks if showing cursors is enabled for a user.
can_show_cursor: function(user, world) {
		return Permissions.user_matches_perm(user, world, world.show_cursor);
	},
can_color_text Checks if user can change their text colour.
can_color_text: function(user, world) {
		return Permissions.user_matches_perm(user, world, world.color_text);
	},
can_color_cell Checks if user can change their cell colour.
can_color_cell: function(user, world) {
		return Permissions.user_matches_perm(user, world, world.color_cell);
	},
user_matches_perm Gets users permissions.
user_matches_perm: function(user, world, perm) {
		if(perm == -1) { // no one
			return false;
		}
		if(perm == PERM.PUBLIC) { // anyone
			return true;
		}
		if(user.is_owner) {
			return true;
		}
		if(perm == PERM.ADMIN) {
			return false;
		}
		if(perm == PERM.MEMBERS && user.is_member) {
			return true;
		}
		return false;
	}
};