بنقرة واحدة
javascript
// JavaScript coding standards for SceneScape — code style, conventions, and frontend patterns.
// JavaScript coding standards for SceneScape — code style, conventions, and frontend patterns.
Runtime test verification gate for SceneScape — image freshness checks, rebuild-before-test requirements, and retry policy.
Guide for creating SceneScape test cases — unit, functional, integration, UI, and smoke tests with positive and negative cases.
Procedures for updating SceneScape documentation — where to make changes and what to update for each type of modification.
Makefile standards for SceneScape — build targets, conventions, and patterns.
Python coding standards for SceneScape — imports, indentation, patterns, and conventions.
On-demand security review skill for SceneScape — code and configuration security guidance.
| name | javascript |
| description | JavaScript coding standards for SceneScape — code style, conventions, and frontend patterns. |
.github/resources/eslint.config.js).github/resources/.prettierrc.json)make lint-javascript # Run ESLint
make prettier-write # Auto-format all code
make prettier-check # Check formatting
PascalCase (e.g., MapboxPlugin, GoogleMapsPlugin, MapInterface)camelCase (e.g., generateSnapshot, saveSnapshotToServer)UPPER_SNAKE_CASE (e.g., DEFAULT_ZOOM, MAP_CENTER)camelCase (e.g., sceneData, cameraList)_ (convention only, not enforced)SceneScape uses ES6 classes for map plugins and UI components:
class MapboxPlugin extends MapInterface {
constructor() {
super();
this.map = null;
this.accessToken = null;
}
async initialize(containerId, config = {}) {
// Implementation
}
generateSnapshot() {
// Implementation
}
}
Map providers implement a common interface:
class MapInterface {
async initialize(containerId, config) {}
moveToLocation(input) {}
generateBounds() {}
generateSnapshot() {}
getBounds() {}
getCenter() {}
getZoom() {}
}
Prefer async/await over promises for readability:
// Good
async function fetchSceneData(sceneId) {
try {
const response = await fetch(`/api/v1/scenes/${sceneId}/`);
const data = await response.json();
return data;
} catch (error) {
console.error("Failed to fetch scene:", error);
return null;
}
}
// Avoid
function fetchSceneData(sceneId) {
return fetch(`/api/v1/scenes/${sceneId}/`)
.then((response) => response.json())
.catch((error) => console.error(error));
}
SceneScape uses jQuery for DOM manipulation:
$(document).ready(function () {
$("#login-submit").on("click", handleLogin);
$(".roi-color").each(function () {
// Process each element
});
});
// Attach handlers
$("#button-id").on("click", function (event) {
event.preventDefault();
// Handle click
});
// Delegate for dynamic elements
$(document).on("click", ".dynamic-class", function () {
// Handle click on dynamically added elements
});
// By ID
const element = document.getElementById("map");
const $element = $("#map");
// By class
const elements = document.querySelectorAll(".roi-item");
const $elements = $(".roi-item");
async function saveData(data) {
const csrfToken = document.querySelector("[name=csrfmiddlewaretoken]");
const response = await fetch("/api/v1/endpoint/", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-CSRFToken": csrfToken.value,
},
body: JSON.stringify(data),
});
if (response.ok) {
const result = await response.json();
return result;
} else {
console.error("Request failed:", response.status);
return null;
}
}
const formData = new FormData();
formData.append("image_data", imageData);
formData.append("csrfmiddlewaretoken", csrfToken.value);
const response = await fetch("/api/v1/save-snapshot/", {
method: "POST",
headers: {
"X-CSRFToken": csrfToken.value,
},
body: formData,
});
async function processOperation() {
try {
const result = await riskyOperation();
console.log("Success:", result);
return result;
} catch (error) {
console.error("Operation failed:", error);
showErrorMessage(error.message);
return null;
}
}
// Good - early return
function processScene(scene) {
if (!scene) {
console.error("Scene is null");
return;
}
// Process scene
}
// Good - optional chaining
const cameraCount = scene?.cameras?.length ?? 0;
const canvas = document.createElement("canvas");
canvas.width = 1280;
canvas.height = 1280;
const ctx = canvas.getContext("2d");
// Draw image
ctx.drawImage(image, 0, 0);
// Get base64 data
const imageData = canvas.toDataURL("image/png");
// Create SVG element
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
svg.setAttribute("width", "100");
svg.setAttribute("height", "100");
// Add to DOM
$("#svgout").append(svg);
// Debug information
console.log("Processing scene:", sceneId);
// Warnings
console.warn("Camera not found:", cameraId);
// Errors
console.error("Failed to load scene:", error);
// Structured data
console.log("Response:", { status, data, timestamp });
Remove or guard verbose logging in production code:
if (DEBUG_MODE) {
console.log("Detailed debug info:", debugData);
}
/**
* Generate a snapshot of the current map view
* @returns {Promise<string>} Base64-encoded image data
*/
async function generateSnapshot() {
// Implementation
}
// Hide map controls before screenshot
const style = document.createElement("style");
style.textContent = `...`;
// Process each ROI point
points.forEach((point, index) => {
// Transform coordinates to map space
const transformed = transformPoint(point);
});
// Show
$("#element").show();
$("#element").css("display", "block");
// Hide
$("#element").hide();
$("#element").css("display", "none");
$("#element").addClass("active");
$("#element").removeClass("disabled");
$("#element").toggleClass("selected");
// Text
$("#message").text("Operation complete");
// HTML
$("#container").html("<div>New content</div>");
// Attributes
$("#image").attr("src", imageUrl);
// Fade in/out
$("#element").fadeIn(300);
$("#element").fadeOut(300);
// Scroll into view
element.scrollIntoView({ behavior: "smooth" });
mapboxgl.accessToken = apiKey;
const map = new mapboxgl.Map({
container: "map",
style: "mapbox://styles/mapbox/satellite-v9",
center: [lng, lat],
zoom: 15,
});
const map = new google.maps.Map(document.getElementById("map"), {
center: { lat, lng },
zoom: 15,
mapTypeId: "satellite",
});
manager/src/static/js/
├── geospatial/
│ ├── mapbox-plugin.js
│ ├── google-maps-plugin.js
│ └── map-interface.js
└── sscape.js
Scripts are loaded via Django templates:
{% load static %}
<script src="{% static 'js/sscape.js' %}"></script>
<script src="{% static 'js/geospatial/mapbox-plugin.js' %}"></script>
❌ Don't use var:
// Bad
var count = 0;
// Good
const count = 0;
let counter = 0;
❌ Don't modify global scope unnecessarily:
// Bad
window.myGlobalVar = "value";
// Good - use module pattern or classes
const MyModule = {
value: "value",
};
❌ Don't use == for comparisons:
// Bad
if (value == null) {
}
// Good
if (value === null) {
}
if (value == null) {
} // OK only for null/undefined check
❌ Don't create functions in loops:
// Bad
for (let i = 0; i < items.length; i++) {
$("#item-" + i).on("click", function () {
process(i); // i will be wrong
});
}
// Good
items.forEach((item, index) => {
$(`#item-${index}`).on("click", () => process(index));
});
defer// Cache selector
const $container = $("#container");
$container.addClass("active");
$container.append(element);
// Don't repeat
$("#container").addClass("active");
$("#container").append(element);