tool
extends WebNode
class_name WebPage, "res://addons/web_pages/icons/icon_web_page.svg"
export(bool) var sohuld_render_menu : bool = true
export(bool) var allow_web_interface_editing : bool = false
export(Array, Resource) var entries : Array
class WebPageEditCommand:
var method : StringName
var data : Array
var _pending_commands : Array = Array()
var _pending_array_mutex : Mutex = Mutex.new()
signal entries_changed()
func _handle_request(request : WebServerRequest):
if request.get_remaining_segment_count() > 0:
if allow_web_interface_editing:
if web_editor_try_handle(request):
return
for i in range(entries.size()):
var e : WebPageEntry = entries[i]
if e && e.handle_request(request):
return
request.send_error(404)
if sohuld_render_menu:
render_menu(request)
var should_render_edit_bar : bool = allow_web_interface_editing && (request.can_edit() || request.can_delete())
for i in range(entries.size()):
var e : WebPageEntry = entries[i]
if e:
if should_render_edit_bar:
e.render_edit_bar(request)
e.render(request)
if request.can_create():
var b : HTMLBuilder = HTMLBuilder.new()
b.div()
b.a(request.get_url_root_add("add")).f().w("+ Add New").ca()
b.cdiv()
request.body += b.result
request.compile_and_send_body()
func web_editor_try_handle(request : WebServerRequest) -> bool:
var path_segment : String = request.get_current_path_segment()
if path_segment == "add":
return web_editor_handle_add(request)
elif path_segment == "edit":
return web_editor_handle_edit(request)
elif path_segment == "move_up":
return web_editor_handle_move_up(request)
elif path_segment == "move_down":
return web_editor_handle_move_down(request)
elif path_segment == "delete":
return web_editor_handle_delete(request)
return false
func web_editor_handle_add(request : WebServerRequest) -> bool:
if !request.can_create():
return false
if request.get_method() == HTTPServerEnums.HTTP_METHOD_POST:
var t : String = request.get_parameter("type")
var entry : WebPageEntry = null
if !t.empty():
if t == "title_text":
entry = WebPageEntryTitleText.new()
elif t == "text":
entry = WebPageEntryText.new()
elif t == "image":
entry = WebPageEntryImage.new()
if entry:
add_entry_command(entry)
request.send_redirect(request.get_url_root())
return true
else:
request.body += "
Error processing your request!
"
else:
request.body += "Error processing your request!
"
if sohuld_render_menu:
render_menu(request)
var b : HTMLBuilder = HTMLBuilder.new()
b.div()
if true:
b.form_post(request.get_url_root_current())
b.csrf_tokenr(request)
b.input_hidden("type", "title_text")
b.input_submit("Create Title Text")
b.cform()
b.form_post(request.get_url_root_current())
b.csrf_tokenr(request)
b.input_hidden("type", "text")
b.input_submit("Create Text")
b.cform()
b.form_post(request.get_url_root_current())
b.csrf_tokenr(request)
b.input_hidden("type", "image")
b.input_submit("Create Image")
b.cform()
b.cdiv()
request.body += b.result
request.compile_and_send_body()
return true
func web_editor_handle_edit(request : WebServerRequest) -> bool:
if !request.can_edit():
return false
if request.get_remaining_segment_count() < 1:
return false
request.push_path()
var resource_id_str : String = request.get_current_path_segment()
if resource_id_str.empty() || !resource_id_str.is_valid_integer():
request.send_error(404)
return true
var resource_id : int = resource_id_str.to_int()
var entry : WebPageEntry = get_entry_with_id(resource_id)
if !entry:
request.send_error(404)
return true
request.push_path()
entry.handle_edit(request)
return true
func web_editor_handle_move_up(request : WebServerRequest) -> bool:
if !request.can_edit():
return false
if request.get_remaining_segment_count() < 1:
return false
request.push_path()
var resource_id_str : String = request.get_current_path_segment()
if resource_id_str.empty() || !resource_id_str.is_valid_integer():
request.send_error(404)
return true
var resource_id : int = resource_id_str.to_int()
var entry : WebPageEntry = get_entry_with_id(resource_id)
if !entry:
request.send_error(404)
return true
move_entry_up_command(entry)
request.send_redirect(request.get_url_root_parent(1))
return true
func web_editor_handle_move_down(request : WebServerRequest) -> bool:
if !request.can_edit():
return false
if request.get_remaining_segment_count() < 1:
return false
request.push_path()
var resource_id_str : String = request.get_current_path_segment()
if resource_id_str.empty() || !resource_id_str.is_valid_integer():
request.send_error(404)
return true
var resource_id : int = resource_id_str.to_int()
var entry : WebPageEntry = get_entry_with_id(resource_id)
if !entry:
request.send_error(404)
return true
move_entry_down_command(entry)
request.send_redirect(request.get_url_root_parent(1))
return true
func web_editor_handle_delete(request : WebServerRequest) -> bool:
if !request.can_delete():
return false
if request.get_remaining_segment_count() < 1:
return false
request.push_path()
var resource_id_str : String = request.get_current_path_segment()
if resource_id_str.empty() || !resource_id_str.is_valid_integer():
request.send_error(404)
return true
var resource_id : int = resource_id_str.to_int()
var entry : WebPageEntry = get_entry_with_id(resource_id)
if !entry:
request.send_error(404)
return true
if request.get_method() == HTTPServerEnums.HTTP_METHOD_POST:
var accept : String = request.get_parameter("accept")
if accept == "TRUE":
remove_entry_command(entry)
request.send_redirect(request.get_url_root_parent())
return true
else:
request.body += "Error processing your request!
"
if sohuld_render_menu:
render_menu(request)
var b : HTMLBuilder = HTMLBuilder.new()
b.div()
if true:
entry.render(request)
b.form_post(request.get_url_root_current())
b.w("Are you sure you want to delete?")
b.csrf_tokenr(request)
b.input_hidden("accept", "TRUE")
b.input_submit("Delete")
b.cform()
b.cdiv()
request.body += b.result
request.compile_and_send_body()
return true
func create_entry(cls_name : String) -> WebPageEntry:
return _create_entry(cls_name)
func _create_entry(cls_name : String) -> WebPageEntry:
var entry : WebPageEntry = null
if cls_name == "WebPageEntryTitleText":
entry = WebPageEntryTitleText.new()
elif cls_name == "WebPageEntryText":
entry = WebPageEntryText.new()
elif cls_name == "WebPageEntryImage":
entry = WebPageEntryImage.new()
if !entry:
PLogger.log_error("PageEditor: Couldn't create entry for: " + cls_name)
return entry
func get_next_id() -> int:
var id : int = 0
for i in range(entries.size()):
var e : WebPageEntry = entries[i]
if e:
if e.id > id:
id = e.id
return id + 1
func add_entry_command(var entry : WebPageEntry, var after : WebPageEntry = null) -> void:
var command : WebPageEditCommand = WebPageEditCommand.new()
command.method = "add_entry"
command.data.push_back(entry)
command.data.push_back(after)
var request_write_lock : bool = false
_pending_array_mutex.lock()
_pending_commands.push_back(command)
if _pending_commands.size() == 1:
request_write_lock = true
_pending_array_mutex.unlock()
if request_write_lock:
request_write_lock()
func remove_entry_command(var entry : WebPageEntry) -> void:
var command : WebPageEditCommand = WebPageEditCommand.new()
command.method = "remove_entry"
command.data.push_back(entry)
var request_write_lock : bool = false
_pending_array_mutex.lock()
_pending_commands.push_back(command)
if _pending_commands.size() == 1:
request_write_lock = true
_pending_array_mutex.unlock()
if request_write_lock:
request_write_lock()
func move_entry_up_command(var entry : WebPageEntry) -> void:
var command : WebPageEditCommand = WebPageEditCommand.new()
command.method = "move_entry_up"
command.data.push_back(entry)
var request_write_lock : bool = false
_pending_array_mutex.lock()
_pending_commands.push_back(command)
if _pending_commands.size() == 1:
request_write_lock = true
_pending_array_mutex.unlock()
if request_write_lock:
request_write_lock()
func move_entry_down_command(var entry : WebPageEntry) -> void:
var command : WebPageEditCommand = WebPageEditCommand.new()
command.method = "move_entry_down"
command.data.push_back(entry)
var request_write_lock : bool = false
_pending_array_mutex.lock()
_pending_commands.push_back(command)
if _pending_commands.size() == 1:
request_write_lock = true
_pending_array_mutex.unlock()
if request_write_lock:
request_write_lock()
func edit_entry_command(var entry : WebPageEntry, var data : WebPageEntry) -> void:
var command : WebPageEditCommand = WebPageEditCommand.new()
command.method = "replace_entry"
command.data.push_back(entry)
command.data.push_back(data)
var request_write_lock : bool = false
_pending_array_mutex.lock()
_pending_commands.push_back(command)
if _pending_commands.size() == 1:
request_write_lock = true
_pending_array_mutex.unlock()
if request_write_lock:
request_write_lock()
func add_entry(var entry : WebPageEntry, var after : WebPageEntry = null) -> void:
var id : int = get_next_id()
entry.id = id
if after != null:
for i in range(entries.size()):
if entries[i] == after:
entries.insert(i + 1, entry)
break
else:
entries.push_back(entry)
if !entry.is_connected("changed", self, "_on_entry_changed"):
entry.connect("changed", self, "_on_entry_changed")
on_entries_changed()
func get_entry_with_index(index : int) -> WebPageEntry:
if index < 0 || index >= entries.size():
return null
return entries[index]
func get_entry_with_id(id : int) -> WebPageEntry:
for i in range(entries.size()):
var e : WebPageEntry = entries[i]
if e:
if (e.id == id):
return e
return null
func remove_entry(var entry : WebPageEntry) -> void:
if entry && !entry.is_connected("changed", self, "_on_entry_changed"):
entry.connect("changed", self, "_on_entry_changed")
entries.erase(entry)
on_entries_changed()
func move_entry_up(var entry : WebPageEntry) -> void:
# Skips checking the first entry (1, entries.size())
for i in range(1, entries.size()):
if entries[i] == entry:
entries[i] = entries[i - 1]
entries[i - 1] = entry
on_entries_changed()
return
func move_entry_down(var entry : WebPageEntry) -> void:
# Skips checking the last entry (size() - 1)
for i in range(entries.size() - 1):
if entries[i] == entry:
entries[i] = entries[i + 1]
entries[i + 1] = entry
on_entries_changed()
return
func get_entry_before(var entry : WebPageEntry) -> WebPageEntry:
if entries.size() < 2:
return null
if entries[0] == entry:
return null
for i in range(1, entries.size()):
if entries[i] == entry:
return entries[i - 1]
return null
func replace_entry(var entry : WebPageEntry, var data : WebPageEntry) -> void:
for i in range(entries.size()):
if entries[i] == entry:
if entry && entry.is_connected("changed", self, "_on_entry_changed"):
entry.disconnect("changed", self, "_on_entry_changed")
entries[i] = data
if data && !data.is_connected("changed", self, "_on_entry_changed"):
data.connect("changed", self, "_on_entry_changed")
on_entries_changed()
return
func _notification(what):
if what == NOTIFICATION_READY:
if !Engine.editor_hint:
for i in range(entries.size()):
var e : WebPageEntry = entries[i]
if e && !e.is_connected("changed", self, "_on_entry_changed"):
e.connect("changed", self, "_on_entry_changed")
elif what == NOTIFICATION_WEB_NODE_WRITE_LOCKED:
if !Engine.editor_hint:
_pending_array_mutex.lock()
for i in range(_pending_commands.size()):
var e : WebPageEditCommand = _pending_commands[i] as WebPageEditCommand
callv(e.method, e.data)
_pending_commands.clear()
_pending_array_mutex.unlock()
func _on_entry_changed():
on_entries_changed()
func on_entries_changed():
emit_signal("entries_changed")