Browse Source

web完整功能第一版

zfbox
张龙 8 months ago
parent
commit
a3a5b921ca
  1. 2
      .idea/FristProject.iml
  2. 9
      .idea/deployment.xml
  3. 2
      .idea/misc.xml
  4. 9
      config.yaml
  5. 121
      core/CapManager.py
  6. 122
      core/ChannelManager.py
  7. 101
      core/DBManager.py
  8. 243
      core/ModelManager.py
  9. 122
      core/Upload_file.py
  10. 204
      model/ModelManager.py
  11. 9
      model/plugins/AQM_Model.py
  12. 59
      model/plugins/ModelBase.py
  13. 8
      model/plugins/RYRQ/RYRQ_Model.py
  14. 32
      model/plugins/RYRQ_ACL/RYRQ_Model_ACL.py
  15. 155
      model/plugins/yolov5-1.py
  16. 64
      model/weights/yolov5-1/yoloV5.py
  17. 300
      myutils/IPManager.py
  18. 13
      run.py
  19. BIN
      uploads/8.zip
  20. 213
      web/API/channel.py
  21. 198
      web/API/model.py
  22. 22
      web/API/system.py
  23. 41
      web/API/user.py
  24. 115
      web/API/viedo.py
  25. BIN
      web/main/static/resources/chrome/allow-access.png
  26. BIN
      web/main/static/resources/chrome/axure-chrome-extension.crx
  27. BIN
      web/main/static/resources/chrome/axure_logo.png
  28. 187
      web/main/static/resources/chrome/chrome.html
  29. BIN
      web/main/static/resources/chrome/details.png
  30. BIN
      web/main/static/resources/chrome/extensions.png
  31. 130
      web/main/static/resources/chrome/firefox.html
  32. BIN
      web/main/static/resources/chrome/preview-rp.png
  33. 155
      web/main/static/resources/chrome/safari.html
  34. BIN
      web/main/static/resources/chrome/safari_advanced.png
  35. BIN
      web/main/static/resources/chrome/safari_restrictions.png
  36. BIN
      web/main/static/resources/chrome/splitter.gif
  37. BIN
      web/main/static/resources/chrome/splitter.png
  38. 49
      web/main/static/resources/scripts/aiortc-client-new.js
  39. 2115
      web/main/static/resources/scripts/axure/action.js
  40. 771
      web/main/static/resources/scripts/axure/adaptive.js
  41. 178
      web/main/static/resources/scripts/axure/annotation.js
  42. 407
      web/main/static/resources/scripts/axure/axQuery.js
  43. 1864
      web/main/static/resources/scripts/axure/axQuery.std.js
  44. 900
      web/main/static/resources/scripts/axure/doc.js
  45. 278
      web/main/static/resources/scripts/axure/drag.js
  46. 1996
      web/main/static/resources/scripts/axure/events.js
  47. 579
      web/main/static/resources/scripts/axure/expr.js
  48. 286
      web/main/static/resources/scripts/axure/flyout.js
  49. 294
      web/main/static/resources/scripts/axure/geometry.js
  50. 7
      web/main/static/resources/scripts/axure/globals.js
  51. 344
      web/main/static/resources/scripts/axure/ie.js
  52. 326
      web/main/static/resources/scripts/axure/init.temp.js
  53. 91
      web/main/static/resources/scripts/axure/ios.js
  54. 1
      web/main/static/resources/scripts/axure/jquery.nicescroll.min.js
  55. 166
      web/main/static/resources/scripts/axure/legacy.js
  56. 554
      web/main/static/resources/scripts/axure/math.js
  57. 53
      web/main/static/resources/scripts/axure/model.js
  58. 467
      web/main/static/resources/scripts/axure/move.js
  59. 94
      web/main/static/resources/scripts/axure/recording.js
  60. 2413
      web/main/static/resources/scripts/axure/repeater.js
  61. 241
      web/main/static/resources/scripts/axure/sto.js
  62. 1389
      web/main/static/resources/scripts/axure/style.js
  63. 189
      web/main/static/resources/scripts/axure/tree.js
  64. 99
      web/main/static/resources/scripts/axure/utils.temp.js
  65. 136
      web/main/static/resources/scripts/axure/variables.js
  66. 268
      web/main/static/resources/scripts/axure/viewer.js
  67. 1315
      web/main/static/resources/scripts/axure/visibility.js
  68. 48
      web/main/static/resources/scripts/base.js
  69. 375
      web/main/static/resources/scripts/channel_manager.js
  70. 303
      web/main/static/resources/scripts/model_manager.js
  71. 2631
      web/main/static/resources/scripts/player/axplayer.js
  72. 18
      web/main/static/resources/scripts/player/init.js
  73. 219
      web/main/static/resources/scripts/player/splitter.js
  74. 440
      web/main/static/resources/scripts/system_manager.js
  75. 48
      web/main/static/resources/scripts/user_manager.js
  76. 32
      web/main/templates/base.html
  77. 36
      web/main/templates/channel_manager.html
  78. 10
      web/main/templates/header.html
  79. 145
      web/main/templates/model_manager.html
  80. 156
      web/main/templates/schedule.html
  81. 286
      web/main/templates/system_manager.html
  82. 48
      web/main/templates/user_manager.html
  83. 367
      web/main/templates/实时预览.html
  84. 1412
      web/main/templates/通道管理.html
  85. BIN
      zfbox.db

2
.idea/FristProject.iml

@ -2,7 +2,7 @@
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="jdk" jdkName="acl392" jdkType="Python SDK" />
<orderEntry type="jdk" jdkName="Remote Python 3.9.2 (sftp://root@192.168.3.103:22/usr/local/miniconda3/bin/python)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

9
.idea/deployment.xml

@ -1,7 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PublishConfigData" autoUpload="Always" serverName="root@192.168.3.48:22" remoteFilesAllowedToDisappearOnAutoupload="false">
<component name="PublishConfigData" autoUpload="Always" serverName="root@192.168.3.103:22" remoteFilesAllowedToDisappearOnAutoupload="false">
<serverData>
<paths name="root@192.168.3.103:22">
<serverdata>
<mappings>
<mapping deploy="/mnt/zfbox" local="$PROJECT_DIR$" />
</mappings>
</serverdata>
</paths>
<paths name="root@192.168.3.48:22">
<serverdata>
<mappings>

2
.idea/misc.xml

@ -3,7 +3,7 @@
<component name="Black">
<option name="sdkName" value="PyTorch" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="acl392" project-jdk-type="Python SDK" />
<component name="ProjectRootManager" version="2" project-jdk-name="Remote Python 3.9.2 (sftp://root@192.168.3.103:22/usr/local/miniconda3/bin/python)" project-jdk-type="Python SDK" />
<component name="PyCharmProfessionalAdvertiser">
<option name="shown" value="true" />
</component>

9
config.yaml

@ -23,15 +23,16 @@ pw: zfkj_123!@#
MAX_CONTENT_LENGTH : 100 # 100MB
UPLOAD_FOLDER : uploads
ALLOWED_EXTENSIONS : {'zip'}
Model_Plugins: model/plugins
#RTSP
RTSP_Check_Time : 600 #10分钟 -- 2024-7-8 取消使用
#max_channel_num
max_channel_num : 4 #最大视频通道数量
max_channel_num : 8 #最大视频通道数量
#model
model_platform : cpu #acl gpu cpu
model_platform : acl #acl gpu cpu
device_id : 0 #单设备配置
weight_path: /model/weights
yolov5_path: D:/Project/FristProject/model/base_model/yolov5 #使用绝对路径,不同的部署环境需要修改!
@ -43,3 +44,7 @@ verify_rate : 8 #验证帧率--- 也就是视频输出的帧率
warn_video_path: /mnt/zfbox/model/warn/
warn_interval: 120 #报警间隔--单位秒
video_error_count: 3 #单位秒 ---根据验证帧率,判断3秒内都是空帧的话,视频源链接有问题。
#system --- 指定网卡
wired_interface : eth0
wireless_interface : WLAN

121
core/CapManager.py

@ -0,0 +1,121 @@
import math
import queue
import cv2
import threading
import time
from myutils.ConfigManager import myCongif
import subprocess as sp
class VideoCaptureWithFPS:
'''视频捕获的封装类,是一个通道一个'''
def __init__(self, source):
self.source = source
self.width = None
self.height = None
# GStreamer --- 内存占用太高,且工作环境的部署也不简单
# self.pipeline = (
# "rtspsrc location=rtsp://192.168.3.102/live1 protocols=udp latency=100 ! "
# "rtph264depay !"
# " h264parse !"
# " avdec_h264 !"
# " videoconvert !"
# " appsink"
# )
#self.cap = cv2.VideoCapture(self.pipeline, cv2.CAP_GSTREAMER)
#FFmpeg --更加定制化的使用--但要明确宽高。。。
# self.ffmpeg_cmd = [
# 'ffmpeg',
# '-rtsp_transport', 'udp',
# '-i', 'rtsp://192.168.3.102/live1',
# '-f', 'image2pipe',
# '-pix_fmt', 'bgr24',
# '-vcodec', 'rawvideo', '-'
# ]
# self.pipe = sp.Popen(self.ffmpeg_cmd, stdout=sp.PIPE, bufsize=10 ** 8)
# opencv -- 后端默认使用的就是FFmpeg -- 不支持UDP
self.cap = cv2.VideoCapture(self.source)
if self.cap.isOpened(): #若没有打开成功,在读取画面的时候,已有判断和处理 -- 这里也要检查下内存的释放情况
self.width = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
self.height = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
print(self.width,self.height)
#self.fps = fps # 线程保持最大帧率的刷新画面---过高的帧率会影响CPU性能,但过地的帧率会造成帧积压
self.fps = math.ceil(self.cap.get(cv2.CAP_PROP_FPS)/float(myCongif.get_data("verify_rate")))-1 #向上取整。
#print(self.fps)
self.running = True
self.frame_queue = queue.Queue(maxsize=1)
#self.frame = None
#self.read_lock = threading.Lock()
self.thread = threading.Thread(target=self.update)
self.thread.start()
def update(self):
icount = 0
while self.running:
ret, frame = self.cap.read()
if not ret:
icount += 1
if icount > 5: #重连
self.cap.release()
self.cap = cv2.VideoCapture(self.source)
#self.cap = cv2.VideoCapture(self.pipeline, cv2.CAP_GSTREAMER)
if self.cap.isOpened():
self.width = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
self.height = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
print(self.width,self.height)
# self.fps = fps # 线程保持最大帧率的刷新画面---过高的帧率会影响CPU性能,但过地的帧率会造成帧积压
self.fps = math.ceil(
self.cap.get(cv2.CAP_PROP_FPS) / float(myCongif.get_data("verify_rate"))) -1 # 向上取整。
icount = 0
else:
#self.frame = None
sleep_time = myCongif.get_data("cap_sleep_time")
print(f"{self.source}视频流,将于{sleep_time}秒后重连!")
time.sleep(sleep_time)
continue
#resized_frame = cv2.resize(frame, (int(self.width / 2), int(self.height / 2)))
# with self.read_lock:
# self.frame = frame
if self.frame_queue.full():
try:
#print("采集线程丢帧")
self.frame_queue.get(timeout=0.01) #这里不get的好处是,模型线程不会有None
except queue.Empty: #为空不处理
pass
self.frame_queue.put(frame)
# 跳过指定数量的帧以避免积压
for _ in range(self.fps):
self.cap.grab()
# time.sleep(self.fps) #按照视频源的帧率进行休眠
#print("Frame updated at:",time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
def read(self):
'''
直接读视频原画面
:param type: 0-大多数情况读取1-绘制区域时读取一帧但当前帧不丢还是回队列
:return:
'''
# with self.read_lock:
# frame = self.frame.copy() if self.frame is not None else None
# if frame is not None:
# return True, frame
# else:
# return False, None
if not self.frame_queue.empty():
try:
frame = self.frame_queue.get(timeout=0.05)
except queue.Empty:
#print("cap-frame None")
return False, None
else:
#print("cap-frame None")
return False, None
return True, frame
def release(self):
self.running = False
self.thread.join()
self.cap.release()

122
core/ChannelManager.py

@ -4,19 +4,25 @@ import numpy as np
import time
import copy
import queue
import cv2
import asyncio
class ChannelData:
def __init__(self, str_url, int_type, bool_run, deque_length,icount_max):
self.cap = None
self.cap = None #该通道视频采集对象
self.work_th = None #该通道工作线程句柄
self.b_model = False #是否有运行模型线程
self.bool_run = bool_run # 线程运行标识
self.str_url = str_url #视频源地址
self.int_type = int_type #视频源类型,0-usb,1-rtsp,2-hksdk
self.bool_run = bool_run #线程运行标识
self.deque_frame = deque(maxlen=deque_length)
self.icount_max = icount_max # 帧序列号上限
self.lock = threading.RLock() # 用于保证线程安全
self.deque_frame = deque(maxlen=deque_length) #视频缓冲区用于保存录像
self.last_frame = None # 保存图片数据
self.frame_queue = queue.Queue(maxsize=1)
self.counter = 0 #帧序列号--保存报警录像使用
self.icount_max = icount_max #帧序列号上限
self.lock = threading.RLock() # 用于保证线程安全
#添加一帧图片
def add_deque(self, value):
@ -28,26 +34,53 @@ class ChannelData:
#获取最后一帧图片
def get_last_frame(self):
with self.lock:
frame = self.last_frame
return frame
# if not self.frame_queue.empty():
# return self.frame_queue.get()
# else:
# return None
if self.b_model:
# with self.lock:
# frame = self.last_frame
# return frame
#if not self.frame_queue.empty():
try:
frame = self.frame_queue.get(timeout=0.3) #web传输没有做帧率控制了,可以超时时间长一点
except queue.Empty:
print("channel--frame None")
return None
# else:
# return None
return frame
else: #如果没有运行,直接从cap获取画面
if self.cap:
ret, frame = self.cap.read() # 除了第一帧,其它应该都是有画面的
if not ret:
print("channel--frame None")
return None
ret, frame_bgr_webp = cv2.imencode('.jpg', frame)
if not ret:
buffer_bgr_webp = None
else:
buffer_bgr_webp = frame_bgr_webp.tobytes()
return buffer_bgr_webp
return None
def update_last_frame(self,buffer):
if buffer:
with self.lock:
self.last_frame = None
self.last_frame = buffer
# if not self.frame_queue.full():
# self.frame_queue.put(buffer)
# else:
# self.frame_queue.get() # 丢弃最旧的帧
# self.frame_queue.put(buffer)
# with self.lock:
# self.last_frame = None
# self.last_frame = buffer
# if self.frame_queue.full():
# try:
# print("channel--丢帧")
# self.frame_queue.get(timeout=0.01)
# except queue.Empty: #为空不处理
# pass
# self.frame_queue.put(buffer)
try:
self.frame_queue.put(buffer,timeout=0.05)
except queue.Full:
#print("channel--未插入")
pass
#帧序列号自增 一个线程中处理,不用加锁
def increment_counter(self):
@ -58,13 +91,22 @@ class ChannelData:
def get_counter(self):
return self.counter
#清空数据,主要是删除deque 和 last_frame
#清空数据,停止工作线程(若有 ,并删除deque 和 last_frame)
def clear(self):
start_time = time.time()
with self.lock:
self.bool_run = False
time.sleep(1) #休眠一秒,等待通道对应的子线程,停止工作。
self.deque_frame.clear()
self.last_frame = None
if self.b_model: #b_model为true,说明开启了工作线程
self.bool_run = False
self.work_th.join() #等待通道对应的子线程,停止工作。
#time.sleep(1)
self.deque_frame.clear()
self.last_frame = None #二选一
self.frame_queue = queue.Queue(maxsize=1) #二选一
self.counter = 0
end_time = time.time()
execution_time = end_time - start_time
print(f"停止一个通道线程,花费了: {execution_time} seconds")
def stop_run(self):
self.bool_run = False
@ -73,11 +115,11 @@ class ChannelData:
class ChannelManager:
def __init__(self):
self.channels = {}
self.lock = threading.RLock() # 用于保证字典操作的线程安全
self.cm_lock = threading.RLock() # 用于保证字典操作的线程安全
#增加节点
def add_channel(self, channel_id, str_url, int_type, bool_run, deque_length=10,icount_max=100000):
with self.lock:
with self.cm_lock:
if channel_id in self.channels: #若已经有数据,先删除后再增加
self.channels[channel_id].clear() # 手动清理资源
del self.channels[channel_id]
@ -86,29 +128,33 @@ class ChannelManager:
return ch_data
#删除节点
def delete_channel(self, channel_id):
with self.lock:
def delete_channel(self, channel_id): #需要验证资源的释放清空
with self.cm_lock:
if channel_id in self.channels:
self.channels[channel_id].clear() # 手动清理资源
self.channels[channel_id].cap.release()
del self.channels[channel_id]
#获取节点
def get_channel(self, channel_id):
with self.lock:
with self.cm_lock:
return self.channels.get(channel_id)
#停止工作线程---要把视频采集线程停止掉
def stop_channel(self,channel_id):
with self.lock:
with self.cm_lock:
if channel_id == 0:
for clannel_id,clannel_data in self.channels.items():
clannel_data.cap.running = False
clannel_data.clear() #clear 里面已经停止了通道的工作线程
del self.channels
# for clannel_id,clannel_data in self.channels.items():
# clannel_data.clear()
for clannel_data in self.channels:
clannel_data.clear() #停止工作线程,并清空业务数据
clannel_data.cap.release() #停止视频采集线程,并是否采集资源
self.channels.clear() #清空整个字典
else:
if channel_id in self.channels:
self.channels[channel_id].cap.running = False
self.channels[channel_id].clear() # 手动清理资源
self.channels[channel_id].cap.release()
del self.channels[channel_id]
if __name__ == "__main__":

101
core/DBManager.py

@ -108,31 +108,31 @@ class DBManager():
'''
#根据通道ID或者模型ID删除通道和模型间的关联数据 1-通道ID,2-模型ID ,注意会有删除没有数据的情况
:param ID:
:param itype:
:return:
:param itype:1-通道ID2-模型ID
:return: 删除数据库记录没做特别的判断
'''
#channel2model
col_name = ""
if itype ==1:
strsql = f"select ID from channel2model where channel_id={ID};"
datas = self.do_select(strsql)
strsql = f"delete from channel2model where channel_id={ID};"
ret = self.do_sql(strsql)
col_name = "channel_id"
elif itype ==2:
strsql = f"select ID from channel2model where model_id={ID};"
datas = self.do_select(strsql)
strsql = f"delete from channel2model where model_id={ID};"
ret = self.do_sql(strsql)
col_name = "model_id"
else:
return False
#schedule
for data in datas:
return False
strsql = f"select ID from channel2model where {col_name}={ID};"
data = self.do_select(strsql,1)
if data:
c2m_id = data[0]
strsql = f"delete from channel2model where {col_name}={ID};"
ret = self.do_sql(strsql)
# schedule --- 调整后一个通道就一个mode
strsql = f"delete from schedule where channel2model_id={c2m_id};"
ret = self.do_sql(strsql)
return True
#删除通道,需要关联删除布防时间,通道和算法的关联表
def delchannel(self,ID):
ret = self.delC2M(ID,1)
@ -148,51 +148,32 @@ class DBManager():
#修改视频通道和算法间的关联关系
#channel_id 通道ID
#modell_list 最新配置的模型id list
def updateC2M(self,channel_id,model_list):
strsql = f"select model_id from channel2model where channel_id={channel_id};"
datas = set(self.do_select(strsql))
data_new = set(model_list)
#计算要新增和修改的
need_add = data_new - datas
need_del = datas-data_new
#新增
for one in need_add:
strsql = f"insert into channel2model (channel_id,model_id) values ({channel_id},{one});"
if self.do_sql(strsql) == False:
return False
#初始化布防时间 -- 全1
strsql = f"select ID from channel2model where channel_id={channel_id} and model_id={one};"
data = mDBM.do_select(strsql,1)
schedule_data_str = ("{'6': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "
"'0': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "
"'1': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "
"'2': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "
"'3': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],"
"'4': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],"
"'5': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}")
schedule_data = json.loads(schedule_data_str.replace("'", '"'))
for day, hours in schedule_data.items():
for hour, status in enumerate(hours):
strsql = (
f"insert into schedule (channel2model_id,day,hour,status) values ({ID},'{day}',{hour},{status})"
f" on conflict(channel2model_id,day,hour) do update set status=excluded.status;")
ret = mDBM.do_sql(strsql)
if not ret:
return ret
#差删除
for one in need_del:
strsql = f"select ID from channel2model where channel_id={channel_id} and model_id={one};"
c2m_id = mDBM.do_select(strsql,1)[0]
#删除布防计划数据
strsql = f"delete from schedule where channel2model_id={c2m_id};"
if self.do_sql(strsql) == False:
return False
#删除关联记录
strsql = f"delete from channel2model where ID = {c2m_id};"
if self.do_sql(strsql) == False:
return False
return True
def updateC2M(self,channel_id,model_id,check_area,polygon_str,conf_thres,iou_thres):
c2m_id = 0
strsql = f"select ID from channel2model where channel_id={channel_id};"
data = self.do_select(strsql,1)
if data: #修改数据
strsql = (f"update channel2model set model_id = {model_id},check_area={check_area},"
f"polygon='{polygon_str}',conf_thres={conf_thres},iou_thres={iou_thres} "
f"where channel_id={channel_id};")
else: #插入数据
strsql = (f"insert into channel2model (channel_id,model_id,check_area,polygon,conf_thres,iou_thres) "
f"values ({channel_id},{model_id},{check_area},'{polygon_str}',{conf_thres},{iou_thres});")
ret = self.do_sql(strsql)
if not ret:
return c2m_id
else:
if data:
return data[0]
else:
strsql = f"select ID from channel2model where channel_id={channel_id};"
data = self.do_select(strsql,1)
if data:
return data[0]
else:
print("正常不会没有值!!")
return 0
#检查设备ID是否在数据库?
def checkDevID(self,cID):

243
core/ModelManager.py

@ -1,16 +1,11 @@
# 导入代码依赖
import time
import av
import os
import cv2
import numpy as np
import threading
import importlib.util
import datetime
import math
import copy
import queue
from collections import deque
from core.DBManager import mDBM,DBManager
from myutils.MyLogger_logger import LogHandler
from myutils.ConfigManager import myCongif
@ -18,95 +13,7 @@ from model.plugins.ModelBase import ModelBase
from core.ChannelManager import ChannelManager
from core.ACLModelManager import ACLModeManger
from core.WarnManager import WarnManager,WarnData
from PIL import Image
class VideoCaptureWithFPS:
'''视频捕获的封装类,是一个通道一个'''
def __init__(self, source):
self.source = source
self.width = None
self.height = None
# GStreamer
#rtsp_stream = f"rtspsrc location={self.source} ! decodebin ! videoconvert ! appsink"
pipeline = (
f"rtspsrc location={self.source} latency=0 ! "
"rtph264depay ! "
"h264parse ! "
"avdec_h264 ! " # 使用 avdec_h264 代替其他解码器
"videoscale ! "
"video/x-raw,width=640,height=480,framerate=10/1 ! " # 降低分辨率和帧率
"videoconvert ! "
"appsink"
)
self.cap = cv2.VideoCapture(pipeline, cv2.CAP_GSTREAMER)
# opencv
# self.cap = cv2.VideoCapture(self.source)
if self.cap.isOpened(): #若没有打开成功,在读取画面的时候,已有判断和处理 -- 这里也要检查下内存的释放情况
self.width = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
self.height = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
print(self.width,self.height)
#self.fps = fps # 线程保持最大帧率的刷新画面---过高的帧率会影响CPU性能,但过地的帧率会造成帧积压
self.fps = math.ceil(self.cap.get(cv2.CAP_PROP_FPS)/float(myCongif.get_data("verify_rate"))) #向上取整。
#print(self.fps)
self.running = True
#self.frame_queue = queue.Queue(maxsize=1)
self.frame = None
self.read_lock = threading.Lock()
self.thread = threading.Thread(target=self.update)
self.thread.start()
def update(self):
icount = 0
while self.running:
ret, frame = self.cap.read()
if not ret:
icount += 1
if icount > 5: #重连
self.cap.release()
self.cap = cv2.VideoCapture(self.source)
if self.cap.isOpened():
self.width = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
self.height = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
print(self.width,self.height)
# self.fps = fps # 线程保持最大帧率的刷新画面---过高的帧率会影响CPU性能,但过地的帧率会造成帧积压
self.fps = math.ceil(
self.cap.get(cv2.CAP_PROP_FPS) / float(myCongif.get_data("verify_rate"))) # 向上取整。
icount = 0
else:
sleep_time = myCongif.get_data("cap_sleep_time")
print(f"{self.source}视频流,将于{sleep_time}秒后重连!")
time.sleep(sleep_time)
continue
#resized_frame = cv2.resize(frame, (int(self.width / 2), int(self.height / 2)))
with self.read_lock:
self.frame = frame
# if not self.frame_queue.full():
# self.frame_queue.put(resized_frame)
# 跳过指定数量的帧以避免积压
for _ in range(self.fps):
self.cap.grab()
# time.sleep(self.fps) #按照视频源的帧率进行休眠
#print("Frame updated at:",time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
def read(self):
with self.read_lock:
frame = self.frame.copy() if self.frame is not None else None
if frame is not None:
return True, frame
else:
return False, None
# if not self.frame_queue.empty():
# return True, self.frame_queue.get()
# else:
# return False, None
def release(self):
self.running = False
self.thread.join()
self.cap.release()
from core.CapManager import VideoCaptureWithFPS
class ModelManager:
def __init__(self):
@ -147,12 +54,13 @@ class ModelManager:
raise Exception("视频参数错误!")
return cap
def _import_model(self,model_name,model_path,threshold):
def _import_model(self,model_name,model_path,threshold,iou_thres):
'''
根据路径动态导入模块
:param model_name: 模块名称
:param model_path: 模块路径
:param threshold: 置信阈值
:param iou_thres: iou阈值
:return:
'''
if os.path.exists(model_path):
@ -162,28 +70,24 @@ class ModelManager:
return None
module = importlib.util.module_from_spec(module_spec)
module_spec.loader.exec_module(module)
md = getattr(module, "Model")(model_path,threshold) #实例化类
md = getattr(module, "Model")(model_path,threshold,iou_thres) #实例化类
if not isinstance(md, ModelBase):
self.logger.error("{} not zf_model".format(md))
return None
if md.init_ok == False:
self.logger.error("离线模型加载初始化失败!")
return None
else:
self.logger.error("{}文件不存在".format(model_path))
return None
self.logger.debug(f"{model_path} 加载成功!!!!")
return md
def getschedule(self,c2m_id,myDBM):
def getschedule(self,c2m_id):
'''
根据c2mID 查询该算法的布防时间
:param c2m_id:
:return: 以day为行hour作为列的布防标识值二维list
'''
strsql = f"select day,hour,status from schedule where channel2model_id ={c2m_id} order by hour asc,day asc;"
datas = myDBM.do_select(strsql)
datas = mDBM.do_select(strsql)
onelist = []
twolist = []
threelist = []
@ -231,8 +135,7 @@ class ModelManager:
weekday = now.weekday() # 获取星期几,星期一是0,星期天是6
hour = now.hour
result.pop(0) # 保障结果数组定长 --先把最早的结果推出数组
detections = None
bwarn = False
warntext = ""
if model and schedule[weekday][hour] == 1: #不在计划则不进行验证,直接返回图片
# 调用模型,进行检测,model是动态加载的,具体的判断标准由模型内执行 ---- *********
@ -265,41 +168,29 @@ class ModelManager:
buffer_bgr_webp = frame_bgr_webp.tobytes()
return buffer_bgr_webp,img,warntext
def dowork_thread(self,channel_id):
def dowork_thread(self,channel_id,model_data,schedule,m,verify_rate,warn_interval):
'''一个通道一个线程,关联的模型在一个线程检测,局部变量都是一个通道独有'''
channel_data = self.verify_list.get_channel(channel_id) #是对ChannelData 对象的引用
context = None
# 线程ACL初始化
if self.model_platform == "acl": # ACL线程中初始化内容
context = ACLModeManger.th_inti_acl(self.device_id)
#查询关联的模型 --- 在循环运行前把基础数据都准备好
myDBM = DBManager()
myDBM.connect()
strsql = (f"select t1.model_id,t1.check_area,t1.polygon ,t2.duration_time,t2.proportion,t2.model_path,t1.ID,"
f"t2.model_name,t1.conf_threshold "
f"from channel2model t1 left join model t2 on t1.model_id = t2.ID where t1.channel_id ={channel_id};")
#print(strsql)
model = myDBM.do_select(strsql,1) #2024-7-12调整规则,一个通道只关联一个模型,表结构暂时不动
if len(model) ==0:
print(f"{channel_id}视频通道没有关联模型,结束线程!")
return
#基于基类实例化模块类
m = self._import_model("",model[5],model[8]) #动态加载模型处理文件py
schedule = self.getschedule(model[6], myDBM)
result = [0 for _ in range(model[3] * myCongif.get_data("verify_rate"))] # 初始化时间*验证帧率数量的结果list
#初始化模型资源
ret = m.init_acl_resource()
if not ret:
print("初始化模型资源出错,退出线程!")
return
channel_data.b_model = True
result = [0 for _ in range(model_data[3] * verify_rate)] # 初始化时间*验证帧率数量的结果list
proportion = model_data[4] # 判断是否报警的占比
#model[6] -- c2m_id --布防计划 0-周一,6-周日
warn_last_time = time.time()
proportion = model[4] #判断是否报警的占比
warn_save_count = 0 #保存录像的最新帧初始化为0
#开始拉取画面循环检测
cap = channel_data.cap
last_frame_time = time.time() #初始化个读帧时间
#可以释放数据库资源
del myDBM
warn_interval = myCongif.get_data("warn_interval")
while channel_data.bool_run: #基于tag 作为运行标识。 线程里只是读,住线程更新,最多晚一轮,应该不用线程锁。需验证
# 帧率控制帧率
current_time = time.time()
@ -312,7 +203,7 @@ class ModelManager:
if not ret:
continue #没读到画面继续
#执行图片推理
buffer_bgr_webp,img_bgr_ndarray,warn_text = self.verify(frame,m,model,channel_id,schedule,result)
buffer_bgr_webp,img_bgr_ndarray,warn_text = self.verify(frame,m,model_data,channel_id,schedule,result)
#分析图片放入内存中
channel_data.add_deque(img_bgr_ndarray) # 缓冲区大小由maxlen控制 超上限后,删除最前的数据
#channel_data.increment_counter() #帧序列加一
@ -333,7 +224,7 @@ class ModelManager:
warn_last_time = current_time
# 处理报警
warn_data = WarnData()
warn_data.model_name = model[7]
warn_data.model_name = model_data[7]
warn_data.warn_text = warn_text
warn_data.img_buffer = channel_data.copy_deque() # 深度复制缓冲区
warn_data.width = cap.width
@ -353,14 +244,23 @@ class ModelManager:
# cv2.imshow(str(channel_id), img)
# if cv2.waitKey(1) & 0xFF == ord('q'):
# break
#结束线程
cap.release() #视频采集线程结束
if context:#ACL线程中反初始化内容 -- 若线程异常退出,这些资源就不能正常释放了
#先释放每个模型资源
del model
#再释放context
ACLModeManger.th_del_acl(context)
print("开始结束工作线程")
channel_data.b_model = False
if self.model_platform == "acl": # ACL线程中初始化内容
try:
m.release() #释放模型资源资源
#释放context
if context: # ACL线程中反初始化内容 -- 若线程异常退出,这些资源就不能正常释放了
# 再释放context
ACLModeManger.th_del_acl(context)
except Exception as e:
print(e)
#删除模型对象
del m
#cv2.destroyAllWindows()
print("线程结束!!!!")
def send_warn(self):
'''发送报警信息'''
@ -379,60 +279,79 @@ class ModelManager:
strsql = "select id,ulr,type from channel where is_work = 1;" #执行所有通道
else:
strsql = f"select id,ulr,type from channel where is_work = 1 and id = {channel_id};" #单通道启动检测线程
datas = mDBM.do_select(strsql)
for data in datas:
# channel_id, str_url, int_type, bool_run, deque_length
c_data = self.verify_list.add_channel(data[0],data[1],data[2],True,
channel_id = data[0]
#1.创建channel对象 channel_id, str_url, int_type, bool_run, deque_length
c_data = self.verify_list.add_channel(channel_id,data[1],data[2],True,
myCongif.get_data("buffer_len"),myCongif.get_data("RESET_INTERVAL"))
# 启动该通道的视频捕获线程 --把视频捕获线程,放主线程创建
#2.启动该通道的视频捕获线程 --把视频捕获线程,放主线程创建
c_data.cap = self._open_view(c_data.str_url, c_data.int_type) # 创建子线程读画面-把cap给模型就行--
th_chn = threading.Thread(target=self.dowork_thread, args=(data[0],)) #一个视频通道一个线程,线程句柄暂时部保留
th_chn.start()
#3.启动工作线程 **************************
self.start_work_th(channel_id,c_data)
# 启动告警线程
if self.warnM is None:
self.warnM = WarnManager()
self.warnM.start_warnmanager_th()
def stop_work(self,channel_id=0):
'''停止工作线程,0-停止所有,非0停止对应通道ID的线程'''
self.verify_list.stop_channel(channel_id)
def stop_work(self,channel_id=0): #要对应start_work 1.停止工作线程,2.停止cap线程。3.删除c_data
'''停止工作线程(包括采集线程,并删除通道数据对象),0-停止所有,非0停止对应通道ID的线程'''
try:
self.verify_list.stop_channel(channel_id)
except Exception as e:
print(e)
if channel_id == 0:
#停止告警线程
self.warnM.brun = False
def start_work_th(self,channel_id,c_data):
verify_rate = myCongif.get_data("verify_rate")
warn_interval = myCongif.get_data("warn_interval")
strsql = (
f"select t1.model_id,t1.check_area,t1.polygon ,t2.duration_time,t2.proportion,t2.model_path,t1.ID,"
f"t2.model_name,t1.conf_thres,t1.iou_thres "
f"from channel2model t1 left join model t2 on t1.model_id = t2.ID where t1.channel_id ={channel_id};")
model_data = mDBM.do_select(strsql, 1) # 2024-7-12调整规则,一个通道只关联一个模型,表结构暂时不动
if model_data and model_data[0]: # 如果该通道关联了模型
# 基于基类实例化模块类
m = self._import_model("", model_data[5], model_data[8], model_data[9]) # 动态加载模型处理文件py
if m:
schedule = self.getschedule(model_data[6]) # 获取布防计划
# 数据准备OK-开始工作线程
c_data.bool_run = True
c_data.work_th = threading.Thread(target=self.dowork_thread,
args=(channel_id, model_data, schedule, m, verify_rate,
warn_interval)) # 一个视频通道一个线程
c_data.work_th.start()
def restartC2M(self,channel_id):
'''
修改通道管理的算法模型后需要对该通道算法执行部分重新加载执行
:param channel_id:
:return:
'''
pass
channel_data = self.verify_list.get_channel(channel_id)
#停止该通道的工作线程 --dowork_thread -- 并清空channel_data中的业务数据
channel_data.clear()
#重启该通道的工作线程
self.start_work_th(channel_id,channel_data)
#print(f"Current working directory (ModelManager.py): {os.getcwd()}")
mMM = ModelManager()
def test1():
print(cv2.getBuildInformation())
source = 'rtsp://192.168.3.44/live1'
gstreamer_pipeline = (
f"rtspsrc location={source} protocols=udp latency=0 ! "
"rtph264depay ! h264parse ! avdec_h264 ! videoconvert ! appsink"
)
cap = cv2.VideoCapture(gstreamer_pipeline, cv2.CAP_GSTREAMER)
if not cap.isOpened():
print("Error: Unable to open the video source.")
return
else:
print("Successfully opened the video source.")
ret, frame = cap.read()
if ret:
cv2.imshow('Frame', frame)
cv2.waitKey(0)
cap.release()
cv2.destroyAllWindows()
pass
if __name__ == "__main__":

122
core/Upload_file.py

@ -1,15 +1,129 @@
from quart import Blueprint, render_template, request, redirect, url_for, flash, current_app
import os
import subprocess
from werkzeug.utils import secure_filename
import platform
import zipfile
import importlib.util
import shutil
from myutils.ConfigManager import myCongif
from model.plugins.ModelBase import ModelBase
def allowed_file(filename):
return '.' in filename and filename.rsplit('.', 1)[1].lower() in myCongif.get_data('ALLOWED_EXTENSIONS')
#对上传的系统升级包进行检查 type:1--系统升级包,2--算法升级包
def check_file(filepath,type):
pass
def check_file(filepath,filename_pre,type): #默认路径一般都是uploads/文件名
'''
检查上传文件的合法性若符合要求则移动到正式路径下面
:param filepath: .zip文件路径
:param filename_pre: 去除掉.zip的纯文件名
:param type: 1--系统升级包 2--算法升级包
:return: model_version model_name model_path(相对路径)
'''
model_name = None
model_version = None
model_path = None
system = platform.system()
#path = filepath.rsplit('.', 1)[0] #去掉后缀
path = myCongif.get_data("UPLOAD_FOLDER") # uploads
zip_path = filepath.rsplit('.', 1)[0] # uploads/filenamedir
filepath_py = zip_path + '/' + filename_pre + '.py' #这里就需要约束py文件名,就是zip压缩包的文件名
buzip = False
#解压缩
if system == "Windows":
try:
with zipfile.ZipFile(filepath, 'r') as zip_ref:
zip_ref.extractall(path)
buzip = True
except zipfile.BadZipfile:
print("文件格式错误,解压失败")
except Exception as e:
print(f"解压失败: {e}")
elif system == "Linux":
try:
subprocess.run(['unzip', '-o', filepath, '-d', path], check=True)
buzip = True
except subprocess.CalledProcessError as e:
print(f"解压失败: {e.stderr}")
except Exception as e:
print(f"解压失败: {e}")
else:
raise NotImplementedError(f"Unsupported operating system: {system}")
#加载模型文件,获取模型名称和版本号
if buzip:
if type == 2: #模型升级包
print(filepath_py)
model = import_model("",filepath_py,0)
if model:
#把解压文件移动至正式路径
tag_path = myCongif.get_data("Model_Plugins") #model/plugins
ret = move_dir(zip_path,tag_path,filename_pre)
if ret:
model_name = model.name #算法名
model_version = model.version #算法版本
model_path = tag_path+'/'+ filename_pre +'/'+filename_pre +'.py' #py文件的路径,是相对路径
del model
elif type == 1: #系统升级包
pass
else:
pass #错误值
return model_version,model_name,model_path
def move_dir(source_path,tag_path,filename_pre,type=1):
'''
移动文件夹
:param source_path: 源文件夹 ***/***/filedir
:param tag_path: 目标路径 ***/***/ 不需要带filedir
:param filename_pre: 不带后缀的文件名
:param type: 0-不覆盖移动目标路径存在filedir的话返回 1-覆盖移动删除后再移动
:return: False True
'''
bsuccess = False
#若根目录不在,则创建
if not os.path.exists(tag_path): #model/plugins
os.makedirs(tag_path)
#判断移动后目录是否存在
newpath = tag_path + '/' + filename_pre
if os.path.exists(newpath):
if type == 1:
shutil.rmtree(newpath)
else:
return bsuccess #这个返回失败
# 移动文件夹
try:
shutil.move(source_path, tag_path)
print(f"成功将文件夹移动到 {tag_path}")
bsuccess = True
except Exception as e:
print(f"移动文件夹失败: {e}")
return bsuccess
def import_model(model_name,model_path,threshold):
'''
根据路径动态导入模块
:param model_name: 模块名称
:param model_path: 模块路径
:param threshold: 置信阈值
:return:
'''
if os.path.exists(model_path):
module_spec = importlib.util.spec_from_file_location(model_name, model_path)
if module_spec is None:
print(f"{model_path} 加载错误")
return None
module = importlib.util.module_from_spec(module_spec)
module_spec.loader.exec_module(module)
md = getattr(module, "Model")(model_path,threshold) #实例化类
if not isinstance(md, ModelBase):
print("{} not zf_model".format(md))
return None
else:
print("{}文件不存在".format(model_path))
return None
print(f"{model_path} 加载成功!!!!")
return md
def update_system(filepath): #系统升级
pass

204
model/ModelManager.py

@ -1,204 +0,0 @@
import torch
import cv2
import numpy as np
import torch
import os
import importlib
from model.plugins.ModelBase import ModelBase
from loguru import logger
'''
class ModelManager_tmp():
def __init__(self):
print("ModelInit")
def __del__(self):
print("ModelManager DEL")
def __preprocess_image(self,image, cfg, bgr2rgb=True):
"""图片预处理"""
img, scale_ratio, pad_size = letterbox(image, new_shape=cfg['input_shape'])
if bgr2rgb:
img = img[:, :, ::-1]
img = img.transpose(2, 0, 1) # HWC2CHW
img = np.ascontiguousarray(img, dtype=np.float32)
return img, scale_ratio, pad_size
def __draw_bbox(self,bbox, img0, color, wt, names):
"""在图片上画预测框"""
det_result_str = ''
for idx, class_id in enumerate(bbox[:, 5]):
if float(bbox[idx][4] < float(0.05)):
continue
img0 = cv2.rectangle(img0, (int(bbox[idx][0]), int(bbox[idx][1])), (int(bbox[idx][2]), int(bbox[idx][3])),
color, wt)
img0 = cv2.putText(img0, str(idx) + ' ' + names[int(class_id)], (int(bbox[idx][0]), int(bbox[idx][1] + 16)),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1)
img0 = cv2.putText(img0, '{:.4f}'.format(bbox[idx][4]), (int(bbox[idx][0]), int(bbox[idx][1] + 32)),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1)
det_result_str += '{} {} {} {} {} {}\n'.format(
names[bbox[idx][5]], str(bbox[idx][4]), bbox[idx][0], bbox[idx][1], bbox[idx][2], bbox[idx][3])
return img0
def __get_labels_from_txt(self,path):
"""从txt文件获取图片标签"""
labels_dict = dict()
with open(path) as f:
for cat_id, label in enumerate(f.readlines()):
labels_dict[cat_id] = label.strip()
return labels_dict
def __draw_prediction(self,pred, image, labels):
"""在图片上画出预测框并进行可视化展示"""
imgbox = widgets.Image(format='jpg', height=720, width=1280)
img_dw = self.__draw_bbox(pred, image, (0, 255, 0), 2, labels)
imgbox.value = cv2.imencode('.jpg', img_dw)[1].tobytes()
display(imgbox)
def __infer_image(self,img_path, model, class_names, cfg):
"""图片推理"""
# 图片载入
image = cv2.imread(img_path)
# 数据预处理
img, scale_ratio, pad_size = self.__preprocess_image(image, cfg)
# 模型推理
output = model.infer([img])[0]
output = torch.tensor(output)
# 非极大值抑制后处理
boxout = nms(output, conf_thres=cfg["conf_thres"], iou_thres=cfg["iou_thres"])
pred_all = boxout[0].numpy()
# 预测坐标转换
scale_coords(cfg['input_shape'], pred_all[:, :4], image.shape, ratio_pad=(scale_ratio, pad_size))
# 图片预测结果可视化
self.__draw_prediction(pred_all, image, class_names)
def __infer_frame_with_vis(self,image, model, labels_dict, cfg, bgr2rgb=True):
# 数据预处理
img, scale_ratio, pad_size = self.__preprocess_image(image, cfg, bgr2rgb)
# 模型推理
output = model.infer([img])[0]
output = torch.tensor(output)
# 非极大值抑制后处理
boxout = nms(output, conf_thres=cfg["conf_thres"], iou_thres=cfg["iou_thres"])
pred_all = boxout[0].numpy()
# 预测坐标转换
scale_coords(cfg['input_shape'], pred_all[:, :4], image.shape, ratio_pad=(scale_ratio, pad_size))
# 图片预测结果可视化
img_vis = self.__draw_bbox(pred_all, image, (0, 255, 0), 2, labels_dict)
return img_vis
def __img2bytes(self,image):
"""将图片转换为字节码"""
return bytes(cv2.imencode('.jpg', image)[1])
def __infer_camera(self,model, labels_dict, cfg):
"""外设摄像头实时推理"""
def find_camera_index():
max_index_to_check = 10 # Maximum index to check for camera
for index in range(max_index_to_check):
cap = cv2.VideoCapture(index)
if cap.read()[0]:
cap.release()
return index
# If no camera is found
raise ValueError("No camera found.")
# 获取摄像头 --这里可以换成RTSP流
camera_index = find_camera_index()
cap = cv2.VideoCapture(camera_index)
# 初始化可视化对象
image_widget = widgets.Image(format='jpeg', width=1280, height=720)
display(image_widget)
while True:
# 对摄像头每一帧进行推理和可视化
_, img_frame = cap.read()
image_pred = self.__infer_frame_with_vis(img_frame, model, labels_dict, cfg)
image_widget.value = self.__img2bytes(image_pred)
def __infer_video(self,video_path, model, labels_dict, cfg):
"""视频推理"""
image_widget = widgets.Image(format='jpeg', width=800, height=600)
display(image_widget)
# 读入视频
cap = cv2.VideoCapture(video_path)
while True:
ret, img_frame = cap.read()
if not ret:
break
# 对视频帧进行推理
image_pred = self.__infer_frame_with_vis(img_frame, model, labels_dict, cfg, bgr2rgb=True)
image_widget.value = self.__img2bytes(image_pred)
def startWork(self,infer_mode,file_paht = ""):
cfg = {
'conf_thres': 0.4, # 模型置信度阈值,阈值越低,得到的预测框越多
'iou_thres': 0.5, # IOU阈值,高于这个阈值的重叠预测框会被过滤掉
'input_shape': [640, 640], # 模型输入尺寸
}
model_path = 'yolo.om'
label_path = './coco_names.txt'
# 初始化推理模型
model = InferSession(0, model_path)
labels_dict = self.__get_labels_from_txt(label_path)
#执行验证
if infer_mode == 'image':
img_path = 'world_cup.jpg'
self.__infer_image(img_path, model, labels_dict, cfg)
elif infer_mode == 'camera':
self.__infer_camera(model, labels_dict, cfg)
elif infer_mode == 'video':
video_path = 'racing.mp4'
self.__infer_video(video_path, model, labels_dict, cfg)
'''
'''
算法实现类实现算法执行线程根据配内容以线程方式执行算法模块
'''
class ModelManager():
def __init__(self):
print("ModelManager init")
def __del__(self):
print("ModelManager del")
def doWork(self):
pass
#动态导入文件 -- 方法二 -- 相对推荐使用该方法 但spec感觉没什么用
def import_source(spec, plgpath):
module = None
if os.path.exists(plgpath):
module_spec = importlib.util.spec_from_file_location(spec, plgpath)
module = importlib.util.module_from_spec(module_spec)
module_spec.loader.exec_module(module)
else:
logger.error("{}文件不存在".format(plgpath))
return module
#plgpath 为list [poc][file_name][name]
def run_plugin(plgpath, target,copy_flag=True):
module = import_source("", plgpath)
if module:
classname = "Model"
plg = getattr(module, classname)()
if not isinstance(plg, ModelBase):
raise Exception("{} not rx_Model".format(plg))
new_plg = plg
result = new_plg.doWork("","","","") # 执行plugin基类的run, 返回结果
return result
else:
print("模型加载失败")
return None
def test():
run_plugin("plugins/RYRQ_Model_ACL.py","")
if __name__ == "__main__":
test()

9
model/plugins/AQM_Model.py

@ -1,9 +0,0 @@
from model.plugins.ModelBase import ModelBase
class Model(ModelBase):
def __init__(self):
super().__init__()
pass
def doWork(self,image,mode,class_name,cfg,isdraw_box=False,bgr2rgb=True):
print("AQM_Model")

59
model/plugins/ModelBase.py

@ -22,9 +22,19 @@ class ModelBase(ABC):
:param threshold: 模型的置信阈值
'''
self.mylogger = LogHandler().get_logger("ModelManager")
self.platform = myCongif.get_data("model_platform")
self.name = None #基于name来查询,用户对模型的配置参数,代表着模型名称需要唯一 2024-6-18 -逻辑还需要完善和验证
self.version = None
self.model_type = None # 模型类型 1-图像分类,2-目标检测(yolov5),3-分割模型,4-关键点
self.model_id = None # 模型 id
self.input_dataset = None # 输入数据结构
self.output_dataset = None # 输出数据结构
self.model_desc = None # 模型描述信息
self._input_num = 0 # 输入数据个数
self._output_num = 0 # 输出数据个数
self._output_info = [] # 输出信息列表
self._is_released = True # 资源是否被释放
self.system = myCongif.get_data("model_platform") #platform.system() #获取系统平台
self.do_map = { # 定义插件的入口函数 --
# POCType.POC: self.do_verify,
@ -32,11 +42,21 @@ class ModelBase(ABC):
# POCType.BRUTE: self.do_brute
}
self.model_path = path # 模型路径
self.init_ok = False
#self.init_ok = False
#---------------------------
#加载ACL模型文件---模型加载、模型执行、模型卸载的操作必须在同一个Context下
# if self.platform == 'acl':
# if self.init_acl_resource(): # 加载离线模型,创建输出缓冲区
# print("加载模型文件成功!")
# self.init_ok = True
# self._is_released = False # 资源是否被释放
# else: #其他平台暂时不需要额外初始化内容
# self.init_ok = True
def __del__(self):
print("资源释放")
# 卸载ACL模型文件
self.release()
def draw_polygon(self, img, polygon_points,color=(0, 255, 0)):
self.polygon = Polygon(ast.literal_eval(polygon_points))
@ -59,16 +79,16 @@ class ModelBase(ABC):
raise RuntimeError(ret)
print('Init TH-Context Successfully')
def _del_acl(self):
device_id = 0
# 线程释放context
ret = acl.rt.destroy_context(self.context) # 释放 Context
if ret:
raise RuntimeError(ret)
print('Deinit TH-Context Successfully')
print('ACL finalize Successfully')
# def _del_acl(self):
# device_id = 0
# # 线程释放context
# ret = acl.rt.destroy_context(self.context) # 释放 Context
# if ret:
# raise RuntimeError(ret)
# print('Deinit TH-Context Successfully')
# print('ACL finalize Successfully')
def _init_resource(self):
def init_acl_resource(self):
#self._init_acl() #测试使用
''' 初始化模型、输出相关资源。相关数据类型: aclmdlDesc aclDataBuffer aclmdlDataset'''
print("Init model resource")
@ -79,6 +99,8 @@ class ModelBase(ABC):
print(f"{self.model_path}---模型加载失败!")
return False
self.model_desc = acl.mdl.create_desc() # 初始化模型信息对象
if not self.model_desc:
return False
ret = acl.mdl.get_desc(self.model_desc, self.model_id) # 根据模型ID获取该模型的aclmdlDesc类型数据(描述信息)
print("[Model] Model init resource stage success")
# 创建模型输出 dataset 结构
@ -86,6 +108,7 @@ class ModelBase(ABC):
if ret !=0:
print("[Model] create model output dataset fail")
return False
self._is_released = False # 资源是否被释放
return True
def _gen_output_dataset(self):
@ -120,6 +143,7 @@ class ModelBase(ABC):
if ret == FAILED:
self._release_dataset(self.input_dataset) # 失败时释放dataset
self.input_dataset = None
#print("[Model] create model input dataset success")
def _unpack_bytes_array(self, byte_array, shape, datatype):
@ -176,9 +200,10 @@ class ModelBase(ABC):
if ret:
self.mylogger.error(f"acl.mdl.execute fail!--{ret}")
self._release_dataset(self.input_dataset) # 失败时释放dataset --创建输入空间失败时会释放。
self.input_dataset = None
return None
out_numpy = self._output_dataset_to_numpy() # 将推理输出的二进制数据流解码为numpy数组, 数组的shape和类型与模型输出规格一致
self._release_dataset(self.input_dataset) # 释放dataset -- 要不要执行需要验证
#self._release_dataset(self.input_dataset) # 释放dataset -- 要不要执行需要验证
return out_numpy
def release(self):
@ -187,10 +212,12 @@ class ModelBase(ABC):
return
print("Model start release...")
self._release_dataset(self.input_dataset) # 释放输入数据结构
self.input_dataset = None # 将输入数据置空
self._release_dataset(self.output_dataset) # 释放输出数据结构
self.output_dataset = None # 将输出数据置空
if self.input_dataset:
self._release_dataset(self.input_dataset) # 释放输入数据结构
self.input_dataset = None # 将输入数据置空
if self.output_dataset:
self._release_dataset(self.output_dataset) # 释放输出数据结构
self.output_dataset = None # 将输出数据置空
if self.model_id:
ret = acl.mdl.unload(self.model_id) # 卸载模型

8
model/plugins/RYRQ/RYRQ_Model.py

@ -17,10 +17,10 @@ class Model(ModelBase):
self.version = "V1.0"
self.model_type = 2
#实例化模型--实例化模型没有对失败的情况进行处理
self.init_ok = True
self.model = torch.hub.load(yolov5_path, 'custom', path=model_file, source='local')
#if model 失败,inti_ok = Flase
# #实例化模型--实例化模型没有对失败的情况进行处理
# self.init_ok = True
# self.model = torch.hub.load(yolov5_path, 'custom', path=model_file, source='local')
# #if model 失败,inti_ok = Flase
def verify(self,image,data,isdraw=1):

32
model/plugins/RYRQ_ACL/RYRQ_Model_ACL.py

@ -1,27 +1,18 @@
import os.path
from model.plugins.ModelBase import ModelBase
from myutils.ConfigManager import myCongif
from model.base_model.ascnedcl.det_utils import get_labels_from_txt, letterbox, scale_coords, nms, draw_bbox # 模型前后处理相关函数
import cv2
import numpy as np
import torch # 深度学习运算框架,此处主要用来处理数据
from core.ACLModelManager import ACLModeManger
class Model(ModelBase):
def __init__(self,path,threshold=0.5):
def __init__(self,path,threshold=0.5,iou_thres=0.5):
# 找pt模型路径 -- 一个约束py文件和模型文件的路径关系需要固定, -- 上传模型时,要解压好路径
dirpath, filename = os.path.split(path)
self.model_file = os.path.join(dirpath, "yolov5s_bs1.om") # 目前约束模型文件和py文件在同一目录
self.coco_file = os.path.join(dirpath, "coco_names.txt")
super().__init__(self.model_file) #acl环境初始化基类负责类的实例化
self.model_id = None # 模型 id
self.input_dataset = None # 输入数据结构
self.output_dataset = None # 输出数据结构
self.model_desc = None # 模型描述信息
self._input_num = 0 # 输入数据个数
self._output_num = 0 # 输出数据个数
self._output_info = [] # 输出信息列表
self._is_released = False # 资源是否被释放
super().__init__(self.model_file) # acl环境初始化基类负责类的实例化
self.name = "人员入侵-yolov5"
self.version = "V1.0"
self.model_type = 2
@ -29,17 +20,7 @@ class Model(ModelBase):
self.neth = 640 # 缩放的目标高度, 也即模型的输入高度
self.netw = 640 # 缩放的目标宽度, 也即模型的输入宽度
self.conf_threshold = threshold # 置信度阈值
#加载ACL模型文件---模型加载、模型执行、模型卸载的操作必须在同一个Context下
if self._init_resource(): #加载离线模型,创建输出缓冲区
print("加载模型文件成功!")
self.init_ok = True
def __del__(self):
#卸载ACL模型文件
if self.init_ok:
self.release()
self.iou_thres = iou_thres # IOU阈值
def verify(self,image,data,isdraw=1):
@ -63,8 +44,9 @@ class Model(ModelBase):
if outputs:
output = outputs[0] #只放了一张图片
# 后处理 -- boxout 是 tensor-list: [tensor([[],[].[]])] --[x1,y1,x2,y2,置信度,coco_index]
boxout = nms(torch.tensor(output), conf_thres=0.3,
iou_thres=0.5) # 利用非极大值抑制处理模型输出,conf_thres 为置信度阈值,iou_thres 为iou阈值
# 利用非极大值抑制处理模型输出,conf_thres 为置信度阈值,iou_thres 为iou阈值
boxout = nms(torch.tensor(output), conf_thres=self.conf_threshold,iou_thres=self.iou_thres)
pred_all = boxout[0].numpy() # 转换为numpy数组 -- [[],[],[]] --[x1,y1,x2,y2,置信度,coco_index]
# pred_all[:, :4] 取所有行的前4列,pred_all[:,1]--第一列
scale_coords([640, 640], pred_all[:, :4], image.shape, ratio_pad=(scale_ratio, pad_size)) # 将推理结果缩放到原始图片大小

155
model/plugins/yolov5-1.py

@ -1,155 +0,0 @@
# 导入代码依赖
import cv2
import numpy as np
from myutils.ConfigManager import myCongif
import os
import torch
import ipywidgets as widgets
from IPython.display import display
from skvideo.io import vreader, FFmpegWriter
import IPython.display
from ais_bench.infer.interface import InferSession
from det_utils import letterbox, scale_coords, nms
def preprocess_image(image, cfg, bgr2rgb=True):
"""图片预处理"""
img, scale_ratio, pad_size = letterbox(image, new_shape=cfg['input_shape'])
if bgr2rgb:
img = img[:, :, ::-1]
img = img.transpose(2, 0, 1) # HWC2CHW
img = np.ascontiguousarray(img, dtype=np.float32)
return img, scale_ratio, pad_size
def draw_bbox(bbox, img0, color, wt, names):
"""在图片上画预测框"""
det_result_str = ''
for idx, class_id in enumerate(bbox[:, 5]):
if float(bbox[idx][4] < float(0.05)):
continue
img0 = cv2.rectangle(img0, (int(bbox[idx][0]), int(bbox[idx][1])), (int(bbox[idx][2]), int(bbox[idx][3])),
color, wt)
img0 = cv2.putText(img0, str(idx) + ' ' + names[int(class_id)], (int(bbox[idx][0]), int(bbox[idx][1] + 16)),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1)
img0 = cv2.putText(img0, '{:.4f}'.format(bbox[idx][4]), (int(bbox[idx][0]), int(bbox[idx][1] + 32)),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1)
det_result_str += '{} {} {} {} {} {}\n'.format(
names[bbox[idx][5]], str(bbox[idx][4]), bbox[idx][0], bbox[idx][1], bbox[idx][2], bbox[idx][3])
return img0
def get_labels_from_txt(path):
"""从txt文件获取图片标签"""
labels_dict = dict()
with open(path) as f:
for cat_id, label in enumerate(f.readlines()):
labels_dict[cat_id] = label.strip()
return labels_dict
def draw_prediction(pred, image, labels):
"""在图片上画出预测框并进行可视化展示"""
imgbox = widgets.Image(format='jpg', height=720, width=1280)
img_dw = draw_bbox(pred, image, (0, 255, 0), 2, labels)
imgbox.value = cv2.imencode('.jpg', img_dw)[1].tobytes()
display(imgbox)
def infer_image(img_path, model, class_names, cfg):
"""图片推理"""
# 图片载入
image = cv2.imread(img_path)
# 数据预处理
img, scale_ratio, pad_size = preprocess_image(image, cfg)
# 模型推理
output = model.infer([img])[0]
output = torch.tensor(output)
# 非极大值抑制后处理
boxout = nms(output, conf_thres=cfg["conf_thres"], iou_thres=cfg["iou_thres"])
pred_all = boxout[0].numpy()
# 预测坐标转换
scale_coords(cfg['input_shape'], pred_all[:, :4], image.shape, ratio_pad=(scale_ratio, pad_size))
# 图片预测结果可视化
draw_prediction(pred_all, image, class_names)
def infer_frame_with_vis(image, model, labels_dict, cfg, bgr2rgb=True):
# 数据预处理
img, scale_ratio, pad_size = preprocess_image(image, cfg, bgr2rgb)
# 模型推理
output = model.infer([img])[0]
output = torch.tensor(output)
# 非极大值抑制后处理
boxout = nms(output, conf_thres=cfg["conf_thres"], iou_thres=cfg["iou_thres"])
pred_all = boxout[0].numpy()
# 预测坐标转换
scale_coords(cfg['input_shape'], pred_all[:, :4], image.shape, ratio_pad=(scale_ratio, pad_size))
# 图片预测结果可视化
img_vis = draw_bbox(pred_all, image, (0, 255, 0), 2, labels_dict)
return img_vis
def img2bytes(image):
"""将图片转换为字节码"""
return bytes(cv2.imencode('.jpg', image)[1])
def infer_video(video_path, model, labels_dict, cfg):
"""视频推理"""
image_widget = widgets.Image(format='jpeg', width=800, height=600)
display(image_widget)
# 读入视频
cap = cv2.VideoCapture(video_path)
while True:
ret, img_frame = cap.read()
if not ret:
break
# 对视频帧进行推理
image_pred = infer_frame_with_vis(img_frame, model, labels_dict, cfg, bgr2rgb=True)
image_widget.value = img2bytes(image_pred)
def infer_camera(model, labels_dict, cfg):
"""外设摄像头实时推理"""
def find_camera_index():
max_index_to_check = 10 # Maximum index to check for camera
for index in range(max_index_to_check):
cap = cv2.VideoCapture(index)
if cap.read()[0]:
cap.release()
return index
# If no camera is found
raise ValueError("No camera found.")
# 获取摄像头
camera_index = find_camera_index()
cap = cv2.VideoCapture(camera_index)
# 初始化可视化对象
image_widget = widgets.Image(format='jpeg', width=1280, height=720)
display(image_widget)
while True:
# 对摄像头每一帧进行推理和可视化
_, img_frame = cap.read()
image_pred = infer_frame_with_vis(img_frame, model, labels_dict, cfg)
image_widget.value = img2bytes(image_pred)
if __name__ == "__main__":
cfg = {
'conf_thres': 0.4, # 模型置信度阈值,阈值越低,得到的预测框越多
'iou_thres': 0.5, # IOU阈值,高于这个阈值的重叠预测框会被过滤掉
'input_shape': [640, 640], # 模型输入尺寸
}
model_path = os.path.join(myCongif.get_data('weight_path'),'/yolov5-1/yolov5s.pt')
label_path = os.path.join(myCongif.get_data('weight_path'),'/yolov5-1/coco_names.txt')
# 初始化推理模型
model = InferSession(0, model_path)
labels_dict = get_labels_from_txt(label_path)
infer_mode = 'video'
if infer_mode == 'image':
img_path = 'world_cup.jpg'
infer_image(img_path, model, labels_dict, cfg)
elif infer_mode == 'camera':
infer_camera(model, labels_dict, cfg)
elif infer_mode == 'video':
video_path = 'racing.mp4'
infer_video(video_path, model, labels_dict, cfg)

64
model/weights/yolov5-1/yoloV5.py

@ -1,64 +0,0 @@
import torch
import cv2
import numpy as np
from shapely.geometry import Point, Polygon
import os
# # 自定义模型文件的路径
# model_path = 'yolov5s.pt' # 假设模型文件名为 yolov5s.pt 并与执行文件在同一个目录
# # 本地YOLOv5仓库路径
# repo_path = '../base_model/yolov5'
# 自定义模型文件的路径
print(f"Current working directory (yolov5.py): {os.getcwd()}")
model_path = 'D:/Project/FristProject/model/mode_test/yolov5s.pt' # 假设模型文件名为 yolov5s.pt 并与执行文件在同一个目录
# 本地YOLOv5仓库路径
repo_path = 'D:/Project/FristProject/model/base_model/yolov5'
# 加载自定义模型
model = torch.hub.load(repo_path, 'custom', path=model_path, source='local')
# 定义监控区域(多边形顶点)
region_points = [(100, 100), (500, 100), (500, 400), (100, 400)]
polygon = Polygon(region_points)
# 打开摄像头
cap = cv2.VideoCapture(0)
def is_point_in_polygon(point, polygon):
return polygon.contains(Point(point))
while True:
ret, frame = cap.read()
if not ret:
break
# 进行推理
results = model(frame)
detections = results.pandas().xyxy[0]
# 绘制监控区域
cv2.polylines(frame, [np.array(region_points, np.int32)], isClosed=True, color=(0, 255, 0), thickness=2)
for _, row in detections.iterrows():
if row['name'] == 'person':
# 获取人员检测框的中心点
x_center = (row['xmin'] + row['xmax']) / 2
y_center = (row['ymin'] + row['ymax']) / 2
if is_point_in_polygon((x_center, y_center), polygon):
# 触发报警
cv2.putText(frame, 'Alert: Intrusion Detected', (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
print('Alert: Intrusion Detected')
# 绘制检测框
cv2.rectangle(frame, (int(row['xmin']), int(row['ymin'])), (int(row['xmax']), int(row['ymax'])), (255, 0, 0), 2)
cv2.circle(frame, (int(x_center), int(y_center)), 5, (0, 0, 255), -1)
# 显示结果
cv2.imshow('Frame', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()

300
myutils/IPManager.py

@ -0,0 +1,300 @@
import subprocess
import platform
import locale
import re
'''
针对windows和linux的网络信息获取和设置功能类
由于网络接口名字并不一定又有多网卡等情况实际应用时需要指定网络接口固化硬件环境
'''
class IPManager:
def __init__(self):
self.os_type = platform.system()
self.encoding = locale.getpreferredencoding()
def set_ip(self, interface_name, ip_address, subnet_mask, gateway):
if self.os_type == "Windows":
self._set_ip_windows(interface_name, ip_address, subnet_mask, gateway)
elif self.os_type == "Linux":
self._set_ip_linux(interface_name, ip_address, subnet_mask, gateway)
else:
raise NotImplementedError("Unsupported OS")
def connect_wifi(self, ssid, password):
if self.os_type == "Windows":
self._connect_wifi_windows(ssid, password)
elif self.os_type == "Linux":
self._connect_wifi_linux(ssid, password)
else:
raise NotImplementedError("Unsupported OS")
def get_wifi_list(self):
wifis = []
if self.os_type == "Windows":
wifis = self._get_wifi_list_windows()
elif self.os_type == "Linux":
wifis = self._get_wifi_list_linux()
else:
raise NotImplementedError("Unsupported OS")
return wifis
def get_connected_wifi(self):
ssid = None
if self.os_type == "Windows":
ssid = self._get_connected_wifi_windows()
elif self.os_type == "Linux":
ssid = self._get_connected_wifi_linux()
else:
raise NotImplementedError("Unsupported OS")
return ssid
def get_network_info(self):
info = None
if self.os_type == "Windows":
info = self._get_network_info_windows()
elif self.os_type == "Linux":
info = self._get_network_info_linux()
else:
raise NotImplementedError("Unsupported OS")
return info
def _set_ip_windows(self, interface_name, ip_address, subnet_mask, gateway):
command = f'netsh interface ip set address name="{interface_name}" static {ip_address} {subnet_mask} {gateway} 1'
#result = subprocess.run(command, shell=True,capture_output=True, text=True, encoding='utf-8')
# 打印输出结果
result = self._run_cmd(command)
print(result.stdout)
# 检查返回码
if result.returncode == 0:
print("IP address set successfully.")
else:
print("Failed to set IP address. Please check the output for errors.")
def _set_ip_linux(self, interface_name, ip_address, subnet_mask, gateway):
self._run_cmd(f"sudo ip addr flush dev {interface_name}")
self._run_cmd(f"sudo ip addr add {ip_address}/{subnet_mask} dev {interface_name}")
self._run_cmd(f"sudo ip route add default via {gateway}")
def _connect_wifi_windows(self, ssid, password):
command = f'netsh wlan connect name="{ssid}"'
self._run_cmd(command)
def _connect_wifi_linux(self, ssid, password):
command = f"nmcli dev wifi connect '{ssid}' password '{password}'"
self._run_cmd(command)
def _get_wifi_list_windows(self):
command = "netsh wlan show networks"
result = self._run_cmd(command)
wifi_list = []
lines = result.stdout.split('\n')
for line in lines:
if "SSID" in line and "BSSID" not in line:
ssid = line.split(":")[1].strip()
wifi_list.append(ssid)
return wifi_list
def _get_wifi_list_linux(self):
command = "nmcli dev wifi list"
result = self._run_cmd(command)
# 解析输出结果
wifi_list = []
lines = result.stdout.split('\n')
for line in lines[1:]: # 跳过表头
if line.strip():
ssid = line.split()[0]
wifi_list.append(ssid)
return wifi_list
def _get_connected_wifi_windows(self):
command = "netsh wlan show interfaces"
result = self._run_cmd(command)
# 使用正则表达式提取SSID
ssid_match = re.search(r"SSID\s+: (.+)", result.stdout)
if ssid_match:
ssid = ssid_match.group(1).strip()
return ssid
else:
return None
def _get_connected_wifi_linux(self):
command = "iwgetid -r"
result = self._run_cmd(command)
ssid = result.stdout.strip()
if ssid:
return ssid
else:
return None
def _get_network_info_windows(self):
command = "ipconfig /all"
result = self._run_cmd(command)
interfaces = {}
current_interface = None
for line in result.stdout.splitlines():
# 识别接口名称
interface_match = re.match(r"^\s*([^:\s]+.*):$", line)
if interface_match:
current_interface = interface_match.group(1).strip()
interfaces[current_interface] = {"IP": None, "Subnet": None, "Gateway": None, "DNS": []}
if current_interface:
# 解析IP地址
ip_match = re.search(r"^\s*IPv4 地址[^\:]*:\s*(\d+\.\d+\.\d+\.\d+)", line)
if ip_match:
interfaces[current_interface]["IP"] = ip_match.group(1).strip()
# 解析子网掩码
subnet_match = re.search(r"^\s*子网掩码[^\:]*:\s*(\d+\.\d+\.\d+\.\d+)", line)
if subnet_match:
interfaces[current_interface]["Subnet"] = subnet_match.group(1).strip()
# 解析网关
gateway_match = re.search(r"^\s*默认网关[^\:]*:\s*(\d+\.\d+\.\d+\.\d+)", line)
if gateway_match:
interfaces[current_interface]["Gateway"] = gateway_match.group(1).strip()
# 解析DNS服务器
dns_match = re.search(r"^\s*DNS 服务器[^\:]*:\s*(\d+\.\d+\.\d+\.\d+)", line)
if dns_match:
interfaces[current_interface]["DNS"].append(dns_match.group(1).strip())
else:
# 匹配后续行的DNS服务器
dns_continued_match = re.search(r"^\s*(\d+\.\d+\.\d+\.\d+)", line)
if dns_continued_match:
interfaces[current_interface]["DNS"].append(dns_continued_match.group(1).strip())
return interfaces
def _get_network_info_linux(self):
# 获取IP地址、子网掩码和网关
ip_info = self._run_cmd("ip addr show").stdout
route_info = self._run_cmd("ip route show").stdout
# 获取DNS服务器
dns_info = self._run_cmd("nmcli dev show | grep DNS").stdout
interfaces = {}
current_interface = None
for line in ip_info.splitlines():
# 识别接口名称
interface_match = re.match(r"^\d+: ([^:\s]+):", line)
if interface_match:
current_interface = interface_match.group(1).strip()
interfaces[current_interface] = {"IP": None, "Subnet": None, "Gateway": None, "DNS": []}
if current_interface:
# 解析IP地址和子网掩码
ip_match = re.search(r"^\s*inet (\d+\.\d+\.\d+\.\d+)/(\d+)", line)
if ip_match:
interfaces[current_interface]["IP"] = ip_match.group(1).strip()
interfaces[current_interface]["Subnet"] = ip_match.group(2).strip()
# 解析网关
for line in route_info.splitlines():
if "default via" in line:
gateway_match = re.search(r"default via (\d+\.\d+\.\d+\.\d+)", line)
interface_match = re.search(r"dev (\S+)", line)
if gateway_match and interface_match:
interface = interface_match.group(1).strip()
if interface in interfaces:
interfaces[interface]["Gateway"] = gateway_match.group(1).strip()
# 解析DNS服务器
for line in dns_info.splitlines():
dns_match = re.search(r"DNS\[\d+\]:\s*(\d+\.\d+\.\d+\.\d+)", line)
if dns_match:
# 假设第一个接口是主要接口
primary_interface = list(interfaces.keys())[0]
interfaces[primary_interface]["DNS"].append(dns_match.group(1).strip())
return interfaces
def _get_interface_info_windows(self,interface_name):
command = f'netsh interface ip show config name="{interface_name}"'
result = self._run_cmd(command)
info = {"IP": None, "Subnet": None, "Gateway": None, "DNS": []}
# 解析IP地址
ip_match = re.search(r"IP Address:\s*(\d+\.\d+\.\d+\.\d+)", result.stdout)
if ip_match:
info["IP"] = ip_match.group(1).strip()
# 解析子网掩码
subnet_match = re.search(r"Subnet Prefix:\s*(\d+\.\d+\.\d+\.\d+)", result.stdout)
if subnet_match:
info["Subnet"] = subnet_match.group(1).strip()
# 解析网关
gateway_match = re.search(r"Default Gateway:\s*(\d+\.\d+\.\d+\.\d+)", result.stdout)
if gateway_match:
info["Gateway"] = gateway_match.group(1).strip()
# 解析DNS服务器
dns_matches = re.findall(r"Statically Configured DNS Servers:\s*(\d+\.\d+\.\d+\.\d+)", result.stdout)
for dns in dns_matches:
info["DNS"].append(dns.strip())
return info
def _get_interface_info_linux(self,interface_name):
info = {"IP": None, "Subnet": None, "Gateway": None, "DNS": []}
# 获取IP地址和子网掩码
ip_command = f"ip addr show dev {interface_name}"
ip_result = self._run_cmd(ip_command)
ip_match = re.search(r"inet (\d+\.\d+\.\d+\.\d+)/(\d+)", ip_result.stdout)
if ip_match:
info["IP"] = ip_match.group(1).strip()
info["Subnet"] = ip_match.group(2).strip()
# 获取网关信息
gateway_command = f"ip route show dev {interface_name}"
gateway_result = subprocess.run(gateway_command, shell=True, capture_output=True, text=True, encoding='utf-8')
gateway_match = re.search(r"default via (\d+\.\d+\.\d+\.\d+)", gateway_result.stdout)
if gateway_match:
info["Gateway"] = gateway_match.group(1).strip()
# 获取DNS服务器信息
dns_command = f"nmcli dev show {interface_name} | grep DNS"
dns_result = subprocess.run(dns_command, shell=True, capture_output=True, text=True, encoding='utf-8')
dns_matches = re.findall(r"DNS\[\d+\]:\s*(\d+\.\d+\.\d+\.\d+)", dns_result.stdout)
for dns in dns_matches:
info["DNS"].append(dns.strip())
return info
def _run_cmd(self,command):
'''
为了统一命令执行的返回参数格式统一定义了一个执行函数
:param command:
:return:
'''
result = subprocess.run(command, shell=True, capture_output=True, text=True, encoding=self.encoding)
return result
IPM = IPManager()
if __name__ == "__main__":#WLAN
# 示例用法
nm = IPManager()
try:
#nm.set_ip("以太网 2", "192.168.1.100", "255.255.255.0", "192.168.1.1")
#nm.set_ip("WLAN", "192.168.3.100", "255.255.255.0", "192.168.3.1") #zhang wifi
network_info = nm.get_wifi_list()
print(network_info)
except Exception as e:
print(e)
#nm.connect_wifi("YourSSID", "YourPassword")

13
run.py

@ -7,6 +7,7 @@ import asyncio
from hypercorn.asyncio import serve
from hypercorn.config import Config
from core.DBManager import mDBM
from core.Upload_file import allowed_file,check_file,updata_model
print(f"Current working directory (run.py): {os.getcwd()}")
web = create_app()
@ -16,16 +17,12 @@ async def run_quart_app():
await serve(web, config)
def test():
area_id = 1
c_name = "55"
strsql = f"select ID from channel where area_id={area_id} and channel_name={c_name};"
data = mDBM.do_select(strsql, 1)
if data:
print("有值")
else:
print("无值")
filepath = "uploads/RYRQ_Model_ACL.zip"
check_file(filepath,2)
if __name__ == '__main__':
#test()
system = platform.system()
if system == "Windows":
total, used, free = shutil.disk_usage("/")

BIN
uploads/8.zip

Binary file not shown.

213
web/API/channel.py

@ -5,8 +5,10 @@ from web.common.utils import login_required
from core.DBManager import mDBM
from myutils.ReManager import mReM
from core.ModelManager import mMM
from myutils.ConfigManager import myCongif
import cv2
import base64
import time
@api.route('/channel/tree',methods=['GET'])
@login_required
@ -48,19 +50,27 @@ async def channel_add(): #新增通道 -- 2024-8-1修改为与修改通道用一
reMsg = 'rtsp地址不合法'
return jsonify({'status': reStatus, 'msg': reMsg})
strsql = f"select id from area where area_name = '{area}';"
ret = mDBM.do_select(strsql,1)
if ret:
strsql = f"select ID from channel where area_id={ret[0]} and channel_name={cName};"
area = mDBM.do_select(strsql,1)
if area:
area_id = area[0]
strsql = f"select ID from channel where area_id={area_id} and channel_name='{cName}';"
data = mDBM.do_select(strsql, 1)
if data: #有值--代表重复了
if data and data[0] != cid: #有值--代表重复 或者是它自己(只修改RTSP地址)
reStatus = 0
reMsg = "同一区域内的通道名称不能相同!"
else:
if cid == -1:
max_count = myCongif.get_data("max_channel_num")
strsql = "select count(*) from channel;"
data = mDBM.do_select(strsql,1)
if data[0] >= max_count:
reStatus = 0
reMsg = f"已达到最多通道数量-{max_count}通道,不能再添加"
return jsonify({'status': reStatus, 'msg': reMsg})
strsql = (f"INSERT INTO channel (area_id,channel_name,ulr,'type',status) values "
f"({ret[0]},'{cName}','{Rtsp}',1,0);")
f"({area_id},'{cName}','{Rtsp}',1,0);")
else:
strsql = (f"UPDATE channel SET area_id={ret[0]},channel_name='{cName}'"
strsql = (f"UPDATE channel SET area_id={area_id},channel_name='{cName}'"
f",ulr='{Rtsp}' where ID={cid};")
ret = mDBM.do_sql(strsql)
if ret == True:
@ -68,18 +78,22 @@ async def channel_add(): #新增通道 -- 2024-8-1修改为与修改通道用一
if cid == -1:
reMsg = '添加通道成功'
# 对新增的视频通道进行视频采集和
strsql = f"select ID from channel where area_id={ret[0]} and channel_name={cName};"
strsql = f"select ID from channel where area_id={area_id} and channel_name={cName};"
data = mDBM.do_select(strsql, 1)
if data:
cid = data[0]
mMM.start_work(cid)
else:
print("这里不应该没有值!!!!")
print(f"这里不应该没有值!!!!area_id-{area_id},cName--{cName}")
else:
reMsg = '修改通道成功'
#需要先停再启动---不区分有没有修改URL了,就当有修改使用
mMM.stop_work(cid)
start_time = time.time()
mMM.start_work(cid)
end_time = time.time()
execution_time = end_time - start_time
print(f"开始一个通道线程,花费了: {execution_time} seconds")
else:
reStatus = 0
if cid == -1:
@ -93,12 +107,13 @@ async def channel_add(): #新增通道 -- 2024-8-1修改为与修改通道用一
@api.route('/channel/img',methods=['POST'])
@login_required
async def channel_img():
async def get_channel_img():
'''获取一帧图片'''
json_data = await request.get_json()
cid = int(json_data.get('cid'))
channel_data = mMM.verify_list.get_channel(cid)
if channel_data:
# 执行视频传输
# 读取一帧画面
ret,frame = channel_data.cap.read()
if ret:
# 将帧转换为JPEG格式
@ -112,33 +127,6 @@ async def channel_img():
else:
return jsonify({"error": "Channel not found"}), 500
@api.route('/channel/change',methods=['POST'])
@login_required
async def channel_change(): #修改通道信息 -- 已弃用
area_id = (await request.form)['area_id']
channel_id = (await request.form)['channel_id']
channel_name = (await request.form)['channel_name']
url = (await request.form)['url']
if mReM.is_valid_rtsp_url(url) is not True:
reStatus = 0
reMsg = 'rtsp地址不合法'
return jsonify({'status': reStatus, 'msg': reMsg})
strsql = f"select area_name from area where id = {area_id};"
ret = mDBM.do_select(strsql, 1)
if ret:
strsql = f"UPDATE channel SET area_id={area_id},channel_name='{channel_name}',ulr='{url}' where ID={channel_id};"
ret = mDBM.do_sql(strsql)
if ret == True:
reStatus = 1
reMsg = '修改通道信息成'
else:
reStatus = 0
reMsg = '修改通道信息失败,请联系技术支持!'
else:
reStatus = 0
reMsg = '错误的通道ID,请修改'
return jsonify({'status': reStatus, 'msg': reMsg})
@api.route('/channel/del',methods=['POST'])
@login_required
async def channel_del(): #删除通道
@ -149,7 +137,7 @@ async def channel_del(): #删除通道
ret = mDBM.delchannel(cid)
if ret == True:
reStatus = 1
reMsg = '删除通道信息成'
reMsg = '删除通道信息成'
else:
reStatus = 0
reMsg = '删除通道信息失败,请联系技术支持!'
@ -180,7 +168,7 @@ async def channel_check(): #检查通道视频的在线情况--可以获取全
@api.route('/channel/C2M',methods=['POST'])
@login_required
async def channel_to_model():
async def get_ctm_data():
'''获取通道关联模型的相关数据'''
json_data = await request.get_json()
cid = int(json_data.get('cid'))
@ -212,9 +200,100 @@ async def channel_to_model():
redata = {"m_datas":m_datas,"c2m_data":c2m_data_json,"schedule":schedule}
return jsonify(redata)
@api.route('/channel/chanegeC2M',methods=['POST'])
@login_required
async def change_c_t_m():
'''
修改和新增与通道关联的算法模块
:return:
'''
json_data = await request.get_json()
model_name = json_data.get('model_name')
check_area = json_data.get('check_area')
polygon_str = json_data.get('polygon_str')
iou_thres = json_data.get('iou_thres')
conf_thres = json_data.get('conf_thres')
schedule = json_data.get('schedule')
cid = json_data.get('cid')
#返回数据
reStatus = 0
reMsg = "更新失败,请联系技术支持!"
#开始更新--- 统一先停止原通道工作线程
if model_name=="请选择":
strsql = f"select ID from channel2model where channel_id={cid};"
data = mDBM.do_select(strsql,1)
if data:
#需要删除数据
ret = mDBM.delC2M(cid,1) #只是删除了数据库数据
if ret:
#重启下通道的工作线程
mMM.stop_work(cid)
mMM.start_work(cid)
reStatus = 1
reMsg = "更新成功"
else: #原本就没数据
reStatus = 1
reMsg = "更新成功"
else: #新增关联或修改关联
# 验证数据
if conf_thres <= 0 or conf_thres >= 1 or iou_thres <= 0 or iou_thres >= 1:
reMsg = "阈值的有效范围是大于0,小于1;请输入正确的阈值"
return jsonify({'status': reStatus, 'msg': reMsg})
c2m_id = updateModel(cid,model_name,check_area,polygon_str,conf_thres,iou_thres) #c2m表
if c2m_id != 0:
ret = updataSchedule(c2m_id,schedule.replace("'", "\"")) #schedule表
if ret:
# 重启下通道的工作线程
mMM.stop_work(cid)
mMM.start_work(cid)
reStatus = 1
reMsg = "更新成功"
return jsonify({'status': reStatus, 'msg': reMsg})
def updataSchedule(c2m_id,schedule):
# schedule_data_str = ("{'6': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "
# "'0': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "
# "'1': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "
# "'2': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "
# "'3': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],"
# "'4': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],"
# "'5': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}")
#先删
strsql = f"delete from schedule where channel2model_id={c2m_id};"
mDBM.do_sql(strsql)
#再加
json_object = json.loads(schedule)
for day, hours in json_object.items():
for hour, status in enumerate(hours):
strsql = (
f"insert into schedule (channel2model_id,day,hour,status) values ({c2m_id},'{day}',{hour},{status})"
f" on conflict(channel2model_id,day,hour) do update set status=excluded.status;")
ret = mDBM.do_sql(strsql)
if not ret: #插入失败后,需要删除所有数据
strsql = f"delete from schedule where channel2model_id={c2m_id};"
mDBM.do_sql(strsql)
return ret
return 1
def updateModel(channel_id,model_name,check_area,polygon_str,conf_thres,iou_thres):
'''新增和修改通道关联的模型 ----约束:一个通道只能关联一个算法模型
return 0 失败 其他为c2m_id
'''
reStatus = 0
strsql = f"select ID from channel where ID={channel_id};"
if mDBM.do_select(strsql, 1): # 通道号在数据库中
strsql = f"select ID from model where model_name = '{model_name}';"
data = mDBM.do_select(strsql, 1)
if data: #通道和模型都有对应数据
reStatus = mDBM.updateC2M(channel_id, data[0],check_area,polygon_str,conf_thres,iou_thres)
return reStatus
@api.route('/channel/area/list',methods=['GET'])
@login_required
async def channel_area_list(): #获取区域列表
async def channel_area_list():
'''获取所属区域list'''
strsql = "select * from area;"
datas = mDBM.do_select(strsql)
reMsg = [{'id': data[0], 'area_name': data[1]} for data in datas]
@ -225,14 +304,20 @@ async def channel_area_list(): #获取区域列表
async def channel_area_change(): #修改区域名称
area_id = (await request.form)['id']
area_name = (await request.form)['name']
strsql = f"update area set area_name='{area_name}' where id = {area_id};"
ret = mDBM.do_sql(strsql)
if ret == True:
reStatus = 1
reMsg = '修改通道名称成功'
else:
strsql = f"select id from area where area_name='{area_name}';"
datas = mDBM.do_select(strsql)
if datas:
reStatus = 0
reMsg = '修改通道名称失败,请联系技术支持!'
reMsg = '区域名称重复,请修改!'
else:
strsql = f"update area set area_name='{area_name}' where id = {area_id};"
ret = mDBM.do_sql(strsql)
if ret == True:
reStatus = 1
reMsg = '修改通道名称成功'
else:
reStatus = 0
reMsg = '修改通道名称失败,请联系技术支持!'
return jsonify({'status': reStatus, 'msg': reMsg})
@api.route('/channel/area/del',methods=['POST'])
@ -258,15 +343,22 @@ async def channel_area_del(): #删除区域
@api.route('/channel/area/add',methods=['POST'])
@login_required
async def channel_area_add(): #添加区域
area_name = (await request.form)['name']
strsql = f"insert into area (area_name) values ('{area_name}');"
ret = mDBM.do_sql(strsql)
if ret == True:
reStatus = 1
reMsg = '新增区域成功'
else:
json_data = await request.get_json()
area_name = json_data.get('name')
strsql = f"select id from area where area_name='{area_name}';"
data = mDBM.do_select(strsql,1)
if data:
reStatus = 0
reMsg = '新增区域失败,请联系技术支持!'
reMsg = '区域名称重复,请修改!'
else:
strsql = f"insert into area (area_name) values ('{area_name}');"
ret = mDBM.do_sql(strsql)
if ret == True:
reStatus = 1
reMsg = '新增区域成功'
else:
reStatus = 0
reMsg = '新增区域失败,请联系技术支持!'
return jsonify({'status': reStatus, 'msg': reMsg})
@api.route('/channel/model/list',methods=['GET'])
@ -279,17 +371,6 @@ async def channel_model_list(): #获取算法列表
reMsg = [{'ID': data[0], 'model_name': data[1],'version':data[2]} for data in datas]
return jsonify(reMsg)
@api.route('/channel/model/linklist',methods=['GET'])
@login_required
async def channel_model_linklist(): #获取算法列表 --关联算法时展示 --没调用。。
ID = request.args.get('ID') #通道ID
strsql = (f"select t1.ID,t2.model_name from channel2model t1 left join model t2 "
f"on t1.model_id=t2.ID where channel_id={ID};")
datas = mDBM.do_select(strsql)
reMsg = {}
if datas:
reMsg = [{'ID': data[0], 'model_name': data[1]} for data in datas]
return jsonify(reMsg)
@api.route('/channel/model/linkmodel',methods=['POST']) #--没调用。。
@login_required

198
web/API/model.py

@ -1,9 +1,11 @@
import os
import shutil
from quart import jsonify, request,session,flash,redirect
from . import api
from web.common.utils import login_required
from core.DBManager import mDBM
from core.Upload_file import allowed_file,check_file,updata_model
from core.ModelManager import mMM
from core.Upload_file import allowed_file,check_file
from myutils.ConfigManager import myCongif
from werkzeug.utils import secure_filename
@ -16,99 +18,155 @@ async def model_list(): #获取算法列表
"proportion":data[4]} for data in datas]
return jsonify(reMsg)
@api.route('/model/upload',methods=['POST'])
def restart_work(mid):
strsql = f"select channel_id from channel2model where model_id = {mid};"
datas = mDBM.do_select(strsql)
if datas: # 有关联
print("有关联")
# 重启通道业务
for data in datas:
mMM.restartC2M(data[0]) # 根该模型关联的所有通道都需要重启工作线程
@api.route('/model/add',methods=['POST'])
@login_required
async def model_upload(): #上传算法文件--需要进行文件校验
async def model_add(): #新增算法
reStatus = 0
reMsg = "有错误!"
form = await request.form
model_name = form['mName']
files = await request.files
if 'file' not in files:
reMsg = '参数错误'
return jsonify({'status': reStatus, 'msg': reMsg})
file = files['file']
if file.filename == '':
reMsg = '没有选择文件'
return jsonify({'status': reStatus, 'msg': reMsg})
#判断算法名称是否重复
strsql = f"select ID from model where model_name='{model_name}';"
data = mDBM.do_select(strsql, 1)
if data:
reMsg = "算法名称重复,请修改!"
else:
if file and allowed_file(file.filename):
filename = secure_filename(file.filename) #安全过滤
file_path = os.path.join(myCongif.get_data('UPLOAD_FOLDER'), filename)
await file.save(file_path)
#检查上传文件的合法性,若符合要求移动到正式路径
filename_pre = filename.rsplit('.',1)[0] #除去到.zip
model_version, model_name_file, model_path = check_file(file_path,filename_pre,2) #itype--2 是算法模型升级 1-系统升级
#删除压缩包
os.remove(file_path)
if model_version and model_path:
#model表插入数据
strsql = (f"insert into model (model_name,version,model_path) values "
f"('{model_name}','{model_version}','{model_path}');")
ret = mDBM.do_sql(strsql)
if ret:
reStatus = 1
reMsg = '算法添加成功'
else:
reMsg = '插入数据库出错,请联系技术支持!!'
else:
reMsg = '升级包不合法,请重新上传!'
else:
reMsg = '只允许上传zip文件'
#新增算法,不需要处理通道关联的相关业务
return jsonify({'status': reStatus, 'msg': reMsg})
@api.route('/model/upgrade',methods=['POST'])
@login_required
async def model_upgrade(): #升级算法,需要先上传算法文件
reStatus = 0
reMsg = "有错误!"
form = await request.form
model_name = form['model_name']
mid = form['mid']
files = await request.files
if 'file' not in files:
flash('参数错误')
return redirect(request.url)
reMsg = '参数错误'
return jsonify({'status': reStatus, 'msg': reMsg})
file = files['file']
if file.filename == '':
flash('没有选择文件')
return redirect(request.url)
reMsg = '没有选择文件'
return jsonify({'status': reStatus, 'msg': reMsg})
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
filename = secure_filename(file.filename) # 安全过滤
file_path = os.path.join(myCongif.get_data('UPLOAD_FOLDER'), filename)
await file.save(file_path)
if check_file(file_path,2): #itype--2 是算法模型升级
strsql = (f"insert into upgrade (itype,filepath,model_name) values (2,'{file_path}','{model_name}')"
f" on conflict(itype,model_name) do update set filepath=excluded.filepath;")
# 检查上传文件的合法性,若符合要求移动到正式路径
filename_pre = filename.rsplit('.', 1)[0] # 除去到.zip
model_version, model_name_file, model_path = check_file(file_path, filename_pre, 2) # itype--2 是算法模型升级 1-系统升级
# 删除压缩包
os.remove(file_path)
if model_version and model_path:
strsql = (f"update model set version='{model_version}',model_path='{model_path}' "
f"where ID={mid};")
ret = mDBM.do_sql(strsql)
# session['model'] = file_path
if ret:
strsql = f"select id from upgrade where itype=2 and model_name='{model_name}';"
data=mDBM.do_select(strsql,1)
reStatus = data[0]
reMsg = "升级包上传成功"
reStatus = 1
reMsg = '升級算法成功'
#重启业务数据
restart_work(mid)
else:
reStatus = 0
reMsg = "升级包上传失败"
return jsonify({'status': reStatus, 'msg': reMsg})
reMsg = '修改数据库出错,请联系技术支持!!'
else:
flash('升级包不合法,请重新上传')
# return redirect(url_for('main.get_html', html='系统管理.html'))
return redirect(request.url)
reMsg = '升级包不合法,请重新上传!'
else:
flash('只允许上传zip文件')
return redirect(request.url)
reMsg = '只允许上传zip文件'
@api.route('/model/add',methods=['POST'])
@login_required
async def model_add(): #新增算法,需要先上传算法文件
model_name = (await request.form)['model_name']
upgrade_id = (await request.form)['upgrade_id'] #升级文件ID
###---需要根据升级包获取模型文件路径,算法版本号等信息,若根据upgrade_id获取不了对应的信息,则返回报错
###
strsql = f"select ID from model where model_name='{model_name}';"
data = mDBM.do_select(strsql,1)
if data:
reStatus = 0
reMsg = "算法名称重复,请修改!"
else:
strsql = f"insert into model (model_name) values ('{model_name}');" #还有参数未写全
ret = mDBM.do_sql(strsql)
if ret:
reStatus = 1
reMsg = "新增算法成功!"
else:
reStatus = 0
reMsg = "新增算法失败,请联系技术支持!"
return jsonify({'status': reStatus, 'msg': reMsg})
@api.route('/model/upgrade',methods=['POST'])
@api.route('/model/del',methods=['POST'])
@login_required
async def model_upgrade(): #升级算法,需要先上传算法文件
return jsonify(1)
async def model_del():
json_data = await request.get_json()
mid = json_data.get('mid')
#删除与该算法关联的通道相关数据
strsql = f"select channel_id from channel2model where model_id = {mid};"
datas = mDBM.do_select(strsql)
if datas: #有关联
#删与通道的关联信息 --c2m,schedule
mDBM.delC2M(mid,2)
#重启通道业务
for data in datas:
mMM.restartC2M(data[0]) #根该模型关联的所有通道都需要重启工作线程
@api.route('/model/config',methods=['GET'])
@login_required
async def model_config(): #获取算法的配置信息 --- list已经获取
ID = request.args.get('ID')
strsql = f"select model_name,version,duration_time,proportion from model where ID={ID};"
#删除算法文件
strsql = f"select model_path from model where ID = {mid};"
data = mDBM.do_select(strsql,1)
reMsg = {"model_name":data[0],"version":data[1],"duration_time":data[2],"proportion":data[3]}
return jsonify(reMsg)
if data:
py_path = data[0]
dir_path = py_path.rsplit('/',1)[0] #正常最后一层应该都是/--手动加的
print(dir_path)
shutil.rmtree(dir_path)
# 删该算法记录
strsql = f"delete from model where ID = {mid};"
mDBM.do_sql(strsql)
#正常来说删除一般不会失败
return jsonify({'status': 1, 'msg': "删除成功"})
@api.route('/model/changecnf',methods=['POST'])
@login_required
async def model_config_change(): #修改算法的配置信息
ID = (await request.form)['ID']
duration_time = (await request.form)['duration_time']
proportion = float((await request.form)['proportion'])
if proportion>0 and proportion < 1:
strsql = f"update model set duration_time='{duration_time}',proportion='{proportion}' where ID={ID};"
ret = mDBM.do_sql(strsql)
if ret:
reStatus = 1
reMsg = "修复算法配置成功"
json_data = await request.get_json()
mid = json_data.get('mid')
reStatus = 0
try:
duration_time = int(json_data.get('duration_time'))
proportion = float(json_data.get('proportion'))
if proportion > 0 and proportion < 1:
strsql = f"update model set duration_time='{duration_time}',proportion='{proportion}' where ID={mid};"
ret = mDBM.do_sql(strsql)
if ret:
reStatus = 1
reMsg = "修改算法配置成功"
#重启-工作线程
restart_work(mid)
else:
reMsg = "修改算法配置失败"
else:
reStatus = 0
reMsg = "修复算法配置失败"
else:
reStatus = 0
reMsg = "占比需要为大于0,小于1的值"
reMsg = "占比阈值需要为大于0,小于1的值"
except ValueError:
reMsg = "数据类型不对!"
return jsonify({'status': reStatus, 'msg': reMsg})

22
web/API/system.py

@ -6,6 +6,7 @@ from core.DBManager import mDBM
from core.Upload_file import allowed_file,check_file,update_system
from myutils.ConfigManager import myCongif
from myutils.ReManager import mReM
from myutils.IPManager import IPM
from werkzeug.utils import secure_filename
@api.route('/system/info',methods=['GET'])
@ -15,11 +16,28 @@ async def system_info(): #获取系统信息
data = mDBM.do_select(strsql,1)
strRet = ""
if data:
strRet = {"ID":data[0],"version":data[1],"dev_ip":data[2],"dev_mask":data[3],"dev_gateway":data[4],
"server_ip":data[5],"server_port":data[6]}
#获取wifilist
wifilist = IPM.get_wifi_list()
connected_wifi = IPM.get_connected_wifi()
print(connected_wifi)
strRet = {"ID":data[0],"version":data[1],"wired_type":data[2],"wired_ip":data[3],"wired_mask":data[4],
"wired_gateway":data[5],"wired_dns":data[6],"wireless_type":data[7],"wireless_ip":data[8],"wireless_mask":data[9],
"wireless_gateway":data[10],"wireless_dns":data[11],"service_ip":data[12],"service_port":data[13],
"ssid":connected_wifi,"wifi_passwd":data[15],"wifi_list":wifilist}
return jsonify(strRet) #它将Python对象转换为JSON格式的字符串,并将其作为HTTP响应的主体返回给客户端,
# 同时设置正确的Content-Type响应头,表明响应主体是JSON格式的数据。
@api.route('/system/area',methods=['GET'])
@login_required
async def area_info(): #获取系统信息
strsql = "select * from area;"
datas = mDBM.do_select(strsql)
strRet = ""
if datas:
strRet = [{'ID':data[0],'area_name':data[1]} for data in datas]
return jsonify(strRet)
@api.route('/system/upload',methods=['POST'])
@login_required
async def system_upload(): #上传系统升级文件

41
web/API/user.py

@ -1,4 +1,5 @@
import os
import hashlib
from quart import Quart, render_template, request, session, redirect, url_for,jsonify,send_file,flash
from quart_sqlalchemy import SQLAlchemy
from quart_session import Session
@ -39,8 +40,9 @@ async def user_login(): #用户登录
#比对用户名和密码
strsql = f"select password from user where username = '{username}'"
db_password = mDBM.do_select(strsql,1)
passwd_md5 = get_md5(password)
if db_password:
if db_password[0] == password: #后续需要对密码进行MD5加默
if db_password[0] == passwd_md5: #后续需要对密码进行MD5加默
print("登录成功")
session['user'] = username
return redirect(url_for('main.get_html', html='view_main.html'))
@ -86,19 +88,29 @@ async def user_adduser(): #新增用户
@api.route('/user/passwd',methods=['POST'])
@login_required
async def user_change_passwd(): #重置密码
username = (await request.form)['username']
password = myCongif.get_data('pw')
strsql = f"update user set password='{password}' where username='{username}';"
ret = mDBM.do_sql(strsql)
if ret == True:
reStatus = 1
reMsg = '重置密码成功'
async def user_change_passwd(): #修改密码
json_data = await request.get_json()
oldpasswd = json_data.get('oldpasswd')
newpasswd = json_data.get('newpasswd')
old_md5= get_md5(oldpasswd)
print(old_md5)
strsql = f"select id from user where password='{old_md5}';"
data = mDBM.do_select(strsql,1)
reStatus = 0
if data:
new_md5 = get_md5(newpasswd)
strsql = f"update user set password = '{new_md5}' where password = '{old_md5}';"
ret = mDBM.do_sql(strsql)
if ret:
reStatus = 1
reMsg = '修改密码成功'
else:
reMsg = '修改密码失败,请联系技术支持!'
else:
reStatus = 0
reMsg = '重置密码失败,请联系管理员处理!'
reMsg = '原密码错误,请确认!'
return jsonify({'status':reStatus,'msg':reMsg})
@api.route('/user/changeuser',methods=['POST'])
@login_required
async def user_change_user_info(): #修改用户信息
@ -124,4 +136,9 @@ async def get_user(user_id):
else:
return jsonify({'error': 'User not found'}), 404
except Exception as e:
return handle_error(e)
return handle_error(e)
def get_md5(value):
md5 = hashlib.md5() # 创建一个md5对象
md5.update(value.encode('utf-8')) # 使用utf-8编码更新待计算的字符串
return md5.hexdigest() # 返回十六进制的MD5值

115
web/API/viedo.py

@ -14,38 +14,6 @@ logger = logging.getLogger(__name__)
#pcs = set() #创建一个空的集合,去重复且无序
pcs = {}
'''
--------------基础信息--后续封装在函数里---------------
'''
# 打开摄像头
# def get_camera():
# cap = cv2.VideoCapture(0)
# if not cap.isOpened():
# raise IOError("Cannot open webcam")
# return cap
#
# cap = get_camera()
# last_image = None
# read_lock = threading.Lock()
# def camera_thread():
# global cap, last_image
# while True:
# try:
# ret, frame = cap.read()
# if not ret:
# logger.warning("Camera disconnected. Reconnecting...")
# cap.release()
# cap = get_camera()
# continue
# frame = cv2.resize(frame, (640, 480)) # 降低视频分辨率
# with read_lock:
# last_image = frame
# time.sleep(1.0/20)
# except Exception as e:
# logger.error(f"Error in camera thread: {e}")
# continue
#threading.Thread(target=camera_thread, daemon=True).start()
'''
---------------------传输--------------------------
'''
@ -146,42 +114,50 @@ async def get_stats(peer_connection):
async def ws_video_feed(channel_id):
print(f"New connection for channel: {channel_id}")
channel_data = mMM.verify_list.get_channel(channel_id)
if channel_data:
verify_rate = int(myCongif.get_data("verify_rate"))
frame_interval = 1.0 / verify_rate #用于帧率控制
error_max_count = verify_rate * int(myCongif.get_data("video_error_count")) #视频帧捕获失败触发提示的上限
sleep_time = int(myCongif.get_data("cap_sleep_time"))
last_frame_time = time.time() # 初始化个读帧时间
icount = 0
while channel_data.bool_run: #这里的多线程并发,还需要验证检查
# 帧率控制帧率
current_time = time.time()
elapsed_time = current_time - last_frame_time
if elapsed_time < frame_interval:
await asyncio.sleep(frame_interval - elapsed_time) # 若小于间隔时间则休眠
last_frame_time = time.time()
#执行视频传输
frame = channel_data.get_last_frame()
if frame is not None:
#img = frame.to_ndarray(format="bgr24")
# ret, buffer = cv2.imencode('.jpg', frame)
# if not ret:
# continue
# frame = buffer.tobytes()
icount = 0
await websocket.send(frame)
else:
icount += 1
if icount > error_max_count:
try:
if channel_data:
verify_rate = int(myCongif.get_data("verify_rate"))
error_max_count = verify_rate * int(myCongif.get_data("video_error_count")) #视频帧捕获失败触发提示的上限
sleep_time = int(myCongif.get_data("cap_sleep_time"))
frame_interval = 1.0 / verify_rate #用于帧率控制
last_frame_time = time.time() # 初始化个读帧时间
icount = 0
while True: #这里的多线程并发,还需要验证检查
# 帧率控制帧率 ---输出暂时不控制帧率,有就传输
current_time = time.time()
elapsed_time = current_time - last_frame_time
if elapsed_time < frame_interval:
await asyncio.sleep(frame_interval - elapsed_time) # 若小于间隔时间则休眠
last_frame_time = time.time()
#执行视频传输
frame = channel_data.get_last_frame()
if frame is not None:
#img = frame.to_ndarray(format="bgr24")
# ret, buffer = cv2.imencode('.jpg', frame)
# if not ret:
# continue
# frame = buffer.tobytes()
icount = 0
error_message = b"video_error"
await websocket.send(error_message)
await asyncio.sleep(sleep_time*1000) #等待视频重连时间
else:
print("没有通道数据!")
error_message = b"client_error"
await websocket.send(error_message)
await asyncio.sleep(0.1) #等0.1秒前端处理时间
await websocket.send(frame)
else:
#print("frame is None")
icount += 1
if icount > error_max_count:
print("视频源无图像")
icount = 0
error_message = b"video_error"
await websocket.send(error_message)
await asyncio.sleep(sleep_time) #等待视频重连时间
#await asyncio.sleep(0.02)
else:
print("没有通道数据!")
error_message = b"client_error"
await websocket.send(error_message)
await asyncio.sleep(0.1) #等0.1秒前端处理时间
except Exception as e:
print(f"WebSocket connection for channel {channel_id} closed: {e}")
finally:
print(f"Cleaning up resources for channel {channel_id}")
@api.route('/shutdown', methods=['POST'])
async def shutdown():#这是全关 --需要修改
@ -216,7 +192,7 @@ async def start_stream(): #开启视频通道,把视频通道编号和元素
strsql = f"select element_id from channel where ID = {channel_id};"
data = mDBM.do_select(strsql,1)
if data:
if data[0] == '':
if not data[0] or data[0] == '':
strsql = f"update channel set element_id = '{element_id}' where ID={channel_id};"
ret = mDBM.do_sql(strsql)
if ret == True:
@ -236,7 +212,6 @@ async def close_stream(): #关闭视频通道
element_id = json_data.get('element_id')
reStatus = 0
reMsg =""
#?关闭视频播放--业务逻辑-待确认后端是否需要执行
#数据库中该通道的关联关系要清除
strsql = f"update channel set element_id = '' where element_id={element_id};"
ret = mDBM.do_sql(strsql)
@ -245,4 +220,6 @@ async def close_stream(): #关闭视频通道
reMsg = '关闭画面成功!'
else:
reMsg = '删除通道与组件关联关系失败,请联系技术支持!'
# ?关闭视频播放--业务逻辑-待确认后端是否需要执行
return jsonify({'status': reStatus, 'msg': reMsg})

BIN
web/main/static/resources/chrome/allow-access.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

BIN
web/main/static/resources/chrome/axure-chrome-extension.crx

Binary file not shown.

BIN
web/main/static/resources/chrome/axure_logo.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

187
web/main/static/resources/chrome/chrome.html

@ -1,187 +0,0 @@
<html>
<head>
<title>Install the Axure RP Chrome Extension</title>
<style type="text/css">
*
{
font-family: NunitoSans, Helvetica, Arial, sans-serif;
}
body
{
text-align: center;
background-color: #fafafa;
}
p
{
font-size: 14px;
line-height: 18px;
color: #333333;
}
div.container
{
width: 980px;
margin-left: auto;
margin-right: auto;
text-align: left;
}
a
{
text-decoration: none;
color: #009dda;
}
.button
{
background: #A502B3;
font: normal 16px Arial, sans-serif;
color: #FFFFFF;
padding: 10px 30px 10px 30px;
border: 2px solid #A502B3;
display: inline-block;
margin-top: 10px;
text-transform: uppercase;
font-size: 14px;
border-radius: 4px;
}
a:hover.button
{
border: 2px solid #A502B3;
color: #A502B3;
background-color: #FFFFFF;
}
div.left
{
width: 400px;
float: left;
margin-right: 80px;
}
div.right
{
width: 400px;
float: left;
}
div.buttonContainer
{
text-align: center;
}
h1
{
font-size: 36px;
color: #333333;
line-height: 50px;
margin-bottom: 20px;
font-weight: normal;
}
h2
{
font-size: 24px;
font-weight: normal;
color: #08639C;
text-align: center;
}
h3
{
font-size: 16px;
color: #333333;
font-weight: normal;
text-transform: uppercase;
}
.heading
{
border-bottom: 1px solid black;
height: 36px;
line-height: 36px;
font-size: 22px;
color: #000000;
}
span.faq
{
font-size: 16px;
line-height: 24px;
font-weight: normal;
text-transform: uppercase;
color: #333333;
display: block;
}
</style>
</head>
<body>
<div class="container">
<br />
<br />
<img src="axure_logo.png" alt="axure" />
<br />
<br />
<h1>
AXURE RP EXTENSION FOR CHROME</h1>
<p style="font-size: 14px; color: #666666; margin-top: 10px;">
Google Chrome requires an extension to view locally stored projects. Alternatively,
upload your RP file to <a href="https://www.axure.cloud">Axure Cloud</a> or use a different
browser. You can also Preview from Axure RP.</p>
<img src="preview-rp.png" alt="preview"/>
<h3 class="heading">
VIEW LOCAL PROJECTS IN CHROME</h3>
<div class="left">
<h3>
1. Install Extension from Chrome Store</h3>
<div class="buttonContainer">
<a class="button" href="https://chrome.google.com/webstore/detail/dogkpdfcklifaemcdfbildhcofnopogp"
target="_blank">Install Extension</a>
</div>
</div>
<div class="right">
<h3>
2. Open "More Tools > Extensions"</h3>
<img src="extensions.png" alt="extensions"/>
</div>
<div style="clear: both; height: 20px;">
&nbsp;</div>
<div class="left">
<h3>
3. View Axure RP Extension Details</h3>
<img src="details.png" alt="extension details"/>
</div>
<div class="right">
<h3>
4. Check "Allow access to file URLs"</h3>
<img src="allow-access.png" alt="allow access"/>
</div>
<div style="clear: both; height: 20px;">
&nbsp;</div>
<div class="left">
<h3>
5. Click the button below</h3>
<div class="buttonContainer">
<a class="button" href="../../start.html">View in Chrome</a>
</div>
</div>
<div style="clear: both; height: 20px;">
</div>
<h3 class="heading">
EXTENSION FAQ</h3>
<p>
<span class="faq">What is a Chrome Extension?</span> Extensions are downloadable
plug-ins for Google Chrome that modify the browser
and allow you additional capabilities.
</p>
<p style="margin-top: 25px;">
<span class="faq">Why do I need to install the extension?</span> Google requires
this extension to be installed to allow the viewing of local files in
Chrome
</p>
<p style="margin-top: 25px; margin-bottom: 25px;">
<span class="faq">Why does this extension require a high access level?</span> This
extension requires a high access level to allow the viewing of the file://
protocol. Axure does not track or access any of your information.
</p>
<h3 class="heading">
WE'RE HERE TO HELP</h3>
<p>
Need help or have any questions? Contact our support team at <a href="mailto:support@axure.com">
support@axure.com</a>.
</p>
<div style="clear: both; height: 20px;">
</div>
</div>
</body>
</html>

BIN
web/main/static/resources/chrome/details.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

BIN
web/main/static/resources/chrome/extensions.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

130
web/main/static/resources/chrome/firefox.html

@ -1,130 +0,0 @@
<html>
<head>
<title>Axure RP - Firefox Local File Restrictions</title>
<style type="text/css">
*
{
font-family: Helvetica, Arial, sans-serif;
}
body
{
text-align: center;
background-color: #fafafa;
}
p
{
font-size: 14px;
line-height: 18px;
color: #333333;
}
div.container
{
width: 980px;
margin-left: auto;
margin-right: auto;
text-align: left;
}
a
{
text-decoration: none;
color: #009dda;
}
.button
{
background: #A502B3;
font: normal 16px Arial, sans-serif;
color: #FFFFFF;
padding: 10px 30px 10px 30px;
border: 2px solid #A502B3;
display: inline-block;
margin-top: 10px;
text-transform: uppercase;
font-size: 14px;
border-radius: 4px;
}
a:hover.button
{
border: 2px solid #A502B3;
color: #A502B3;
background-color: #FFFFFF;
}
div.left
{
width: 400px;
float: left;
margin-right: 80px;
}
div.right
{
width: 400px;
float: left;
}
div.buttonContainer
{
text-align: center;
}
h1
{
font-size: 36px;
color: #333333;
line-height: 50px;
margin-bottom: 20px;
font-weight: normal;
}
h2
{
font-size: 24px;
font-weight: normal;
color: #08639C;
text-align: center;
}
h3
{
font-size: 16px;
line-height: 24px;
color: #333333;
font-weight: normal;
}
.heading
{
border-bottom: 1px solid black;
height: 36px;
line-height: 36px;
font-size: 22px;
color: #000000;
}
span.faq
{
font-size: 16px;
font-weight: normal;
text-transform: uppercase;
color: #333333;
display: block;
}
</style>
</head>
<body>
<div class="container">
<br />
<br />
<img src="axure_logo.png" alt="axure" />
<br />
<h1>
FIREFOX LOCAL FILE RESTRICTIONS</h1>
<p style="font-size: 16px; line-height: 24px; color: #666666; margin-top: 10px;">
Firefox does not permit locally stored files to be viewed. Use Preview to view your projects in progress.
<img src="preview-rp.png" alt="preview"/>
</p>
<p style="font-size: 16px; line-height: 24px; color: #666666; margin-top: 10px;">
Alternatively, you can choose a different web browser, upload your RP file to <a href="https://app.axure.cloud">Axure Cloud</a> or publish the local files to a web server.</p>
<h3 class="heading">
We're Here to Help</h3>
<p>
Need help or have any questions? Drop us a line at <a href="mailto:support@axure.com">
support@axure.com</a>.
</p>
<div style="clear: both; height: 20px;">
</div>
</div>
</body>
</html>

BIN
web/main/static/resources/chrome/preview-rp.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

155
web/main/static/resources/chrome/safari.html

@ -1,155 +0,0 @@
<html>
<head>
<title>Axure RP - Safari Local File Restrictions</title>
<style type="text/css">
*
{
font-family: Helvetica, Arial, sans-serif;
}
body
{
text-align: center;
background-color: #fafafa;
}
p
{
font-size: 14px;
line-height: 18px;
color: #333333;
}
div.container
{
width: 980px;
margin-left: auto;
margin-right: auto;
text-align: left;
}
a
{
text-decoration: none;
color: #009dda;
}
.button
{
background: #A502B3;
font: normal 16px Arial, sans-serif;
color: #FFFFFF;
padding: 10px 30px 10px 30px;
border: 2px solid #A502B3;
display: inline-block;
margin-top: 10px;
text-transform: uppercase;
font-size: 14px;
border-radius: 4px;
}
a:hover.button
{
border: 2px solid #A502B3;
color: #A502B3;
background-color: #FFFFFF;
}
div.left
{
width: 400px;
float: left;
margin-right: 80px;
}
div.right
{
width: 400px;
float: left;
}
div.buttonContainer
{
text-align: center;
}
h1
{
font-size: 36px;
color: #333333;
line-height: 50px;
margin-bottom: 20px;
font-weight: normal;
}
h2
{
font-size: 24px;
font-weight: normal;
color: #08639C;
text-align: center;
}
h3
{
font-size: 16px;
line-height: 24px;
color: #333333;
font-weight: normal;
}
.heading
{
border-bottom: 1px solid black;
height: 36px;
line-height: 36px;
font-size: 22px;
color: #000000;
}
span.faq
{
font-size: 16px;
font-weight: normal;
text-transform: uppercase;
color: #333333;
display: block;
}
</style>
</head>
<body>
<div class="container">
<br />
<br />
<img src="axure_logo.png" alt="axure" />
<br />
<h1>
SAFARI LOCAL FILE RESTRICTIONS</h1>
<p style="font-size: 16px; line-height: 24px; color: #666666; margin-top: 10px;">
To view locally stored projects in Safari, you will need to "disable local file restrictions". Alternatively,
you can upload your RP file to <a href="https://www.axure.cloud">Axure Cloud</a> or publish the local files to a web server. You can also Preview from Axure RP.</p>
<img src="preview-rp.png" alt="preview"/>
<h3 class="heading">
VIEW LOCAL PROJECTS IN SAFARI</h3>
<div class="">
<h3>
1. Open "Safari > Preferences > Advanced" from the top menu, and check the option to "Show Develop menu in menu bar"</h3>
<img src="safari_advanced.png" alt="advanced" />
</div>
<div style="clear: both; height: 20px;">
&nbsp;
</div>
<div class="">
<h3>
2. In the Develop menu that appears in the menu bar, click "Develop > Disable Local File Restrictions" to un-select the menu option</h3>
<img src="safari_restrictions.png" alt="extensions" />
</div>
<div style="clear: both; height: 20px;">
&nbsp;</div>
<div class="left">
<h3>
3. Click the button below
</h3>
<div class="buttonContainer">
<a class="button" href="../../start.html">View in Safari</a>
</div>
</div>
<div style="clear: both; height: 20px;">
</div>
<h3 class="heading">
We're Here to Help</h3>
<p>
Need help or have any questions? Drop us a line at <a href="mailto:support@axure.com">
support@axure.com</a>.
</p>
<div style="clear: both; height: 20px;">
</div>
</div>
</body>
</html>

BIN
web/main/static/resources/chrome/safari_advanced.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

BIN
web/main/static/resources/chrome/safari_restrictions.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 149 KiB

BIN
web/main/static/resources/chrome/splitter.gif

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

BIN
web/main/static/resources/chrome/splitter.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 251 B

49
web/main/static/resources/scripts/aiortc-client-new.js

@ -4,6 +4,17 @@ var channel_list = null;
const fourViewButton = document.getElementById('fourView');
const nineViewButton = document.getElementById('nineView');
//页面即将卸载时执行
window.addEventListener('beforeunload', function (event) {
// 关闭所有 WebSocket 连接或执行其他清理操作
for(let key in video_list){
delete run_list[key];
video_list[key].close();
delete video_list[key];
}
});
//页面加载时执行
document.addEventListener('DOMContentLoaded', async function() {
console.log('DOM fully loaded and parsed');
// 发送请求获取额外数据 --- 这个接口功能有点大了---暂时只是更新通道树2024-7-29
@ -53,6 +64,8 @@ document.addEventListener('DOMContentLoaded', async function() {
}
});
//视频窗口
document.getElementById('fourView').addEventListener('click', function() {
if (fourViewButton.classList.contains('btn-primary')) {
@ -255,39 +268,51 @@ function connectToStream(element_id,channel_id,channel_name) {
const socket = new WebSocket(streamUrl);
video_list[element_id] = socket;
run_list[element_id] = true;
imgElement.style.display = 'block';
berror_state = false;
// 处理连接打开事件
socket.onopen = () => {
console.log('WebSocket connection established');
};
socket.onmessage = function(event) {
// 释放旧的对象URL---需要吗?
// if (imgElement.src) {
// URL.revokeObjectURL(imgElement.src);
// }
const reader = new FileReader();
reader.readAsArrayBuffer(event.data);
reader.onload = () => {
const arrayBuffer = reader.result;
const decoder = new TextDecoder("utf-8");
const decodedData = decoder.decode(arrayBuffer);
if (decodedData === "video_error") { //video_error
displayErrorMessage(imgElement, "该视频源未获取到画面,请检查,默认5分钟后重新链接视频源。");
displayErrorMessage(imgElement, "该视频源未获取到画面,请检查,默认每隔2分钟将重新链接视频源。");
berror_state = true;
} else if(decodedData === "client_error"){ //client_error
run_list[element_id] = false;
displayErrorMessage(imgElement, "该通道节点数据存在问题,请重启或联系技术支持!");
socket.close(); // 停止连接
berror_state = true;
}
else {
const blob = new Blob([arrayBuffer], { type: 'image/jpeg' });
const imageUrl = URL.createObjectURL(blob);
imgElement.src = imageUrl;
imgElement.style.display = 'block';
// imgElement.src = URL.createObjectURL(result);
// imgElement.style.display = 'block';
if(berror_state){
removeErrorMessage(imgElement);
berror_state = false;
}
// 释放旧的对象URL
if (imgElement.src) {
URL.revokeObjectURL(imgElement.src);
}
//blob = new Blob([arrayBuffer], { type: 'image/jpeg' });
imgElement.src = URL.createObjectURL(event.data);
}
};
reader.readAsArrayBuffer(event.data);
//图片显示方案二
// if (imgElement.src) {
// URL.revokeObjectURL(imgElement.src);
// }
// imgElement.src = URL.createObjectURL(event.data);
};
socket.onclose = function() {

2115
web/main/static/resources/scripts/axure/action.js

File diff suppressed because it is too large

771
web/main/static/resources/scripts/axure/adaptive.js

@ -1,771 +0,0 @@
$axure.internal(function($ax) {
$ax.adaptive = {};
$axure.utils.makeBindable($ax.adaptive, ["viewChanged"]);
var _auto = true;
var _autoIsHandledBySidebar = false;
var _views;
var _idToView;
var _enabledViews = [];
var _initialViewToLoad;
var _initialViewSizeToLoad;
var _loadFinished = false;
$ax.adaptive.loadFinished = function() {
if(_loadFinished) return;
_loadFinished = true;
if($ax.adaptive.currentViewId) $ax.viewChangePageAndMasters();
else $ax.postAdaptiveViewChanged();
};
var _handleResize = function(forceSwitchTo) {
if(!_auto) return;
if(_auto && _autoIsHandledBySidebar && !forceSwitchTo) return;
var $window = $(window);
var height = $window.height();
var width = $window.width();
var toView = _getAdaptiveView(width, height);
var toViewId = toView && toView.id;
_switchView(toViewId, forceSwitchTo);
};
var _setAuto = $ax.adaptive.setAuto = function(val) {
if(_auto != val) {
_auto = Boolean(val);
}
};
var _setLineImage = function(id, imageUrl) {
$jobj(id).attr('src', imageUrl);
};
var _switchView = function (viewId, forceSwitchTo) {
//if(!$ax.pageData.isAdaptiveEnabled) return;
var previousViewId = $ax.adaptive.currentViewId;
if(typeof previousViewId == 'undefined') previousViewId = '';
if(typeof viewId == 'undefined') viewId = '';
if (viewId == previousViewId) {
if(forceSwitchTo) $ax.postAdaptiveViewChanged(forceSwitchTo);
return;
}
$ax('*').each(function(obj, elementId) {
if (!$ax.public.fn.IsTreeNodeObject(obj.type)) return;
if(!obj.hasOwnProperty('isExpanded')) return;
var query = $ax('#' + elementId);
var defaultExpanded = obj.isExpanded;
query.expanded(defaultExpanded);
});
// reset all the inline positioning from move and rotate actions including size and transformation
$axure('*').each(function (diagramObject, elementId) {
if(diagramObject.isContained) return;
if($ax.getParentRepeaterFromElementIdExcludeSelf(elementId)) return;
var element = document.getElementById(elementId);
if(element) {
var resetCss = {
top: "", left: "", width: "", height: "", opacity: "",
transform: "", webkitTransform: "", MozTransform: "", msTransform: "", OTransform: ""
};
var query = $(element);
query.css(resetCss);
var isPanel = $ax.public.fn.IsDynamicPanel(diagramObject.type);
if(!isPanel || diagramObject.fitToContent) { //keeps size on the panel states when switching adaptive views to optimize fit to panel
if(diagramObject.fitToContent) $ax.dynamicPanelManager.setFitToContentCss(elementId, true);
var children = query.children();
if(children.length) children.css(resetCss);
}
$ax.dynamicPanelManager.resetFixedPanel(diagramObject, element);
$ax.dynamicPanelManager.resetAdaptivePercentPanel(diagramObject, element);
}
});
$ax.adaptive.currentViewId = viewId; // we need to set this so the enabled and selected styles will apply properly
if(previousViewId) {
$ax.style.clearAdaptiveStyles();
$('*').removeClass(previousViewId);
} else {
$ax.style.reselectElements();
}
$axure('*').each(function (obj, elementId) {
if($ax.getParentRepeaterFromElementIdExcludeSelf(elementId)) return;
$ax.style.updateElementIdImageStyle(elementId); // When image override exists, fix styling/borders
});
//$ax.style.startSuspendTextAlignment();
// reset all the images only if we're going back to the default view
if(!viewId) {
$axure('*').each(function (diagramObject, elementId) {
if($ax.getParentRepeaterFromElementIdExcludeSelf(elementId)) return;
$ax.placeholderManager.refreshPlaceholder(elementId);
var images = diagramObject.images;
if(diagramObject.type == 'horizontalLine' || diagramObject.type == 'verticalLine') {
var startImg = images['start~'];
_setLineImage(elementId + "_start", startImg);
var endImg = images['end~'];
_setLineImage(elementId + "_end", endImg);
var lineImg = images['line~'];
_setLineImage(elementId + "_line", lineImg);
} else if(diagramObject.type == $ax.constants.CONNECTOR_TYPE) {
_setAdaptiveConnectorImages(elementId, images, '');
} else if(images) {
if (diagramObject.generateCompound) {
if($ax.style.IsWidgetDisabled(elementId)) {
disabledImage = _getImageWithTag(images, 'disabled~');
if(disabledImage) $ax.style.applyImage(elementId, disabledImage, 'disabled');
return;
}
if($ax.style.IsWidgetSelected(elementId)) {
selectedImage = _getImageWithTag(images, 'selected~');
if(selectedImage) $ax.style.applyImage(elementId, selectedImage, 'selected');
return;
}
$ax.style.applyImage(elementId, _getImageWithTag(images, 'normal~'), 'normal');
} else {
if ($ax.style.IsWidgetDisabled(elementId)) {
var disabledImage = _matchImage(elementId, images, [], 'disabled', true);
if (disabledImage) $ax.style.applyImage(elementId, disabledImage, 'disabled');
return;
}
if ($ax.style.IsWidgetSelected(elementId)) {
var selectedImage = _matchImage(elementId, images, [], 'selected', true);
if (selectedImage) $ax.style.applyImage(elementId, selectedImage, 'selected');
return;
}
var normalImage = _matchImage(elementId, images, [], 'normal', true);
$ax.style.applyImage(elementId, normalImage, 'normal');
}
}
//align all text
var child = $jobj(elementId).children('.text');
if(child.length) $ax.style.transformTextWithVerticalAlignment(child[0].id, function() { });
});
// we have to reset visibility if we aren't applying a new view
$ax.visibility.resetLimboAndHiddenToDefaults();
$ax.visibility.clearMovedAndResized();
$ax.repeater.refreshAllRepeaters();
$ax.dynamicPanelManager.updateParentsOfNonDefaultFitPanels();
$ax.dynamicPanelManager.updatePercentPanelCache($ax('*'));
} else {
$ax.visibility.clearLimboAndHidden();
$ax.visibility.clearMovedAndResized();
_applyView(viewId);
$ax.repeater.refreshAllRepeaters();
$ax.dynamicPanelManager.updateAllLayerSizeCaches();
$ax.dynamicPanelManager.updateParentsOfNonDefaultFitPanels();
}
$ax.annotation.updateAllFootnotes();
//$ax.style.resumeSuspendTextAlignment();
$ax.adaptive.triggerEvent('viewChanged', {});
if(_loadFinished) $ax.viewChangePageAndMasters(forceSwitchTo);
};
var _getImageWithTag = function(image, tag) {
var flattened = {};
for (var component in image) {
var componentImage = image[component][tag];
if(componentImage) flattened[component] = componentImage;
}
return flattened;
}
// gets the inheritance chain of a particular view.
var _getAdaptiveIdChain = $ax.adaptive.getAdaptiveIdChain = function(viewId) {
if(!viewId) return [];
var view = _idToView[viewId];
var chain = [];
var current = view;
while(current) {
chain[chain.length] = current.id;
current = _idToView[current.baseViewId];
}
return chain.reverse();
};
var _getMasterAdaptiveIdChain = $ax.adaptive.getMasterAdaptiveIdChain = function (masterId, viewId) {
if (!viewId) return [];
var master = $ax.pageData.masters[masterId];
var masterViews = master.adaptiveViews;
var idToMasterView = {};
if (masterViews && masterViews.length > 0) {
for (var i = 0; i < masterViews.length; i++) {
var view = masterViews[i];
idToMasterView[view.id] = view;
}
}
if (!idToMasterView) return [];
var view = idToMasterView[viewId];
var chain = [];
var current = view;
while (current) {
chain[chain.length] = current.id;
current = idToMasterView[current.baseViewId];
}
return chain.reverse();
};
var _getPageStyle = $ax.adaptive.getPageStyle = function() {
var currentViewId = $ax.adaptive.currentViewId;
var adaptiveChain = _getAdaptiveIdChain(currentViewId);
var currentStyle = $.extend({}, $ax.pageData.page.style);
for(var i = 0; i < adaptiveChain.length; i++) {
var viewId = adaptiveChain[i];
$.extend(currentStyle, $ax.pageData.page.adaptiveStyles[viewId]);
}
return currentStyle;
};
var _setAdaptiveLineImages = function(elementId, images, viewIdChain) {
for(var i = viewIdChain.length - 1; i >= 0; i--) {
var viewId = viewIdChain[i];
var startImg = images['start~' + viewId];
if(startImg) {
_setLineImage(elementId + "_start", startImg);
var endImg = images['end~' + viewId];
_setLineImage(elementId + "_end", endImg);
var lineImg = images['line~' + viewId];
_setLineImage(elementId + "_line", lineImg);
break;
}
}
};
var _setAdaptiveConnectorImages = function (elementId, images, view) {
var conn = $jobj(elementId);
var count = conn.children().length-1; // -1 for rich text panel
for(var i = 0; i < count; i++) {
var img = images['' + i + '~' + view];
$jobj(elementId + '_seg' + i).attr('src', img);
}
};
var _applyView = $ax.adaptive.applyView = function(viewId, query) {
var limboIds = {};
var hiddenIds = {};
var jquery;
if(query) {
jquery = query.jQuery();
jquery = jquery.add(jquery.find('*'));
var jqueryAnn = $ax.annotation.jQueryAnn(query);
jquery = jquery.add(jqueryAnn);
} else {
jquery = $('*').not('#ios-safari-fixed');
query = $ax('*');
}
jquery.addClass(viewId);
var viewIdChain = _getAdaptiveIdChain(viewId);
// this could be made more efficient by computing it only once per object
query.each(function(diagramObject, elementId) {
_applyAdaptiveViewOnObject(diagramObject, elementId, viewIdChain, viewId, limboIds, hiddenIds);
});
$ax.visibility.addLimboAndHiddenIds(limboIds, hiddenIds, query);
//$ax.dynamicPanelManager.updateAllFitPanelsAndLayerSizeCaches();
$ax.dynamicPanelManager.updatePercentPanelCache(query);
};
var _applyAdaptiveViewOnObject = function(diagramObject, elementId, viewIdChain, viewId, limboIds, hiddenIds) {
var adaptiveChain = [];
for(var i = 0; i < viewIdChain.length; i++) {
var viewId = viewIdChain[i];
var viewStyle = diagramObject.adaptiveStyles[viewId];
if(viewStyle) {
adaptiveChain[adaptiveChain.length] = viewStyle;
if (viewStyle.size) $ax.public.fn.convertToSingleImage($jobj(elementId));
}
}
var state = $ax.style.generateState(elementId);
// set the image
var images = diagramObject.images;
if(images) {
if(diagramObject.type == 'horizontalLine' || diagramObject.type == 'verticalLine') {
_setAdaptiveLineImages(elementId, images, viewIdChain);
} else if (diagramObject.type == $ax.constants.CONNECTOR_TYPE) {
_setAdaptiveConnectorImages(elementId, images, viewId);
} else if (diagramObject.generateCompound) {
var compoundUrl = _matchImageCompound(diagramObject, elementId, viewIdChain, state);
if (compoundUrl) $ax.style.applyImage(elementId, compoundUrl, state);
}else {
var imgUrl = _matchImage(elementId, images, viewIdChain, state);
if(imgUrl) $ax.style.applyImage(elementId, imgUrl, state);
}
}
// addaptive override style (not including default style props)
var adaptiveStyle = $ax.style.computeAllOverrides(elementId, undefined, state, viewId);
// this style INCLUDES the object's my style
var compoundStyle = $.extend({}, diagramObject.style, adaptiveStyle);
// if (diagramObject.owner.type == 'Axure:Master' && diagramObject.adaptiveStyles) {
// adaptiveStyle = $ax.style.computeFullStyle(elementId, state, viewId);
// }
if(!diagramObject.isContained) {
$ax.style.setAdaptiveStyle(elementId, adaptiveStyle);
}
var scriptId = $ax.repeater.getScriptIdFromElementId(elementId);
if(compoundStyle.limbo && !diagramObject.isContained) limboIds[scriptId] = true;
// sigh, javascript. we need the === here because undefined means not overriden
if(compoundStyle.visible === false) hiddenIds[scriptId] = true;
};
var _matchImage = function(id, images, viewIdChain, state, doNotProgress) {
var override = $ax.style.getElementImageOverride(id, state);
if(override) return override;
if(!images) return undefined;
let scriptId = $ax.repeater.getScriptIdFromElementId(id);
if(state == 'disabled' && $ax.style.IsWidgetSelected(id) || state == 'selected' && $ax.style.IsWidgetDisabled(id)) {
let diagramObject = $ax.getObjectFromElementId(id);
if(diagramObject && $ax.public.fn.IsSelectionButton(diagramObject.type)) {
var selectedDisabled = $ax.constants.SELECTED_DISABLED;
}
}
// first check all the images for this state
for(let i = viewIdChain.length - 1; i >= 0; i--) {
let viewId = viewIdChain[i];
if(selectedDisabled) {
let img = findImage(images, scriptId, selectedDisabled, viewId)
if(img) return img;
} else {
let img = findImage(images, scriptId, state, viewId);
if (img) return img;
}
}
// check for the default state style
if(selectedDisabled) {
let defaultStateImage = findImage(images, scriptId, selectedDisabled)
if(defaultStateImage) return defaultStateImage;
} else {
let defaultStateImage = findImage(images, scriptId, state);
if (defaultStateImage) return defaultStateImage;
}
if(doNotProgress) return undefined;
state = $ax.style.progessState(state);
if (state) return _matchImage(scriptId, images, viewIdChain, state);
// SHOULD NOT REACH HERE! NORMAL SHOULD ALWAYS CATCH AT THE DEFAULT!
return images['normal~']; // this is the default
};
let findImage = function(images, scriptId, state, viewId) {
if(!images) return undefined;
if(!viewId) viewId = "";
let withScript = scriptId + "~" + state + "~" + viewId;
let img = images[withScript];
if(!img) img = images[state + "~" + viewId];
return img;
}
var _matchImageCompound = function(diagramObject, id, viewIdChain, state) {
var images = [];
for(var i = 0; i < diagramObject.compoundChildren.length; i++) {
var component = diagramObject.compoundChildren[i];
images[component] = _matchImage(id, diagramObject.images[component], viewIdChain, state);
}
return images;
};
$ax.adaptive.getImageForStateAndView = function(id, state) {
var viewIdChain = _getAdaptiveIdChain($ax.adaptive.currentViewId);
var diagramObject = $ax.getObjectFromElementId(id);
if (diagramObject.generateCompound) return _matchImageCompound(diagramObject, id, viewIdChain, state);
else return _matchImage(id, diagramObject.images, viewIdChain, state);
};
var _getAdaptiveView = function(winWidth, winHeight) {
var _isViewOneGreaterThanTwo = function (view1, view2, winHeight) {
if (view1.size.width > view2.size.width) return true;
if (view1.size.width == view2.size.width) {
if (view2.size.height <= winHeight) return view1.size.height > view2.size.height && view1.size.height <= winHeight;
else return view1.size.height < view2.size.height;
}
return false;
};
var _isViewOneLessThanTwo = function(view1, view2) {
var width2 = view2.size.width || 1000000; // artificially large number
var height2 = view2.size.height || 1000000;
var width1 = view1.size.width || 1000000;
var height1 = view1.size.height || 1000000;
return width1 < width2 || (width1 == width2 && height1 < height2);
};
var _isWindowWidthGreaterThanViewWidth = function(view, width) {
return width >= view.size.width;
};
var _isWindowWidthLessThanViewWidth = function(view1, width) {
var viewWidth = view1.size.width || 1000000;
return width <= viewWidth;
};
var greater = undefined;
var less = undefined;
var defaultView = $ax.pageData.defaultAdaptiveView;
if (_isWindowWidthGreaterThanViewWidth(defaultView, winWidth, winHeight)) greater = defaultView;
less = defaultView;
for(var i = 0; i < _enabledViews.length; i++) {
var view = _enabledViews[i];
if(_isWindowWidthGreaterThanViewWidth(view, winWidth, winHeight)) {
if(!greater || _isViewOneGreaterThanTwo(view, greater, winHeight)) greater = view;
}
if(_isWindowWidthLessThanViewWidth(view, winWidth, winHeight)) {
if(!less || _isViewOneLessThanTwo(view, less)) less = view;
}
}
return greater || less;
};
var _isAdaptiveInitialized = function() {
return typeof _idToView != 'undefined';
};
$ax.messageCenter.addMessageListener(function(message, data) {
//If the adaptive plugin hasn't been initialized yet then
//save the view to load so that it can get set when initialize occurs
if (message == 'switchAdaptiveView') {
if (!$axure.utils.isInPlayer()) return;
var href = window.location.href.split('#')[0];
var lastSlash = href.lastIndexOf('/');
href = href.substring(lastSlash + 1);
if(href != data.src) return;
var view = data.view == 'auto' ? undefined : (data.view == 'default' ? '' : data.view);
if(!_isAdaptiveInitialized()) {
_initialViewToLoad = view;
} else _handleLoadViewId(view);
} else if (message == 'setAdaptiveViewForSize') {
if (!$axure.utils.isInPlayer()) return;
_autoIsHandledBySidebar = true;
if(!_isAdaptiveInitialized()) {
_initialViewSizeToLoad = data;
} else _handleSetViewForSize(data.width, data.height);
} else if (message == 'getScale') {
if (!$axure.utils.isInPlayer()) return;
var prevScaleN = data.prevScaleN;
var newScaleN = 1;
var contentOriginOffset = 0;
var $body = $('body');
$body.css('height', '');
if (data.scale != 0) {
var adjustScrollScale = false;
if ($('html').getNiceScroll().length == 0 && !MOBILE_DEVICE) {
//adding nicescroll so width is correct when getting scale
_addNiceScroll($('html'), { emulatetouch: false, horizrailenabled: false });
adjustScrollScale = true;
}
$('html').css('overflow-x', 'hidden');
var bodyWidth = $body.width();
var isCentered = $body.css('position') == 'relative';
// screen width does not adjust on screen rotation for iOS (width is always shorter screen measurement)
var isLandscape = window.orientation != 0 && window.orientation != 180;
var mobileWidth = (IOS ? (isLandscape ? window.screen.height : window.screen.width) : window.screen.width) - data.panelWidthOffset;
var scaleN = newScaleN = (MOBILE_DEVICE ? mobileWidth : $(window).width()) / bodyWidth;
if (data.scale == 2) {
var pageSize = $ax.public.fn.getPageSize();
var hScaleN = (MOBILE_DEVICE ? data.viewportHeight : $(window).height()) / Math.max(1, pageSize.bottom);
if (hScaleN < scaleN) {
scaleN = newScaleN = hScaleN;
}
if (isCentered) contentOriginOffset = scaleN * (bodyWidth / 2);
}
if ((SAFARI && IOS) || SHARE_APP) {
var pageSize = $ax.public.fn.getPageSize();
$body.first().css('height', pageSize.bottom + 'px');
} //else $body.css('height', $body.height() + 'px');
if (adjustScrollScale) {
_removeNiceScroll($('html'));
_addNiceScroll($('html'), { emulatetouch: false, horizrailenabled: false, cursorwidth: Math.ceil(6 / newScaleN) + 'px', cursorborder: 1 / newScaleN + 'px solid #fff', cursorborderradius: 5 / newScaleN + 'px' });
}
}
var contentScale = {
scaleN: newScaleN,
prevScaleN: prevScaleN,
contentOriginOffset: contentOriginOffset,
clipToView: data.clipToView,
viewportHeight: data.viewportHeight,
viewportWidth: data.viewportWidth,
panelWidthOffset: data.panelWidthOffset,
scale: data.scale
};
$axure.messageCenter.postMessage('setContentScale', contentScale);
} else if (message == 'setDeviceMode') {
if (!$axure.utils.isInPlayer()) return;
_isDeviceMode = data.device;
if (data.device) {
// FIXES firefox cursor not staying outside initial device frame border
// SAFARI needs entire content height so that trackpad can be disabled
//if (FIREFOX || (SAFARI && !IOS)) {
// var pageSize = $ax.public.fn.getPageSize();
// $('html').css('height', pageSize.bottom + 'px');
//}
_removeNiceScroll($('html'), true);
if (!MOBILE_DEVICE) {
_addNiceScroll($('html'), { emulatetouch: true, horizrailenabled: false }, true);
$('html').addClass('mobileFrameCursor');
$('html').css('cursor', 'url(resources/css/images/touch.cur), auto');
$('html').css('cursor', 'url(resources/css/images/touch.svg) 32 32, auto');
$('html').css('overflow-x', 'hidden');
if (IE) {
document.addEventListener("click", function () {
// IE still sometimes wants an argument here
this.activeElement.releasePointerCapture();
}, false);
}
if ($axure.browser.isEdge) {
document.addEventListener("pointerdown", function (e) {
this.activeElement.releasePointerCapture(e.pointerId);
}, false);
}
$ax.dynamicPanelManager.initMobileScroll();
}
// Gives horizontal scroll to android in 100% (handled outside of iframe)
$('html').css('overflow-x', 'hidden');
$('body').css('margin', '0px');
$(function () { _setHorizontalScroll(false); });
} else {
_removeNiceScroll($('html'), true);
$('html').css('overflow-x', '');
$('html').css('cursor', '');
//$('html').removeAttr('style');
$('body').css('margin', '');
$('html').removeClass('mobileFrameCursor');
$(function () { _setHorizontalScroll(!data.scaleToWidth); });
$ax.dynamicPanelManager.initMobileScroll();
}
}
});
var _isDeviceMode = false;
$ax.adaptive.isDeviceMode = function () {
return _isDeviceMode;
}
var _isHtmlQuery = function ($container) { return $container.length > 0 && $container[0] == $('html')[0]; }
var _removeNiceScroll = $ax.adaptive.removeNiceScroll = function ($container, blockResetScroll) {
if (!blockResetScroll) {
$container.scrollLeft(0);
$container.scrollTop(0);
}
var nS = $container.getNiceScroll();
var emulateTouch = nS.length > 0 && nS[0].opt.emulateTouch;
nS.remove();
//clean up nicescroll css
if (IE) $container.css({ '-ms-overflow-y': '', 'overflow-y': '', '-ms-overflow-style': '', '-ms-touch-action': '' });
if (!emulateTouch) return;
if (_isHtmlQuery($container)) {
$('#scrollContainer').remove();
$('#base').off('mouseleave.ax');
} else {
$container.off('mouseleave.ax');
}
}
var _addNiceScrollExitDetector = function ($container) {
if (_isHtmlQuery($container)) {
// add a fixed div the size of the frame that will not move as we scroll like html,body,#base,children
// so we are able to detect when the mouse leaves that frame area if there is no existing DOM element
var $scrollContainer = $("<div id='scrollContainer'></div>");
var $body = $('body');
$scrollContainer.css({
'position': 'fixed',
'width': $body.width(),
'height': $body.height()
});
// we want #base div to handle the event so that it bubbles up from the scrollContainer div which
// handles the bounds of the frame in case there was no previously exisiting child to bubble up the
// event or if the user has clicked on an existing child node to start the emulated touch scroll
var $base = $('#base');
$base.on('mouseleave.ax', function (e) {
var nS = $container.getNiceScroll();
for (var i = 0; i < nS.length; ++i)
nS[i].ontouchend(e);
});
// need to prepend so it is first child in DOM and doesn't block mouse events to other children which
// would make them unable to scroll
$base.prepend($scrollContainer);
} else {
$container.on('mouseleave.ax', function (e) {
var nS = $container.getNiceScroll();
for (var i = 0; i < nS.length; ++i)
nS[i].ontouchend(e);
});
}
}
var _addNiceScroll = $ax.adaptive.addNiceScroll = function ($container, options, blockResetScroll) {
if (!blockResetScroll) {
$container.scrollLeft(0);
$container.scrollTop(0);
}
$container.niceScroll(options);
// RP-581 add handling to stop scroll on mouse leave if enable cursor-drag scrolling like touch devices in desktop computer
if (options.emulatetouch) _addNiceScrollExitDetector($container);
//clean up nicescroll css so child scroll containers show scrollbars in IE
if (IE) $container.css({ '-ms-overflow-y': '', '-ms-overflow-style': '' });
if(IOS) $container.css({ 'overflow-y': ''});
}
//given the element, find the container that's using nice scroll (including the element itself)
$ax.adaptive.getNiceScrollContainer = function(element) {
var parent = element;
while(parent) {
if($(parent).getNiceScroll().length > 0) return parent;
parent = parent.parentElement;
}
return undefined;
}
$ax.adaptive.updateMobileScrollOnBody = function () {
var niceScroll = $('html').getNiceScroll();
if (niceScroll.length == 0) return;
niceScroll.resize();
}
var _setTrackpadHorizontalScroll = function (active) {
var preventScroll = function (e) {
if (Math.abs(e.wheelDeltaX) != 0) {
e.preventDefault();
}
}
if (!active) {
document.body.addEventListener("mousewheel", preventScroll, { passive: false });
document.getElementById('html').addEventListener("mousewheel", preventScroll, { passive: false });
} else {
document.body.removeEventListener("mousewheel", preventScroll, { passive: false });
document.getElementById('html').removeEventListener("mousewheel", preventScroll, { passive: false });
}
}
var _setHorizontalScroll = function (active) {
var $body = $(document);
if (!active) {
$body.bind('scroll', function () {
if ($body.scrollLeft() !== 0) {
$body.scrollLeft(0);
}
});
} else {
$body.unbind('scroll');
}
}
$ax.adaptive.setAdaptiveView = function(view) {
var viewIdForSitemapToUnderstand = view == 'auto' ? undefined : (view == 'default' ? '' : view);
if(!_isAdaptiveInitialized()) {
_initialViewToLoad = viewIdForSitemapToUnderstand;
} else _handleLoadViewId(viewIdForSitemapToUnderstand);
};
$ax.adaptive.initialize = function() {
_views = $ax.pageData.adaptiveViews;
_idToView = {};
var useViews = $ax.document.configuration.useViews;
if(_views && _views.length > 0) {
for(var i = 0; i < _views.length; i++) {
var view = _views[i];
_idToView[view.id] = view;
if(useViews) _enabledViews[_enabledViews.length] = view;
}
if(_autoIsHandledBySidebar && _initialViewSizeToLoad) _handleSetViewForSize(_initialViewSizeToLoad.width, _initialViewSizeToLoad.height);
else _handleLoadViewId(_initialViewToLoad);
}
$axure.resize(function(e) {
_handleResize();
$ax.postResize(e); //window resize fires after view changed
});
};
var _handleLoadViewId = function (loadViewId, forceSwitchTo) {
if(typeof loadViewId != 'undefined') {
_setAuto(false);
_switchView(loadViewId != 'default' ? loadViewId : '', forceSwitchTo);
} else {
_setAuto(true);
_handleResize(forceSwitchTo);
}
};
var _handleSetViewForSize = function (width, height) {
var toView = _getAdaptiveView(width, height);
var toViewId = toView && toView.id;
_switchView(toViewId, "auto");
};
$ax.adaptive.getSketchKey = function() {
return $ax.pageData.sketchKeys[$ax.adaptive.currentViewId || ''];
}
});

178
web/main/static/resources/scripts/axure/annotation.js

@ -1,178 +0,0 @@
// ******* Annotation MANAGER ******** //
$axure.internal(function($ax) {
var NOTE_SIZE = 10;
var _annotationManager = $ax.annotation = {};
var _updateLinkLocations = $ax.annotation.updateLinkLocations = function(elementId) {
var textId = $ax.GetTextPanelId(elementId);
if(!textId) return;
var rotation = $ax.getObjectFromElementId(elementId).style.rotation;
//we have to do this because webkit reports the post-transform position but when you set positions it's pre-transform
if(WEBKIT && rotation) {
//we can dynamiclly rotate a widget now, show need to remember the transform rather than just remove it
//here jquery.css will return 'none' if element is display none
var oldShapeTransform = document.getElementById(elementId).style['-webkit-transform'];
var oldTextTransform = document.getElementById(textId).style['-webkit-transform'];
$('#' + elementId).css('-webkit-transform', 'scale(1)');
$('#' + textId).css('-webkit-transform', 'scale(1)');
}
$('#' + textId).find('div[id$="_ann"]').each(function(index, value) {
var elementId = value.id.replace('_ann', '');
var $link = $('#' + elementId);
var annPos = $link.position();
annPos.left += $link.width();
//var annPos = $(value).position();
var left = annPos.left;// - NOTE_SIZE;
var top = annPos.top - 5;
$(value).css('left', left).css('top', top);
});
//undo the transform reset
if(WEBKIT && rotation) {
$('#' + elementId).css('-webkit-transform', oldShapeTransform || '');
$('#' + textId).css('-webkit-transform', oldTextTransform || '');
}
};
var _toggleAnnotationDialog = function (elementId, event) {
let win = $(window);
let scrollY = win.scrollTop();
let scrollX = win.scrollLeft();
let x = event.pageX - scrollX;
let y = event.pageY - scrollY;
let frameElement = window.frameElement;
let parent = window.parent;
//ann dialog is relative to mainFrame, exclude the mainFrame location so the notes shows up correctly in device mode
while(frameElement && frameElement.name !== 'mainFrame') {
let rect = frameElement.getBoundingClientRect();
x += rect.x;
y += rect.y;
if(!parent) break;
frameElement = parent.frameElement;
parent = parent.parent;
}
let messageData = { id: elementId, x: x, y: y }
if (!$axure.utils.isInPlayer()) messageData.page = $ax.pageData.notesData;
$ax.messageCenter.postMessage('toggleAnnDialog', messageData);
}
$ax.annotation.initialize = function () {
_createFootnotes($ax('*'), true);
}
var _createFootnotes = $ax.annotation.createFootnotes = function(query, create) {
if(!$ax.document.configuration.showAnnotations) return;
var widgetNotes = $ax.pageData.notesData.widgetNotes;
if (widgetNotes) {
var ownerToFns = $ax.pageData.notesData.ownerToFns;
if(!$.isEmptyObject(ownerToFns)) {
query.each(function(dObj, elementId) {
var fns = ownerToFns[dObj.id];
if (fns !== undefined) {
var elementIdQuery = $('#' + elementId);
if (dObj.type == 'hyperlink') {
var parentId = $ax.GetParentIdFromLink(elementId);
if (create) {
elementIdQuery.after("<div id='" + elementId + "_ann' class='annnote'>&#8203;</div>");
appendFns($('#' + elementId + "_ann"), fns);
}
_updateLinkLocations(parentId);
} else {
if (create) {
elementIdQuery.after("<div id='" + elementId + "_ann' class='annnote'>&#8203;</div>");
appendFns($('#' + elementId + "_ann"), fns);
}
_adjustIconLocation(elementId, dObj);
}
if (create) {
$('#' + elementId + "_ann").click(function (e) {
_toggleAnnotationDialog(dObj.id, e);
return false;
});
var isVisible = true;
var isMaster = $ax.public.fn.IsReferenceDiagramObject(dObj.type);
if (isMaster) isVisible = dObj.visible;
else isVisible = $ax.visibility.IsIdVisible(elementId);
if (!isVisible) {
var ann = document.getElementById(elementId + "_ann");
if (ann) $ax.visibility.SetVisible(ann, false);
}
}
}
});
}
}
function appendFns($parent, fns) {
for (var index = 0; index < fns.length; index++) {
$parent.append("<div class='annnotelabel' >" + fns[index] + "</div>");
}
}
};
$ax.annotation.updateAllFootnotes = function () {
_createFootnotes($ax('*'), false);
}
$ax.annotation.jQueryAnn = function(query) {
var elementIds = [];
query.each(function(diagramObject, elementId) {
if(diagramObject.annotation) elementIds[elementIds.length] = elementId;
});
var elementIdSelectors = jQuery.map(elementIds, function(elementId) { return '#' + elementId + '_ann'; });
var jQuerySelectorText = (elementIdSelectors.length > 0) ? elementIdSelectors.join(', ') : '';
return $(jQuerySelectorText);
};
$(window.document).ready(function() {
//$ax.annotation.InitializeAnnotations($ax(function(dObj) { return dObj.annotation; }));
$ax.messageCenter.addMessageListener(function(message, data) {
//If the annotations are being hidden via the Sitemap toggle button, hide any open dialogs
if(message == 'annotationToggle') {
if (data == true) {
$('div.annnote').show();
} else {
$('div.annnote').hide();
}
}
});
});
//adjust annotation location to a element's top right corner
var _adjustIconLocation = $ax.annotation.adjustIconLocation = function(id, dObj) {
var ann = document.getElementById(id + "_ann");
if(ann) {
var corners = $ax.public.fn.getCornersFromComponent(id);
var width = $(ann).width();
var newTopRight = $ax.public.fn.vectorPlus(corners.relativeTopRight, corners.centerPoint);
//note size is 14x8, this is how rp calculated it as well
ann.style.left = (newTopRight.x - width) + "px";
var elementType = dObj ? dObj.type : $ax.getTypeFromElementId(id);
var yOffset = $ax.public.fn.IsTableCell(elementType) ? 0 : -8;
ann.style.top = (newTopRight.y + yOffset) + "px";
}
var ref = document.getElementById(id + "_ref");
if(ref) {
if(!corners) corners = $ax.public.fn.getCornersFromComponent(id);
var newBottomRight = $ax.public.fn.vectorPlus(corners.relativeBottomRight, corners.centerPoint);
ref.style.left = (newBottomRight.x - 8) + 'px';
ref.style.top = (newBottomRight.y - 10) + 'px';
}
}
});

407
web/main/static/resources/scripts/axure/axQuery.js

@ -1,407 +0,0 @@
$axure = function(query) {
return $axure.query(query);
};
// ******* AxQuery and Page metadata ******** //
(function() {
var $ax = function() {
var returnVal = $axure.apply(this, arguments);
var axFn = $ax.fn;
for (var key in axFn) {
returnVal[key] = axFn[key];
}
return returnVal;
};
$ax.public = $axure;
$ax.fn = {};
$axure.internal = function(initFunction) {
//Attach messagecenter to $ax object so that it can be used in viewer.js, etc in internal scope
if(!$ax.messageCenter) $ax.messageCenter = $axure.messageCenter;
return initFunction($ax);
};
var _lastFiredResize = 0;
var _resizeFunctions = [];
var _lastTimeout;
var _fireResize = function() {
if (_lastTimeout) window.clearTimeout(_lastTimeout);
_lastTimeout = undefined;
_lastFiredResize = new Date().getTime();
for(var i = 0; i < _resizeFunctions.length; i++) _resizeFunctions[i]();
};
$axure.resize = function(fn) {
if(fn) _resizeFunctions[_resizeFunctions.length] = fn;
else $(window).resize();
};
$(window).resize(function() {
var THRESHOLD = 50;
_updateWindowInfo();
var now = new Date().getTime();
if(now - _lastFiredResize > THRESHOLD) {
_fireResize();
} else if(!_lastTimeout) {
_lastTimeout = window.setTimeout(_fireResize, THRESHOLD);
}
});
$(window).scroll(function () {
_updateWindowInfo();
});
var _windowInfo;
var _updateWindowInfo = $axure.updateWindowInfo = function () {
var win = {};
var jWin = $(window);
var scrollWin = $('#ios-safari-html').length > 0 ? $('#ios-safari-html') : jWin;
win.width = jWin.width();
win.height = jWin.height();
win.scrollx = scrollWin.scrollLeft();
win.scrolly = scrollWin.scrollTop();
_windowInfo = win;
};
$ax.getWindowInfo = function () {
if(!_windowInfo) _updateWindowInfo();
return _windowInfo;
};
window.$obj = function(id) {
return $ax.getObjectFromElementId(id);
};
window.$id = function(obj) {
return obj.scriptIds[0];
};
window.$jobj = function(id) {
return $(document.getElementById(id));
};
window.$jobjAll = function(id) {
return $addAll($jobj(id), id);
};
window.$addAll = function(jobj, id) {
return jobj.add($jobj(id + '_ann')).add($jobj(id + '_ref'));
};
$ax.INPUT = function(id) { return id + "_input"; };
$ax.IsImageFocusable = function (type) { return $ax.public.fn.IsImageBox(type) || $ax.public.fn.IsVector(type) || $ax.public.fn.IsTreeNodeObject(type) || $ax.public.fn.IsTableCell(type); };
$ax.IsTreeNodeObject = function (type) { return $ax.public.fn.IsTreeNodeObject(type); };
$ax.IsSelectionButton = function (type) { return $ax.public.fn.IsCheckBox(type) || $ax.public.fn.IsRadioButton(type); };
var _fn = {};
$axure.fn = _fn;
$axure.fn.jQuery = function() {
var elements = this.getElements();
return $(elements);
};
$axure.fn.$ = $axure.fn.jQuery;
var _query = function(query, queryArg) {
var returnVal = {};
var _axQueryObject = returnVal.query = { };
_axQueryObject.filterFunctions = [];
if (query == '*') {
_axQueryObject.filterFunctions[0] = function() { return true; };
} else if (typeof(query) === 'function') {
_axQueryObject.filterFunctions[0] = query;
} else {
var firstString = $.trim(query.toString());
if (firstString.charAt(0) == '@') {
_axQueryObject.filterFunctions[0] = function(diagramObject) {
return diagramObject.label == firstString.substring(1);
};
} else if (firstString.charAt(0) == '#') {
_axQueryObject.elementId = firstString.substring(1);
} else {
if (firstString == 'label') {
_axQueryObject.filterFunctions[0] = function(diagramObject) {
return queryArg instanceof Array && queryArg.indexOf(diagramObject.label) > 0 ||
queryArg instanceof RegExp && queryArg.test(diagramObject.label) ||
diagramObject.label == queryArg;
};
} else if(firstString == 'elementId') {
_axQueryObject.filterFunctions[0] = function(diagramObject, elementId) {
return queryArg instanceof Array && queryArg.indexOf(elementId) > 0 ||
elementId == queryArg;
};
}
}
}
var axureFn = $axure.fn;
for (var key in axureFn) {
returnVal[key] = axureFn[key];
}
return returnVal;
};
$axure.query = _query;
var _getFilterFnFromQuery = function(query) {
var filter = function(diagramObject, elementId) {
// Non diagram objects are allowed to be queryed, such as text inputs.
if (diagramObject && !$ax.public.fn.IsReferenceDiagramObject(diagramObject.type) && !document.getElementById(elementId)) return false;
var retVal = true;
for(var i = 0; i < query.filterFunctions.length && retVal; i++) {
retVal = query.filterFunctions[i](diagramObject, elementId);
}
return retVal;
};
return filter;
};
$ax.public.fn.filter = function(query, queryArg) {
var returnVal = _query(query, queryArg);
if(this.query.elementId) returnVal.query.elementId = this.query.elementId;
//If there is already a function, offset by 1 when copying other functions over.
var offset = returnVal.query.filterFunctions[0] ? 1 : 0;
//Copy all functions over to new array.
for(var i = 0; i < this.query.filterFunctions.length; i++) returnVal.query.filterFunctions[i+offset] = this.query.filterFunctions[i];
//Functions are in reverse order now
returnVal.query.filterFunctions.reverse();
return returnVal;
};
$ax.public.fn.each = function(fn) {
var filter = _getFilterFnFromQuery(this.query);
var elementIds = this.query.elementId ? [this.query.elementId] : $ax.getAllElementIds();
for (var i = 0; i < elementIds.length; i++) {
var elementId = elementIds[i];
var diagramObject = $ax.getObjectFromElementId(elementId);
if (filter(diagramObject, elementId)) {
fn.apply(diagramObject, [diagramObject, elementId]);
}
}
};
$ax.public.fn.getElements = function() {
var elements = [];
this.each(function(dObj, elementId) {
var elementById = document.getElementById(elementId);
if(elementById) elements[elements.length] = elementById;
});
return elements;
};
$ax.public.fn.getElementIds = function() {
var elementIds = [];
this.each(function(dObj, elementId) { elementIds[elementIds.length] = elementId; });
return elementIds;
};
// Deep means to keep getting parents parent until at the root parent. Parent is then an array instead of an id.
// Filter options: layer, rdo, repeater, item, dynamicPanel, state
$ax.public.fn.getParents = function (deep, filter) {
if(filter == '*') filter = ['layer', 'rdo', 'repeater', 'item', 'dynamicPanel', 'state'];
var elementIds = this.getElementIds();
var parentIds = [];
var getParent = function(elementId) {
var containerIndex = elementId.indexOf('_container');
if(containerIndex !== -1) elementId = elementId.substring(0, containerIndex);
if(elementId.indexOf('_text') !== -1) elementId = $ax.GetShapeIdFromText(elementId);
// Check repeater item before layer, because repeater item detects it's parent layer, but wants to go directly to it's repeater first.
// if repeater item, then just return repeater
var scriptId = $ax.repeater.getScriptIdFromElementId(elementId);
var itemNum = $ax.repeater.getItemIdFromElementId(elementId);
var parentRepeater = $ax.getParentRepeaterFromScriptId(scriptId);
// scriptId is item or repeater itself
if (parentRepeater == scriptId) {
// If you are repeater item, return your repeater
if (itemNum) return filter.indexOf('repeater') != -1 ? scriptId : getParent(scriptId);
// Otherwise you are actually at repeater, clean parentRepeater, or else you loop
parentRepeater = undefined;
}
// Layer only references it if it is a direct layer to it
var parent = $ax.getLayerParentFromElementId(elementId);
// If layer is allowed we found parent, otherwise ignore and keep climbing
if (parent) return filter.indexOf('layer') != -1 ? parent : getParent(parent);
// if state, then just return panel
if(scriptId.indexOf('_state') != -1) {
var panelId = $ax.repeater.createElementId(scriptId.split('_')[0], itemNum);
// If dynamic panel is allowed we found parent, otherwise ignore and keep climbing
return filter.indexOf('dynamicPanel') != -1 ? panelId : getParent(panelId);
}
var parentType = '';
if(parentRepeater) {
parentType = 'item';
parent = $ax.repeater.createElementId(parentRepeater, itemNum);
}
var masterPath = $ax.getPathFromScriptId($ax.repeater.getScriptIdFromElementId(elementId));
masterPath.pop();
if(masterPath.length > 0) {
var masterId = $ax.getElementIdFromPath(masterPath, { itemNum: itemNum }, true);
if(!masterId) return undefined;
var masterRepeater = $ax.getParentRepeaterFromElementId($ax.repeater.getScriptIdFromElementId(masterId));
if(!parentRepeater || masterRepeater) {
parentType = 'rdo';
parent = masterId;
}
}
var obj = $obj(elementId);
var parentDynamicPanel = obj.parentDynamicPanel;
if(parentDynamicPanel) {
// Make sure the parent if not parentRepeater, or dynamic panel is also in that repeater
// If there is a parent master, the dynamic panel must be in it, otherwise parentDynamicPanel would be undefined.
var panelPath = masterPath;
panelPath[panelPath.length] = parentDynamicPanel;
panelId = $ax.getElementIdFromPath(panelPath, { itemNum: itemNum }, true);
if(!panelId) return undefined;
var panelRepeater = $ax.getParentRepeaterFromElementId(panelId);
if(!parentRepeater || panelRepeater) {
parentType = 'state';
parent = panelId + '_state' + obj.panelIndex;
}
}
// If at top or parent type is desired, then return parent, otherwise keep climbing
return !parent || filter.indexOf(parentType) != -1 ? parent : getParent(parent);
};
for (var i = 0; i < elementIds.length; i++) {
var elementId = elementIds[i];
if ((elementId || elementId === 0) && elementId !== "undefined") {
var parent = getParent(elementId);
if (deep) {
var parents = [];
while (parent) {
parents[parents.length] = parent;
// If id is not a valid object, you are either repeater item or dynamic panel state
//if(!$obj(parent)) parent = $ax.visibility.getWidgetFromContainer($jobj(parent).parent().attr('id'));
parent = getParent(parent);
}
parent = parents;
}
parentIds[parentIds.length] = parent;
}
}
return parentIds;
};
// Get the path to the child, where non leaf nodes can be masters, layers, dynamic panels, and repeaters.
$ax.public.fn.getChildren = function(deep, ignoreUnplaced) { // ignoreUnplaced should probably be the default, but when that is done a full audit of usages should be done
var elementIds = this.getElementIds();
var children = [];
var getChildren = function (elementId) {
var obj = $obj(elementId);
//if(!obj) return undefined;
var isRepeater = obj && obj.type == $ax.constants.REPEATER_TYPE;
if (isRepeater && $ax.repeater.getScriptIdFromElementId(elementId) != elementId) {
//prevent repeater items from being marked as isRepeater
//TODO: evaluate changing the naming convention to be more like panel states which don't seem to have this problem
obj = undefined;
isRepeater = false;
}
var isDynamicPanel = obj && obj.type == $ax.constants.DYNAMIC_PANEL_TYPE;
//var isLayer = obj.type == $ax.constants.LAYER_TYPE;
//var isMaster = obj.type == $ax.constants.MASTER_TYPE || obj.type == $ax.constants.REFERENCE_DIAGRAM_OBJECT_TYPE;
var isMenu = obj && obj.type == $ax.constants.MENU_OBJECT_TYPE;
var isTreeNode = obj && obj.type == $ax.constants.TREE_NODE_OBJECT_TYPE;
//var isTable = obj.type == $ax.constants.TABLE_TYPE;
//var isCompoundVector = obj.type == $ax.constants.VECTOR_SHAPE_TYPE && obj.generateCompound;
//if (isRepeater || isDynamicPanel || isLayer || isMaster || isMenu || isTreeNode || isTable) {// || isCompoundVector) {
// Find parent that children should be pulled from. Default is just the elementId query (used by table and master)
var parent = $jobj(elementId);
if(isRepeater) {
parent = $();
var itemIds = $ax.getItemIdsForRepeater(elementId);
for(var itemIndex = 0; itemIndex < itemIds.length; itemIndex++) parent = parent.add($jobj($ax.repeater.createElementId(elementId, itemIds[itemIndex])));
} else if(isDynamicPanel) {
// Really only need to do active state probably...
parent = $jobj(elementId).children();
// Get through all containers
while ($(parent[0]).attr('id').indexOf('container') != -1) parent = parent.children();
// Now at states, but want states content
parent = parent.children();
} else if(isTreeNode) parent = $jobj($ax.repeater.applySuffixToElementId(elementId, '_children'));
// Menu doesn't want all children, only tables and menus, so it must be handled specially
var children = isMenu ? parent.children('.ax_table').add(parent.children('.ax_menu')) : parent.children();
children = $ax.visibility.getRealChildren(_fixForBasicLinks(children));
// For tree nodes you want the the button shape contained by the elementQuery too
if(isTreeNode) {
var treeNodeChildren = $jobj(elementId).children();
for(var treeNodeIndex = 0; treeNodeIndex < treeNodeChildren.length; treeNodeIndex++) {
var treeNodeChild = $(treeNodeChildren[treeNodeIndex]);
var childObj = $obj(treeNodeChild.attr('id'));
if (childObj && $ax.public.fn.IsVector(childObj.type)) children = children.add(treeNodeChild);
}
}
var childrenIds = [];
for(var childIndex = 0; childIndex < children.length; childIndex++) {
var childObj = $(children[childIndex]);
var id = childObj.attr('id');
if(typeof(id) == 'undefined' && childObj.is('a')) id = $(childObj.children()[0]).attr('id');
// Ignore annotations and any other children that are not elements
if (id.split('_').length > 1) continue;
// Ignore Unplaced
if(ignoreUnplaced && $ax.visibility.isScriptIdLimbo($ax.repeater.getScriptIdFromElementId(id))) continue;
childrenIds.push(id);
}
if(deep) {
var childObjs = [];
for(var i = 0; i < childrenIds.length; i++) {
var childId = childrenIds[i];
childObjs[i] = { id: childId, children: getChildren(childId) };
}
childrenIds = childObjs;
}
return childrenIds;
//}
//return undefined;
};
for(var i = 0; i < elementIds.length; i++) {
var elementId = elementIds[i];
//if the state is passed in, look for children in the content element
if (elementId.indexOf('_state') > -1 && elementId.indexOf('_content') < 0) elementId = elementId + '_content';
children[children.length] = { id: elementId, children: getChildren(elementId)};
}
return children;
};
var _fixForBasicLinks = function(query) {
var hasBasicLinks = query.filter('.basiclink').length > 0;
if(!hasBasicLinks) return query;
var retval = $();
for(var i = 0; i < query.length; i++) {
var child = $(query[i]);
if(child.hasClass('basiclink')) retval = retval.add(child.children());
else retval = retval.add(child);
}
return retval;
};
})();

1864
web/main/static/resources/scripts/axure/axQuery.std.js

File diff suppressed because it is too large

900
web/main/static/resources/scripts/axure/doc.js

@ -1,900 +0,0 @@
$axure.internal(function($ax) {
var _pageData;
var _initializePageFragment = function(pageFragment, objIdToObject) {
var objectArrayHelper = function(objects, parent) {
for(var i = 0; i < objects.length; i++) {
diagramObjectHelper(objects[i], parent);
}
};
var diagramObjectHelper = function(diagramObject, parent) {
$ax.initializeObject('diagramObject', diagramObject);
objIdToObject[pageFragment.packageId + '~' + diagramObject.id] = diagramObject;
diagramObject.parent = parent;
diagramObject.owner = pageFragment;
diagramObject.scriptIds = [];
if(diagramObject.diagrams) { //dynamic panel
for(var i = 0; i < diagramObject.diagrams.length; i++) {
var diagram = diagramObject.diagrams[i];
objectArrayHelper(diagram.objects, diagram);
}
} else if($ax.public.fn.IsLayer(diagramObject.type)) {
var layerObjs = diagramObject.objs;
objectArrayHelper(layerObjs, parent);
}
if(diagramObject.objects) objectArrayHelper(diagramObject.objects, diagramObject);
};
objectArrayHelper(pageFragment.diagram.objects, pageFragment.diagram);
};
var _initalizeStylesheet = function(stylesheet) {
var stylesById = {};
var customStyles = stylesheet.customStyles;
for(var key in customStyles) {
var style = customStyles[key];
stylesById[style.id] = style;
}
var duplicateStyles = stylesheet.duplicateStyles;
for(var duplicateKey in duplicateStyles) {
stylesById[duplicateKey] = stylesById[duplicateStyles[duplicateKey]];
}
stylesheet.stylesById = stylesById;
};
var _initializeDocumentData = function() {
_initalizeStylesheet($ax.document.stylesheet);
};
var _initializePageData;
// ******* Dictionaries ******** //
(function() {
var scriptIdToParentLayer = {};
var elementIdToObject = {};
var scriptIdToObject = {};
var scriptIdToRepeaterId = {};
var repeaterIdToScriptIds = {};
var repeaterIdToItemIds = {};
var scriptIdToPath = {};
var _scriptIds = [];
var elementIdToText = {};
var radioGroupToSelectedElementId = {};
_initializePageData = function() {
if(!_pageData || !_pageData.page || !_pageData.page.diagram) return;
var objIdToObject = {};
_initializePageFragment(_pageData.page, objIdToObject);
for(var masterId in _pageData.masters) {
var master = _pageData.masters[masterId];
_initializePageFragment(master, objIdToObject);
}
var _pathsToScriptIds = [];
_pathToScriptIdHelper(_pageData.objectPaths, [], _pathsToScriptIds, scriptIdToPath);
for(var i = 0; i < _pathsToScriptIds.length; i++) {
var path = _pathsToScriptIds[i].idPath;
var scriptId = _pathsToScriptIds[i].scriptId;
var packageId = _pageData.page.packageId;
if(path.length > 1) {
for(var j = 0; j < path.length - 1; j++) {
var rdoId = path[j];
var rdo = objIdToObject[packageId + '~' + rdoId];
packageId = rdo.masterId;
}
}
var diagramObject = objIdToObject[packageId + '~' + path[path.length - 1]];
diagramObject.scriptIds[diagramObject.scriptIds.length] = scriptId;
scriptIdToObject[scriptId] = diagramObject;
_scriptIds[_scriptIds.length] = scriptId;
}
// Now map scriptIds to repeaters and layers
var mapScriptIdToRepeaterId = function(scriptId, repeaterId) {
scriptIdToRepeaterId[scriptId] = repeaterId;
var scriptIds = repeaterIdToScriptIds[repeaterId];
if(scriptIds) scriptIds[scriptIds.length] = scriptId;
else repeaterIdToScriptIds[repeaterId] = [scriptId];
};
var mapScriptIdToLayerId = function(obj, layerId, path) {
var pathCopy = $ax.deepCopy(path);
pathCopy[path.length] = obj.id;
var scriptId = $ax.getScriptIdFromPath(pathCopy);
scriptIdToParentLayer[scriptId] = layerId;
}
var mapIdsToRepeaterAndLayer = function(path, objs, repeaterId) {
var pathCopy = $ax.deepCopy(path);
for(var i = 0; i < objs.length; i++) {
var obj = objs[i];
pathCopy[path.length] = obj.id;
var scriptId = $ax.getScriptIdFromPath(pathCopy);
// Rdo have no element on page and are not mapped to the repeater
if(repeaterId) mapScriptIdToRepeaterId(scriptId, repeaterId);
if($ax.public.fn.IsDynamicPanel(obj.type)) {
for(var j = 0; j < obj.diagrams.length; j++) mapIdsToRepeaterAndLayer(path, obj.diagrams[j].objects, repeaterId);
} else if($ax.public.fn.IsReferenceDiagramObject(obj.type)) {
mapIdsToRepeaterAndLayer(pathCopy, $ax.pageData.masters[obj.masterId].diagram.objects, repeaterId);
} else if($ax.public.fn.IsRepeater(obj.type)) {
mapScriptIdToRepeaterId(scriptId, scriptId);
mapIdsToRepeaterAndLayer(path, obj.objects, scriptId);
} else if($ax.public.fn.IsLayer(obj.type)) {
var layerObjs = obj.objs;
for(var j = 0; j < layerObjs.length; j++) {
mapScriptIdToLayerId(layerObjs[j], scriptId, path);
}
mapIdsToRepeaterAndLayer(path, layerObjs, repeaterId);
} else if(obj.objects && obj.objects.length) {
if(repeaterId) {
for(var j = 0; j < obj.objects.length; j++) {
mapIdsToRepeaterAndLayer(path, obj.objects, repeaterId);
}
}
}
}
};
mapIdsToRepeaterAndLayer([], $ax.pageData.page.diagram.objects);
};
$ax.getPathFromScriptId = function(scriptId) {
var reversedPath = [];
var path = scriptIdToPath[scriptId];
while(path && path.uniqueId) {
reversedPath[reversedPath.length] = path.uniqueId;
path = path.parent;
}
return reversedPath.reverse();
};
var _getScriptIdFromFullPath = function(path) {
var current = $ax.pageData.objectPaths;
for(var i = 0; i < path.length; i++) {
current = current[path[i]];
if(!current) return current;
}
return current && current.scriptId;
};
var _getScriptIdFromPath = function(path, relativeTo, includeLimbo) {
var relativePath = [];
var includeMasterInPath = false;
if(relativeTo) {
var relativeToScriptId;
if(relativeTo.srcElement) { //this is eventInfo
relativeToScriptId = $ax.repeater.getScriptIdFromElementId(relativeTo.srcElement);
includeMasterInPath = relativeTo.isMasterEvent;
} else if(typeof relativeTo === 'string') { //this is an element id
relativeToScriptId = relativeTo;
}
if(relativeToScriptId) {
relativePath = $ax.getPathFromScriptId(relativeToScriptId);
if(!includeMasterInPath) relativePath = relativePath.slice(0, relativePath.length - 1);
} else if(relativeTo instanceof Array) { //this is a path
relativePath = relativeTo;
}
}
var fullPath = relativePath.concat(path);
var scriptId = _getScriptIdFromFullPath(fullPath);
return (includeLimbo || !$ax.visibility.isScriptIdLimbo(scriptId)) && scriptId;
};
$ax.getScriptIdFromPath = _getScriptIdFromPath;
var _getElementIdsFromPath = function(path, eventInfo) {
var scriptId = _getScriptIdFromPath(path, eventInfo);
if(!scriptId) return [];
// Don't need placed check hear. If unplaced, scriptId will be undefined and exit out before here.
return $ax.getElementIdsFromEventAndScriptId(eventInfo, scriptId);
};
$ax.getElementIdsFromPath = _getElementIdsFromPath;
var _getElementIdFromPath = function(path, params, includeLimbo) {
var scriptId = _getScriptIdFromPath(path, params.relativeTo, includeLimbo);
if(!scriptId) return scriptId;
var itemNum = params.itemNum;
if(params.relativeTo && typeof params.relativeTo === 'string') {
if($jobj(params.relativeTo)) itemNum = $ax.repeater.getItemIdFromElementId(params.relativeTo);
}
return $ax.repeater.createElementId(scriptId, itemNum);
};
$ax.getElementIdFromPath = _getElementIdFromPath;
var _getElementsIdFromEventAndScriptId = function(eventInfo, scriptId) {
var itemId = eventInfo && $ax.repeater.getItemIdFromElementId(eventInfo.srcElement);
var target = false;
// Try to get itemId from target if you can't get it from source.
if(!itemId) {
itemId = eventInfo && eventInfo.targetElement && $ax.repeater.getItemIdFromElementId(eventInfo.targetElement);
if(itemId) target = true;
}
var parentRepeater = $ax.getParentRepeaterFromScriptId(scriptId);
if(parentRepeater && scriptId != parentRepeater) {
if(itemId && (!eventInfo || parentRepeater == $ax.getParentRepeaterFromScriptId($ax.repeater.getScriptIdFromElementId(target ? eventInfo.targetElement : eventInfo.srcElement)))) {
return [$ax.repeater.createElementId(scriptId, itemId)];
}
var elementIds = [];
var itemIds = $ax.getItemIdsForRepeater(parentRepeater);
if(!itemIds) return [];
for(var i = 0; i < itemIds.length; i++) elementIds[i] = $ax.repeater.createElementId(scriptId, itemIds[i]);
return elementIds;
}
return [scriptId];
};
$ax.getElementIdsFromEventAndScriptId = _getElementsIdFromEventAndScriptId;
var _getSrcElementIdFromEvent = function(event) {
var currentQuery = $(event.srcElement || event.target);
while(currentQuery && currentQuery.length && (!$obj(currentQuery.attr('id')) || $jobj(currentQuery.attr('id')).hasClass('text'))) {
currentQuery = currentQuery.parent();
};
return currentQuery.attr('id');
};
$ax.getSrcElementIdFromEvent = _getSrcElementIdFromEvent;
var _getEventInfoFromEvent = function(event, skipShowDescriptions, elementId) {
var eventInfo = {};
eventInfo.srcElement = elementId;
eventInfo.now = new Date();
if(event != null) {
//elementId can be empty string, so can't simple use "or" assignment here.
eventInfo.srcElement = elementId || elementId == '' ? elementId : _getSrcElementIdFromEvent(event);
eventInfo.which = event.which;
// When getting locations in mobile, need to extract the touch object to get the mouse location attributes
var mouseEvent = (event.originalEvent && event.originalEvent.changedTouches && event.originalEvent.changedTouches[0]) || event.originalEvent;
if(mouseEvent && !mouseEvent.type) mouseEvent.type = event.type;
if(skipShowDescriptions) eventInfo.skipShowDescriptions = true;
// Always update mouse location if possible
$ax.event.updateMouseLocation(mouseEvent);
}
// Always set event info about cursor
var _cursor = eventInfo.cursor = {};
_cursor.x = $ax.mouseLocation.x;
_cursor.y = $ax.mouseLocation.y;
var body = $('body');
if(body.css('position') == 'relative') {
_cursor.x -= ($ax.getNumFromPx(body.css('left')) + Math.max(0, ($(window).width() - body.width()) / 2));
}
eventInfo.pageX = _cursor.x + 'px';
eventInfo.pageY = _cursor.y + 'px';
// Do Keyboard Info
eventInfo.keyInfo = $ax.event.keyState();
eventInfo.window = $ax.getWindowInfo();
eventInfo.thiswidget = _getWidgetInfo(eventInfo.srcElement);
eventInfo.item = _getItemInfo(eventInfo.srcElement);
eventInfo.dragInfo = $ax.drag.GetWidgetDragInfo();
return eventInfo;
};
$ax.getEventInfoFromEvent = _getEventInfoFromEvent;
$ax.getBasicEventInfo = function() {
var eventInfo = {};
eventInfo.now = new Date();
eventInfo.window = $ax.getWindowInfo();
eventInfo.cursor = { x: 0, y: 0};
return eventInfo;
};
//var _getWindowInfo = function() {
// var win = {};
// win.width = $(window).width();
// win.height = $(window).height();
// win.scrollx = $(window).scrollLeft();
// win.scrolly = $(window).scrollTop();
// return win;
//};
//$ax.getWindowInfo = _getWindowInfo;
var repeaterInfoCache = [];
$ax.cacheRepeaterInfo = function(repeaterId, repeaterInfo) {
repeaterInfoCache[repeaterId] = repeaterInfo;
}
$ax.removeCachedRepeaterInfo = function(repeaterId) {
repeaterInfoCache[repeaterId] = undefined;
}
var _getItemInfo = function(elementId) {
if(!elementId) return { valid: false };
elementId = _getParentElement(elementId);
var index = $ax.repeater.getItemIdFromElementId(elementId);
if(!index) return { valid: false };
var item = { valid: true };
var scriptId = $ax.repeater.getScriptIdFromElementId(elementId);
var repeaterId = $ax.getParentRepeaterFromScriptId(scriptId);
item.repeater = repeaterInfoCache[repeaterId] ? repeaterInfoCache[repeaterId] : _getWidgetInfo(repeaterId);
$ax.repeater.setDisplayProps(item, repeaterId, index);
item.ismarked = $ax.repeater.isEditItem(repeaterId, index);
item.isvisible = Boolean($jobj(elementId).length);
return item;
};
$ax.getItemInfo = _getItemInfo;
var _getWidgetInfo = function(elementId) {
if(!elementId) return { valid: false };
elementId = _getParentElement(elementId);
//var elementAxQuery = $ax('#' + elementId);
var elementQuery = $jobj(elementId);
var obj = $obj(elementId);
var widget = { valid: true, isWidget: true, obj: obj, elementQuery: elementQuery, isLayer: $ax.public.fn.IsLayer(obj.type) };
widget.elementId = elementId;
widget.name = widget.label = (elementQuery.data('label') ? elementQuery.data('label') : '');
//widget.text = $ax('#' + elementId).text();
widget.opacity = Number(elementQuery.css('opacity')) * 100;
//widget.rotation = $ax.move.getRotationDegree(widget.elementId);
var scriptId = $ax.repeater.getScriptIdFromElementId(elementId);
var repeaterId = $ax.getParentRepeaterFromScriptId(scriptId);
if(repeaterId) widget.repeater = $ax.public.fn.IsRepeater(obj.type) ? widget : _getWidgetInfo(repeaterId);
// Right now only dynamic panel can scroll
if($ax.public.fn.IsDynamicPanel(obj.type)) {
var stateId = $ax.visibility.GetPanelState(elementId);
//can be empty when refreshing repeater and applying filter
if(stateId) {
var stateQuery = $('#' + stateId);
widget.scrollx = stateQuery.scrollLeft();
widget.scrolly = stateQuery.scrollTop();
//widget.stateQuery = stateQuery;
}
} else {
widget.scrollx = 0;
widget.scrolly = 0;
}
// repeater only props
if($ax.public.fn.IsRepeater(obj.type)) {
widget.visibleitemcount = repeaterIdToItemIds[scriptId] ? repeaterIdToItemIds[scriptId].length : $ax.repeater.getVisibleDataCount(scriptId);
widget.itemcount = $ax.repeater.getFilteredDataCount(scriptId);
widget.datacount = $ax.repeater.getDataCount(scriptId);
widget.pagecount = $ax.repeater.getPageCount(scriptId);
widget.pageindex = $ax.repeater.getPageIndex(scriptId);
}
// Get widget info funcs
//widget.elementAxQuery = function () {
// return this.elementAxQueryProp || (this.elementAxQueryProp = $ax('#' + this.elementId));
//}
//widget.isFitToContent = function () {
// if (this.isFitToContentProp === undefined) {
// if (!this.stateQuery) this.isFitToContentProp = false;
// else this.isFitToContentProp = $ax.dynamicPanelManager.isIdFitToContent(this.elementId);
// }
// return this.isFitToContentProp;
//}
widget.x = function () { return this.getProp('x'); }
widget.y = function () { return this.getProp('y'); }
widget.pagex = function () { return this.getProp('pagex'); }
widget.pagey = function () { return this.getProp('pagey'); }
widget.width = function () { return this.getProp('width'); }
widget.height = function () { return this.getProp('height'); }
widget.left = function () { return this.x(); }
widget.top = function () { return this.y(); }
widget.right = function () { return this.x() + this.width(); }
widget.bottom = function () { return this.y() + this.height(); }
widget.rotation = function () { return this.getProp('rotation'); }
widget.text = function () { return this.getProp('text'); }
widget.getProp = function (prop) {
var propName = prop + 'Prop';
if (typeof (this[propName]) != 'undefined') return this[propName];
return this[propName] = this.cacheProp(prop);
};
widget.cacheProp = function (prop) {
if(prop == 'x' || prop == 'y' || prop == 'width' || prop == 'height') {
var boundingRect = $ax('#' + this.elementId).offsetBoundingRect(true);
this.xProp = boundingRect.left;
this.yProp = boundingRect.top;
this.widthProp = boundingRect.width;
this.heightProp = boundingRect.height;
}
if(prop == 'pagex' || prop == 'pagey') {
var viewportLocation = $ax('#' + this.elementId).viewportLocation();
this.pagexProp = viewportLocation.left;
this.pageyProp = viewportLocation.top;
}
if(prop == 'rotation') {
this.rotationProp = $ax.move.getRotationDegree(this.elementId);
}
if (prop == 'text') {
this.textProp = $ax('#' + this.elementId).text();
}
return this[prop + 'Prop'];
//// I'm keeping the returned undefineds the same as before, but really I could probably return undefined right away if elementQuery is empty
//if (this.isLayer) {
// if (prop == 'pagex' || prop == 'pagey') {
// if (this.elementQuery.length > 0) {
// if (prop == 'pagex') return this.elementAxQuery().left();
// else return this.elementAxQuery().top();
// }
// return undefined; // Otherwise, it is undefined as there is no element
// }
// var boundingRect = $ax.public.fn.getWidgetBoundingRect(this.elementId);
// this.xProp = boundingRect.left;
// this.yProp = boundingRect.top;
// this.widthProp = boundingRect.width;
// this.heightProp = boundingRect.height;
// return this[prop + 'Prop'];
//}
//if (this.elementQuery.length <= 0) return prop == 'x' || prop == 'y' ? 0 : undefined;
//switch (prop) {
// case 'x': return this.elementAxQuery().locRelativeIgnoreLayer(false);
// case 'y': return this.elementAxQuery().locRelativeIgnoreLayer(true);
// case 'pagex': return this.elementAxQuery().left();
// case 'pagey': return this.elementAxQuery().top();
//}
//var val = this.elementAxQuery()[prop]();
//if (this.isFitToContent()) val = this.stateQuery[prop]();
//return val;
};
//widget.leftfixed = function() { this.getFixed('left'); }
//widget.topfixed = function() { this.getFixed('top'); }
//widget.rightfixed = function() { this.getFixed('right'); }
//widget.bottomfixed = function() { this.getFixed('bottom'); }
//widget.isFixed = function() {
// if(this.isFixedProp === undefined) this.isFixedProp = this.elementQuery.css('position') == 'fixed)';
// return this.isFixedProp;
//}
//widget.getFixed = function (prop) {
// var fixed = prop + 'fixedProp';
// if(!this.isFixed()) widget[fixed] = widget[prop]();
// if(widget[fixed] === undefined) {
// if(prop == 'left' || prop == 'right') {
// if(this.windowScrollX === undefined) this.windowScrollX = $(window).scrollLeft();
// var windowScroll = this.windowScrollX;
// } else {
// if(this.windowScrollY === undefined) this.windowScrollY = $(window).scrollTop();
// windowScroll = this.windowScrollY;
// }
// widget[fixed] = widget[prop]() - windowScroll;
// }
// return widget[fixed];
//}
return widget;
};
$ax.getWidgetInfo = _getWidgetInfo;
$ax.GetTextPanelId = function (id, create) {
if(!$ax('#' + id).SupportsRichText()) return '';
var buttonShape = $ax.GetButtonShape(id);
var panelDiv = buttonShape.find('.text')[0];
if(!panelDiv) {
if(!create) return "";
var adaptiveId = $ax.adaptive.currentViewId;
var newId = id + "_text";
//var newDiv = $('<div id="' + newId + '" class="text" style="visibility: inherit; position: absolute"></div>');
var newDiv = $('<div id="' + newId + '" class="text' + (adaptiveId ? (' ' + adaptiveId) : '') + '" style="visibility: inherit; position: absolute"><p><span></span></p></div>');
buttonShape.append(newDiv);
$ax.style.setAdaptiveStyle(id, $ax.style.computeAllOverrides(id, undefined, $ax.style.generateState(id), adaptiveId));
panelDiv = newDiv[0];
}
return panelDiv.id;
}
$ax.GetParentIdFromLink = function(id) {
return $ax.GetShapeIdFromText($jobj(id).parentsUntil('.text').parent().attr('id'));
};
$ax.GetButtonShapeId = function(id) {
var obj = $obj(id);
switch(obj.type) {
case $ax.constants.TREE_NODE_OBJECT_TYPE:
return obj.buttonShapeId ? $ax.getElementIdFromPath([obj.buttonShapeId], { relativeTo: id }) : "";
case $ax.constants.LINK_TYPE:
return "";
default:
return id;
}
};
$ax.GetButtonShape = function(id) {
return $jobj($ax.GetButtonShapeId(id));
};
$ax.GetShapeIdFromText = function(id) {
if(!id) return undefined; // this is to prevent an infinite loop.
var current = document.getElementById(id);
if(!current) return undefined;
current = current.parentElement;
while(current && current.tagName != 'BODY') {
var currentId = current.id;
if(currentId && currentId != 'base') return $ax.visibility.getWidgetFromContainer(currentId);
current = current.parentElement;
}
return undefined;
};
$ax.GetImageIdFromShape = function(id) {
var image = $ax.GetButtonShape(id).find('img[id$=img]');
if(!image.length) image = $jobj(id).find('img[id$=image_sketch]');
return image.attr('id');
};
var _getParentElement = $ax.getParentElement = function(elementId) {
var obj = $obj(elementId);
while(obj.isContained) {
var path = $ax.getPathFromScriptId($ax.repeater.getScriptIdFromElementId(elementId));
var itemId = $ax.repeater.getItemIdFromElementId(elementId);
path[path.length - 1] = obj.parent.id;
elementId = $ax.getElementIdFromPath(path, { itemNum: itemId });
obj = $obj(elementId);
}
return elementId;
};
$ax.addItemIdToRepeater = function(itemId, repeaterId) {
var itemIds = repeaterIdToItemIds[repeaterId];
if(itemIds) itemIds[itemIds.length] = itemId;
else repeaterIdToItemIds[repeaterId] = [itemId];
var scriptIds = repeaterIdToScriptIds[repeaterId];
for(var i = 0; i < scriptIds.length; i++) elementIdToObject[$ax.repeater.createElementId(scriptIds[i], itemId)] = $ax.getObjectFromScriptId(scriptIds[i]);
};
$ax.getAllElementIds = function() {
var elementIds = [];
for(var i = 0; i < _scriptIds.length; i++) {
var scriptId = _scriptIds[i];
var repeaterId = scriptIdToRepeaterId[scriptId];
if(repeaterId && repeaterId != scriptId) {
var itemIds = repeaterIdToItemIds[repeaterId] || [];
for(var j = 0; j < itemIds.length; j++) elementIds[elementIds.length] = $ax.repeater.createElementId(scriptId, itemIds[j]);
} else elementIds[elementIds.length] = scriptId;
}
return elementIds;
};
$ax.getAllScriptIds = function() {
return _scriptIds;
};
$ax.getObjectFromElementId = function(elementId) {
return $ax.getObjectFromScriptId($ax.repeater.getScriptIdFromElementId(elementId));
};
$ax.getObjectFromScriptId = function(scriptId) {
return scriptIdToObject[scriptId];
};
$ax.getParentRepeaterFromElementId = function(elementId) {
return $ax.getParentRepeaterFromScriptId($ax.repeater.getScriptIdFromElementId(elementId));
};
$ax.getParentRepeaterFromElementIdExcludeSelf = function (elementId) {
var repeaterId = $ax.getParentRepeaterFromElementId(elementId);
return repeaterId != elementId ? repeaterId : undefined;
};
$ax.getParentRepeaterFromScriptId = function(scriptId) {
return scriptIdToRepeaterId[scriptId];
};
var _getChildScriptIdsForRepeater = function(repeaterId) {
return repeaterIdToScriptIds[repeaterId];
};
var _getItemIdsForRepeater = function(repeaterId) {
return repeaterIdToItemIds[repeaterId] || [];
};
$ax.getItemIdsForRepeater = _getItemIdsForRepeater;
var _clearItemIdsForRepeater = function(repeaterId) {
repeaterIdToItemIds[repeaterId] = [];
};
$ax.clearItemsForRepeater = _clearItemIdsForRepeater;
$ax.getChildElementIdsForRepeater = function(repeaterId) {
var scriptIds = _getChildScriptIdsForRepeater(repeaterId);
var itemIds = _getItemIdsForRepeater(repeaterId);
var retVal = [];
if(!itemIds || !scriptIds) return retVal;
for(var i = 0; i < scriptIds.length; i++) {
for(var j = 0; j < itemIds.length; j++) {
retVal[retVal.length] = $ax.repeater.createElementId(scriptIds[i], itemIds[j]);
}
}
return retVal;
};
$ax.getRdoParentFromElementId = function(elementId) {
var scriptId = $ax.repeater.getScriptIdFromElementId(elementId);
var rdoId = scriptIdToPath[scriptId].parent.scriptId;
if($ax.getParentRepeaterFromScriptId(rdoId)) rdoId = $ax.repeater.createElementId(rdoId, $ax.repeater.getItemIdFromElementId(elementId));
return rdoId;
};
$ax.getLayerParentFromElementId = function (elementId) {
var itemId = $ax.repeater.getItemIdFromElementId(elementId);
var scriptId = scriptIdToParentLayer[$ax.repeater.getScriptIdFromElementId(elementId)];
return $ax.getParentRepeaterFromElementId(scriptId) ? $ax.repeater.createElementId(scriptId, itemId) : scriptId;
}
$ax.updateElementText = function(elementId, text) {
elementIdToText[elementId] = text;
};
$ax.hasElementTextChanged = function(elementId, text) {
return elementIdToText[elementId] != text;
};
$ax.updateRadioButtonSelected = function(group, elementId) {
var old = radioGroupToSelectedElementId[group];
radioGroupToSelectedElementId[group] = elementId;
return old;
};
$ax.hasRadioButtonSelectedChanged = function(group, elementId) {
return radioGroupToSelectedElementId[group] != elementId;
};
})();
//Recursively populates fullPathArray with:
// [ { idPath, scriptId }, ... ]
//for every scriptId in the object
//also populates an object of scriptId -> path
var _pathToScriptIdHelper = function(currentPath, currentChain, fullPathArray, scriptIdToPath) {
for(var key in currentPath) {
if(key != "scriptId") {
var nextPath = currentPath[key];
_pathToScriptIdHelper(nextPath, currentChain.concat(key), fullPathArray, scriptIdToPath);
nextPath.parent = currentPath;
nextPath.uniqueId = key;
} else {
fullPathArray[fullPathArray.length] = { idPath: currentChain, scriptId: currentPath.scriptId };
scriptIdToPath[currentPath.scriptId] = currentPath;
}
}
};
$ax.public.loadCurrentPage = $ax.loadCurrentPage = function(pageData) {
$ax.pageData = _pageData = pageData;
_initializePageData();
};
$ax.public.loadDocument = $ax.loadDocument = function(document) {
$ax.document = document;
_initializeDocumentData();
};
/**
Navigates to a page
*/
$ax.public.navigate = $ax.navigate = function(to) { //url, includeVariables, type) {
var targetUrl;
if(typeof (to) === 'object') {
targetUrl = !to.includeVariables ? to.url : $ax.globalVariableProvider.getLinkUrl(to.url, to.useGlobalVarNameInUrl);
if(to.target == "new") {
window.open(targetUrl, "");
} else if(to.target == "popup") {
var features = _getPopupFeatures(to.popupOptions);
window.open(targetUrl, "", features);
} else {
var targetLocation = window.location;
if(to.target == "current") {
} else if(to.target == "parent") {
if(!top.opener) return;
targetLocation = top.opener.window.location;
} else if(to.target == "parentFrame") {
targetLocation = parent.location;
} else if(to.target == "frame") {
// targetLocation = to.frame.contentWindow.location;
$(to.frame).attr('src', targetUrl || 'about:blank');
return;
}
if (!_needsReload(targetLocation, to.url)) {
targetLocation.href = targetUrl || 'about:blank';
} else {
targetLocation.href = $axure.utils.getReloadPath() + "#" + encodeURI(targetUrl);
}
}
} else {
$ax.navigate({
url: to,
target: "current",
includeVariables: arguments[1]
});
}
};
var _needsReload = function(oldLocation, newBaseUrl) {
var reload = false;
try {
var oldUrl = oldLocation.href;
var oldBaseUrl = oldUrl.split("#")[0];
var lastslash = oldBaseUrl.lastIndexOf("/");
if(lastslash > 0) {
oldBaseUrl = oldBaseUrl.substring(lastslash + 1, oldBaseUrl.length);
if(oldBaseUrl == encodeURI(newBaseUrl)) {
reload = true;
}
}
} catch(e) {
}
return reload;
};
var _getPopupFeatures = function(options) {
var defaultOptions = {
toolbar: true,
scrollbars: true,
location: true,
status: true,
menubar: true,
directories: true,
resizable: true,
centerwindow: true,
left: -1,
top: -1,
height: -1,
width: -1
};
var selectedOptions = $.extend({}, defaultOptions, options);
var optionsList = [];
optionsList.push('toolbar=' + (selectedOptions.toolbar ? 'yes' : 'no'));
optionsList.push('scrollbars=' + (selectedOptions.scrollbars ? 'yes' : 'no'));
optionsList.push('location=' + (selectedOptions.location ? 'yes' : 'no'));
optionsList.push('status=' + (selectedOptions.status ? 'yes' : 'no'));
optionsList.push('menubar=' + (selectedOptions.menubar ? 'yes' : 'no'));
optionsList.push('directories=' + (selectedOptions.directories ? 'yes' : 'no'));
optionsList.push('resizable=' + (selectedOptions.resizable ? 'yes' : 'no'));
if(selectedOptions.centerwindow == false) {
if(selectedOptions.left > -1) {
optionsList.push('left=' + selectedOptions.left);
}
if(selectedOptions.top > -1) {
optionsList.push('top=' + selectedOptions.top);
}
}
var height = 0;
var width = 0;
if(selectedOptions.height > 0) {
optionsList.push('height=' + selectedOptions.height);
height = selectedOptions.height;
}
if(selectedOptions.width > 0) {
optionsList.push('width=' + selectedOptions.width);
width = selectedOptions.width;
}
var features = optionsList.join(',');
if(selectedOptions.centerwindow) {
var winl = (window.screen.width - width) / 2;
var wint = (window.screen.height - height) / 2;
features = features + ',left=' + winl + ',top=' + wint;
}
return features;
};
/**
Closes a window
*/
$ax.public.closeWindow = $ax.closeWindow = function() {
parent.window.close();
};
/**
Goes back
*/
$ax.public.back = $ax.back = function() {
window.history.go(-1);
};
/**
Reloads the current page.
# includeVariables: true if it should re-include the variables when the page is reloaded
*/
$ax.public.reload = $ax.reload = function(includeVariables) {
var targetUrl = (includeVariables === false)
? $axure.utils.getReloadPath() + "#" + encodeURI($ax.pageData.url)
: $axure.utils.getReloadPath() + "#" + encodeURI($ax.globalVariableProvider.getLinkUrl($ax.pageData.url));
window.location.href = targetUrl;
};
/**
Sets a variable.
# name: The name of the global variable to set
# value: The value that should be set
*/
$ax.public.setGlobalVariable = $ax.setGlobalVariable = function(name, value) {
if(!name || !value) {
return;
}
$ax.globalVariableProvider.setVariableValue(name, value);
};
/**
Gets the value of a global variable
# name: The name of the global variable value to get
*/
$ax.public.getGlobalVariable = $ax.getGlobalVariable = function(name) {
$ax.globalVariableProvider.getVariableValue(name);
};
$ax.getObjectFromElementIdDisregardHex = function (elementId) {
var elementIdInput = elementId.charAt(0) == '#' ? elementId.substring(1) : elementId;
return this.getObjectFromElementId(elementIdInput);
}
$ax.getTypeFromElementId = function(elementId) {
var obj = this.getObjectFromElementIdDisregardHex(elementId);
return obj && obj.type;
};
$ax.getNumFromPx = function(pxNum) {
return Number(pxNum.replace('px', ''));
}
});

278
web/main/static/resources/scripts/axure/drag.js

@ -1,278 +0,0 @@
$axure.internal(function($ax) {
var widgetDragInfo = new Object();
var _drag = {};
$ax.drag = _drag;
$ax.drag.GetWidgetDragInfo = function() {
return $.extend({}, widgetDragInfo);
};
$ax.drag.StartDragWidget = function(event, id) {
$ax.setjBrowserEvent(jQuery.Event(event));
//we should only start drag on one target, otherwise the _dragWidget and _stopDragWidget events from multiple targets will be conflicted
if(event.donotdrag || widgetDragInfo.started) return;
var x, y;
var tg;
if(IE_10_AND_BELOW) {
x = window.event.clientX + window.document.documentElement.scrollLeft + window.document.body.scrollLeft;
y = window.event.clientY + window.document.documentElement.scrollTop + window.document.body.scrollTop;
tg = window.event.srcElement;
} else {
if(event.changedTouches) {
x = event.changedTouches[0].pageX;
y = event.changedTouches[0].pageY;
} else {
x = event.pageX;
y = event.pageY;
event.preventDefault();
}
tg = event.target;
}
widgetDragInfo.started = true;
widgetDragInfo.hasDragged= false;
widgetDragInfo.widgetId = id;
widgetDragInfo.cursorStartX = x;
widgetDragInfo.cursorStartY = y;
widgetDragInfo.lastX = x;
widgetDragInfo.lastY = y;
widgetDragInfo.currentX = x;
widgetDragInfo.currentY = y;
widgetDragInfo.movedWidgets = new Object();
widgetDragInfo.startTime = (new Date()).getTime();
widgetDragInfo.targetWidget = tg;
var movedownName = IE_10_AND_BELOW && $ax.features.supports.windowsMobile ?
$ax.features.eventNames.mouseDownName : $ax.features.eventNames.mouseMoveName;
$ax.event.addEvent(document, movedownName, _dragWidget, true);
$ax.event.addEvent(document, $ax.features.eventNames.mouseUpName, _stopDragWidget, true);
//$ax.legacy.SuppressBubble(event);
};
var _dragWidget = function(event) {
$ax.setjBrowserEvent(jQuery.Event(event));
var x, y;
if(IE_10_AND_BELOW) {
x = window.event.clientX + window.document.documentElement.scrollLeft + window.document.body.scrollLeft;
y = window.event.clientY + window.document.documentElement.scrollTop + window.document.body.scrollTop;
} else {
if(event.changedTouches) {
x = event.changedTouches[0].pageX;
y = event.changedTouches[0].pageY;
//allow scroll (defaults) if only swipe events have cases and delta x is less than 5px and not blocking scrolling
var deltaX = x - widgetDragInfo.currentX;
var target = window.document.getElementById(widgetDragInfo.widgetId);
if($ax.event.hasSyntheticEvent(widgetDragInfo.widgetId, "onDrag") || $ax.event.hasSyntheticEvent(widgetDragInfo.widgetId, "onSwipeUp") ||
$ax.event.hasSyntheticEvent(widgetDragInfo.widgetId, "onSwipeDown") || (deltaX * deltaX) > 25
|| ($ax.document.configuration.preventScroll && $ax.legacy.GetScrollable(target) == window.document.body)) {
event.preventDefault();
}
} else {
x = event.pageX;
y = event.pageY;
}
}
widgetDragInfo.xDelta = x - widgetDragInfo.currentX;
widgetDragInfo.yDelta = y - widgetDragInfo.currentY;
widgetDragInfo.lastX = widgetDragInfo.currentX;
widgetDragInfo.lastY = widgetDragInfo.currentY;
widgetDragInfo.currentX = x;
widgetDragInfo.currentY = y;
widgetDragInfo.currentTime = (new Date()).getTime();
// $ax.legacy.SuppressBubble(event);
if(!widgetDragInfo.hasDragged) {
widgetDragInfo.hasDragged = true;
$ax.event.raiseSyntheticEvent(widgetDragInfo.widgetId, "onDragStart");
//only update to move cursor is we are moving objects
if($ax.event.hasSyntheticEvent(widgetDragInfo.widgetId, "onDrag")) {
widgetDragInfo.cursorChanged = true;
widgetDragInfo.oldBodyCursor = window.document.body.style.cursor;
window.document.body.style.cursor = 'move';
var widget = window.document.getElementById(widgetDragInfo.widgetId);
widgetDragInfo.oldCursor = widget.style.cursor;
widget.style.cursor = 'move';
//need to do this in order to change the cursor under nice scroll
var niceScrollContainer = $ax.adaptive.getNiceScrollContainer(widget);
if(niceScrollContainer) {
widgetDragInfo.oldNiceScrollContainerCursor = niceScrollContainer.style.cursor;
niceScrollContainer.style.cursor = 'move';
}
}
}
$ax.event.raiseSyntheticEvent(widgetDragInfo.widgetId, "onDrag");
};
var _suppressClickAfterDrag = function(event) {
_removeSuppressEvents();
$ax.legacy.SuppressBubble(event);
};
var _removeSuppressEvents = function () {
if(IE_10_AND_BELOW) {
$ax.event.removeEvent(event.srcElement, 'click', _suppressClickAfterDrag, undefined, true);
$ax.event.removeEvent(widgetDragInfo.targetWidget, 'mousemove', _removeSuppressEvents, undefined, true);
} else {
$ax.event.removeEvent(document, "click", _suppressClickAfterDrag, true);
$ax.event.removeEvent(document, 'mousemove', _removeSuppressEvents, true);
}
};
var _stopDragWidget = function(event) {
$ax.setjBrowserEvent(jQuery.Event(event));
var tg;
var movedownName = IE_10_AND_BELOW && $ax.features.supports.windowsMobile ?
$ax.features.eventNames.mouseDownName : $ax.features.eventNames.mouseMoveName;
$ax.event.removeEvent(document, movedownName, _dragWidget, true);
$ax.event.removeEvent(document, $ax.features.eventNames.mouseUpName, _stopDragWidget, true);
tg = IE_10_AND_BELOW ? window.event.srcElement : event.target;
if(widgetDragInfo.hasDragged) {
widgetDragInfo.currentTime = (new Date()).getTime();
$ax.event.raiseSyntheticEvent(widgetDragInfo.widgetId, "onDragDrop");
if($ax.globalVariableProvider.getVariableValue('totaldragx') < -30 && $ax.globalVariableProvider.getVariableValue('dragtime') < 1000) {
$ax.event.raiseSyntheticEvent(widgetDragInfo.widgetId, "onSwipeLeft");
}
if($ax.globalVariableProvider.getVariableValue('totaldragx') > 30 && $ax.globalVariableProvider.getVariableValue('dragtime') < 1000) {
$ax.event.raiseSyntheticEvent(widgetDragInfo.widgetId, "onSwipeRight");
}
var totalDragY = $ax.globalVariableProvider.getVariableValue('totaldragy');
if(totalDragY < -30 && $ax.globalVariableProvider.getVariableValue('dragtime') < 1000) {
$ax.event.raiseSyntheticEvent(widgetDragInfo.widgetId, "onSwipeUp");
}
if(totalDragY > 30 && $ax.globalVariableProvider.getVariableValue('dragtime') < 1000) {
$ax.event.raiseSyntheticEvent(widgetDragInfo.widgetId, "onSwipeDown");
}
if(widgetDragInfo.cursorChanged) {
window.document.body.style.cursor = widgetDragInfo.oldBodyCursor;
var widget = window.document.getElementById(widgetDragInfo.widgetId);
// It may be null if OnDragDrop filtered out the widget
if(widget != null) widget.style.cursor = widgetDragInfo.oldCursor;
//we don't seems need to reset nicescroll cursor on container, nicescroll seems updates its cursor
// if(widgetDragInfo.oldNiceScrollContainerCursor != undefined) {
// var niceScrollContainer = $ax.adaptive.getNiceScrollContainer(widget);
// if(niceScrollContainer) niceScrollContainer.style.cursor = widgetDragInfo.oldNiceScrollContainerCursor;
// widgetDragInfo.oldNiceScrollContainerCursor = undefined;
// }
widgetDragInfo.cursorChanged = undefined;
}
if(widgetDragInfo.targetWidget == tg && !event.changedTouches) {
// suppress the click after the drag on desktop browsers
if(IE_10_AND_BELOW && widgetDragInfo.targetWidget) {
$ax.event.addEvent(widgetDragInfo.targetWidget, 'click', _suppressClickAfterDrag, true, true);
$ax.event.addEvent(widgetDragInfo.targetWidget, "onmousemove", _removeSuppressEvents, true, true);
} else {
$ax.event.addEvent(document, "click", _suppressClickAfterDrag, true);
$ax.event.addEvent(document, "mousemove", _removeSuppressEvents, true);
}
}
}
widgetDragInfo.hasDragged = false;
widgetDragInfo.movedWidgets = new Object();
widgetDragInfo.started = false;
return false;
};
$ax.drag.GetDragX = function() {
if(widgetDragInfo.hasDragged) return widgetDragInfo.xDelta;
return 0;
};
$ax.drag.GetDragY = function() {
if(widgetDragInfo.hasDragged) return widgetDragInfo.yDelta;
return 0;
};
$ax.drag.GetTotalDragX = function() {
if(widgetDragInfo.hasDragged) return widgetDragInfo.currentX - widgetDragInfo.cursorStartX;
return 0;
};
$ax.drag.GetTotalDragY = function() {
if(widgetDragInfo.hasDragged) return widgetDragInfo.currentY - widgetDragInfo.cursorStartY;
return 0;
};
$ax.drag.GetDragTime = function() {
if(widgetDragInfo.hasDragged) return widgetDragInfo.currentTime - widgetDragInfo.startTime;
return 600000;
};
$ax.drag.LogMovedWidgetForDrag = function (id, dragInfo) {
dragInfo = dragInfo || widgetDragInfo;
if(dragInfo.hasDragged) {
var containerIndex = id.indexOf('_container');
if(containerIndex != -1) id = id.substring(0, containerIndex);
// If state or other non-widget id, this should not be dragged, and should exit out to avoid exceptions.
if(!$obj(id)) return;
var query = $ax('#' + id);
//var x = query.left();
//var y = query.top();
var viewportLocation = query.viewportLocation();
var x = viewportLocation.left;
var y = viewportLocation.top;
var movedWidgets = dragInfo.movedWidgets;
if(!movedWidgets[id]) {
movedWidgets[id] = new Location(x, y);
}
}
};
var Location = function(x, y) {
this.x = x;
this.y = y;
};
$ax.drag.location = Location;
var Rectangle = $ax.drag.Rectangle = function(x, y, width, height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.right = x + width;
this.bottom = y + height;
};
Rectangle.prototype.IntersectsWith = function(rect) {
if(this.Invalid()) return false;
if(rect.length) {
for(var i = 0; i < rect.length; i++) if(!rect[i].Invalid && this.IntersectsWith(rect[i])) return true;
return false;
}
if(rect.Invalid()) return false;
return this.x < rect.right && this.right > rect.x && this.y < rect.bottom && this.bottom > rect.y;
};
Rectangle.prototype.Invalid = function() {
return this.x == -1 && this.y == -1 && this.width == -1 && this.height == -1;
};
Rectangle.prototype.Move = function(x, y) {
return new Rectangle(x, y, this.width, this.height);
};
});

1996
web/main/static/resources/scripts/axure/events.js

File diff suppressed because it is too large

579
web/main/static/resources/scripts/axure/expr.js

@ -1,579 +0,0 @@
// ******* Expr MANAGER ******** //
$axure.internal(function($ax) {
var _expr = $ax.expr = {};
var _binOpHandlers = {
'&&': function(left, right) { return _binOpOverride(left, right, function(left) { return $ax.getBool(left) && $ax.getBool(right()); }); },
'||': function(left, right) { return _binOpOverride(left, right, function(left) { return $ax.getBool(left) || $ax.getBool(right()); }); },
'==': function(left, right) { return isEqual(left, right, true); },
'!=': function(left, right) { return !isEqual(left, right, true); },
'>': function(left, right) { return _binOpNum(left, right, function(left, right) { return left > right; }); },
'<': function(left, right) { return _binOpNum(left, right, function(left, right) { return left < right; }); },
'>=': function(left, right) { return _binOpNum(left, right, function(left, right) { return left >= right; }); },
'<=': function(left, right) { return _binOpNum(left, right, function(left, right) { return left <= right; }); }
};
var checkOps = function(left, right) {
return left == undefined || right == undefined;
};
var isEqual = function (left, right, isFunction) {
if (isFunction) {
//if left and right is function, then get the value
//otherwise left and right should be already the value we want
left = left();
right = right();
}
if(checkOps(left, right)) return false;
if(left instanceof Date && right instanceof Date) {
if(left.getMilliseconds() != right.getMilliseconds()) return false;
if(left.getSeconds() != right.getSeconds()) return false;
if(left.getMinutes() != right.getMinutes()) return false;
if(left.getHours() != right.getHours()) return false;
if(left.getDate() != right.getDate()) return false;
if(left.getMonth() != right.getMonth()) return false;
if(left.getYear() != right.getYear()) return false;
return true;
}
if(left instanceof Object && right instanceof Object) {
var prop;
// Go through all of lefts properties and compare them to rights.
for(prop in left) {
if(!left.hasOwnProperty(prop)) continue;
// If left has a property that the right doesn't they are not equal.
if(!right.hasOwnProperty(prop)) return false;
// If any of their properties are not equal, they are not equal.
if(!isEqual(left[prop], right[prop], false)) return false;
}
for(prop in right) {
// final check to make sure right doesn't have some extra properties that make them not equal.
if(left.hasOwnProperty(prop) != right.hasOwnProperty(prop)) return false;
}
return true;
}
return $ax.getBool(left) == $ax.getBool(right);
};
var _binOpOverride = function(left, right, func) {
left = left();
if(left == undefined) return false;
var res = func(left, right);
return res == undefined ? false : res;
};
var _binOpNum = function(left, right, func) {
var left = left();
var right = right();
if(checkOps(left, right)) return false;
return func(left, Number(right));
};
var _exprHandlers = {};
_exprHandlers.array = function(expr, eventInfo) {
var returnVal = [];
for(var i = 0; i < expr.items.length; i++) {
returnVal[returnVal.length] = _evaluateExpr(expr.items[i], eventInfo);
}
return returnVal;
};
_exprHandlers.binaryOp = function(expr, eventInfo) {
var left = function() { return expr.leftExpr && _evaluateExpr(expr.leftExpr, eventInfo); };
var right = function() { return expr.rightExpr && _evaluateExpr(expr.rightExpr, eventInfo); };
if(left == undefined || right == undefined) return false;
return _binOpHandlers[expr.op](left, right);
};
_exprHandlers.block = function(expr, eventInfo) {
var subExprs = expr.subExprs;
for(var i = 0; i < subExprs.length; i++) {
_evaluateExpr(subExprs[i], eventInfo); //ignore the result
}
};
_exprHandlers.booleanLiteral = function(expr) {
return expr.value;
};
_exprHandlers.nullLiteral = function() { return null; };
_exprHandlers.pathLiteral = function(expr, eventInfo) {
if(expr.isThis) return [eventInfo.srcElement];
if(expr.isFocused && window.lastFocusedControl) {
$ax('#' + window.lastFocusedControl).focus();
return [window.lastFocusedControl];
}
if(expr.isTarget) return [eventInfo.targetElement];
return $ax.getElementIdsFromPath(expr.value, eventInfo);
};
_exprHandlers.panelDiagramLiteral = function(expr, eventInfo) {
var elementIds = $ax.getElementIdsFromPath(expr.panelPath, eventInfo);
var elementIdsWithSuffix = [];
var suffix = '_state' + expr.panelIndex;
for(var i = 0; i < elementIds.length; i++) {
elementIdsWithSuffix[i] = $ax.repeater.applySuffixToElementId(elementIds[i], suffix);
}
return String($jobj(elementIdsWithSuffix).data('label'));
};
_exprHandlers.fcall = function(expr, eventInfo) {
var oldTarget = eventInfo.targetElement;
var targets = [];
var fcallArgs = [];
var exprArgs = expr.arguments;
for(var i = 0; i < expr.arguments.length; i++) {
var exprArg = exprArgs[i];
var fcallArg = '';
if(targets.length) {
for(var j = 0; j < targets.length; j++) {
if(exprArg == null) {
fcallArgs[j][i] = null;
continue;
}
eventInfo.targetElement = targets[j];
fcallArg = _evaluateExpr(exprArg, eventInfo);
if(typeof (fcallArg) == 'undefined') return '';
fcallArgs[j][i] = fcallArg;
}
} else {
if(exprArg == null) {
fcallArgs[i] = null;
continue;
}
fcallArg = _evaluateExpr(exprArg, eventInfo);
if(typeof (fcallArg) == 'undefined') return '';
fcallArgs[i] = fcallArg;
}
// We do support null exprArgs...
// TODO: This makes 2 assumptions that may change in the future. 1. The pathLiteral is the always the first arg. 2. there is always only 1 pathLiteral
if(exprArg && exprArg.exprType == 'pathLiteral') {
targets = fcallArg;
// fcallArgs is now an array of an array of args
for(j = 0; j < targets.length; j++) fcallArgs[j] = [[fcallArg[j]]];
}
}
// we want to preserve the target element from outside this function.
eventInfo.targetElement = oldTarget;
var retval = '';
if(targets.length) {
// Go backwards so retval is the first item.
for(i = targets.length - 1; i >= 0; i--) {
var args = fcallArgs[i];
// Add event info to the end
args[args.length] = eventInfo;
retval = _exprFunctions[expr.functionName].apply(this, args);
}
} else fcallArgs[fcallArgs.length] = eventInfo;
return targets.length ? retval : _exprFunctions[expr.functionName].apply(this, fcallArgs);
};
_exprHandlers.globalVariableLiteral = function(expr) {
return expr.variableName;
};
_exprHandlers.keyPressLiteral = function(expr) {
var keyInfo = {};
keyInfo.keyCode = expr.keyCode;
keyInfo.ctrl = expr.ctrl;
keyInfo.alt = expr.alt;
keyInfo.shift = expr.shift;
return keyInfo;
};
_exprHandlers.adaptiveViewLiteral = function(expr) {
return expr.id;
};
_exprHandlers.optionLiteral = function(expr) {
return expr.value;
}
var _substituteSTOs = function(expr, eventInfo) {
//first evaluate the local variables
var scope = {};
for(var varName in expr.localVariables) {
scope[varName] = $ax.expr.evaluateExpr(expr.localVariables[varName], eventInfo);
}
// TODO: [ben] Date and data object (obj with info for url or image) both need to return non-strings.
var i = 0;
var retval;
var retvalString = expr.value.replace(/\[\[(?!\[)(.*?)\]\](?=\]*)/g, function(match) {
var sto = expr.stos[i++];
if(sto.sto == 'error') return match;
try {
var result = $ax.evaluateSTO(sto, scope, eventInfo);
} catch(e) {
return match;
}
if((result instanceof Object) && i == 1 && expr.value.substring(0, 2) == '[[' &&
expr.value.substring(expr.value.length - 2) == ']]') {
// If the result was an object, this was the first result, and the whole thing was this expresion.
retval = result;
}
return ((result instanceof Object) && (result.label || result.text)) || result;
});
// If more than one group returned, the object is not valid
if(i != 1) retval = false;
return retval || retvalString;
};
_exprHandlers.htmlLiteral = function (expr, eventInfo) {
eventInfo.htmlLiteral = true;
var html = _substituteSTOs(expr, eventInfo);
eventInfo.htmlLiteral = false
return html;
};
_exprHandlers.stringLiteral = function(expr, eventInfo) {
return _substituteSTOs(expr, eventInfo);
};
var _exprFunctions = {};
_exprFunctions.SetCheckState = function(elementIds, value) {
var toggle = value == 'toggle';
var boolValue = Boolean(value) && value != 'false';
for(var i = 0; i < elementIds.length; i++) {
var query = $ax('#' + elementIds[i]);
query.selected(toggle ? !query.selected() : boolValue);
}
};
_exprFunctions.SetSelectedOption = function(elementIds, value) {
for(var i = 0; i < elementIds.length; i++) {
var elementId = elementIds[i];
var obj = $jobj($ax.INPUT(elementId));
if(obj.val() == value) return;
obj.val(value);
if($ax.event.HasSelectionChanged($ax.getObjectFromElementId(elementId))) $ax.event.raiseSyntheticEvent(elementId, 'onSelectionChange');
}
};
_exprFunctions.SetGlobalVariableValue = function(varName, value) {
$ax.globalVariableProvider.setVariableValue(varName, value);
};
_exprFunctions.SetWidgetFormText = function(elementIds, value) {
for(var i = 0; i < elementIds.length; i++) {
var elementId = elementIds[i];
var inputId = $ax.repeater.applySuffixToElementId(elementId, '_input');
var obj = $jobj(inputId);
if(obj.val() == value || (value == '' && $ax.placeholderManager.isActive(elementId))) return;
obj.val(value);
$ax.placeholderManager.updatePlaceholder(elementId, !value);
if($ax.event.HasTextChanged($ax.getObjectFromElementId(elementId))) $ax.event.TryFireTextChanged(elementId);
}
};
_exprFunctions.SetFocusedWidgetText = function(elementId, value) {
if(window.lastFocusedControl) {
var elementId = window.lastFocusedControl;
var type = $obj(elementId).type;
if ($ax.public.fn.IsTextBox(type) || $ax.public.fn.IsTextArea(type)) _exprFunctions.SetWidgetFormText([elementId], value);
else _exprFunctions.SetWidgetRichText([elementId], value, true);
}
};
_exprFunctions.GetRtfElementHeight = function(rtfElement) {
if(rtfElement.innerHTML == '') rtfElement.innerHTML = '&nbsp;';
return rtfElement.offsetHeight;
};
_exprFunctions.SetWidgetRichText = function(ids, value, plain) {
// Converts dates, widgetinfo, and the like to strings.
value = _exprFunctions.ToString(value);
//Replace any newlines with line breaks
var finalValue = value.replace(/\r\n/g, '<br>').replace(/\n/g, '<br>');
for(var i = 0; i < ids.length; i++) {
var id = ids[i];
// If calling this on button shape, get the id of the rich text panel inside instead
if($obj(id).type !== $ax.constants.LINK_TYPE) id = $ax.GetTextPanelId(id, true);
var element = window.document.getElementById(id);
$ax.visibility.SetVisible(element, value != '');
$ax.style.transformTextWithVerticalAlignment(id, function() {
var spans = $jobj(id).find('span');
if(plain) {
// Can't set value as text because '<br/>' doesn't actually do a line break
// Can't set vaule as html because it doesn't like '<' and ignores all after it
// Create tags yourself
var lines = value.split(/\r\n|\n/);
//if we are dealing with only one line, just reuse the old one
if(spans.length === 1 && lines.length === 1) {
$(spans[0]).text(value);
return;
}
// Wrap in span and p, style them accordingly.
var span = $('<span></span>');
if(spans.length > 0) {
span.attr('style', $(spans[0]).attr('style'));
span.attr('id', $(spans[0]).attr('id'));
}
if(lines.length == 1) span.text(value);
else {
for(var i = 0; i < lines.length; i++) {
if(i != 0) span.append($('<br />'));
var line = lines[i];
if(line.length == 0) continue;
var subSpan = $('<span />');
subSpan.text(line);
span.append(subSpan);
}
}
var ps = $jobj(id).find('p');
if(ps && ps.length) {
ps[0].innerHTML = $('<div></div>').append(span).html();;
if(ps.length > 1) {
for(var i = 1; i < ps.length; i++) {
$(ps[i]).remove();
}
}
} else {
var p = $('<p></p>');
p.append(span);
element.innerHTML = $('<div></div>').append(p).html();
}
} else element.innerHTML = finalValue;
});
if(!plain) $ax.style.CacheOriginalText(id, true);
}
};
_exprFunctions.GetCheckState = function(ids) {
return $ax('#' + ids[0]).selected();
};
_exprFunctions.GetDisabledState = function (ids) {
return !$ax('#' + ids[0]).enabled();
};
_exprFunctions.GetSelectedOption = function (ids) {
var inputs = $jobj($ax.INPUT(ids[0]));
return inputs.length ? inputs[0].value : '';
};
_exprFunctions.GetNum = function(str) {
//Setting a GlobalVariable to some blank text then setting a widget to the value of that variable would result in 0 not ""
//I have fixed this another way so commenting this should be fine now
//if (!str) return "";
return isNaN(str) ? str : Number(str);
};
_exprFunctions.GetGlobalVariableValue = function(id) {
return $ax.globalVariableProvider.getVariableValue(id);
};
_exprFunctions.GetGlobalVariableLength = function(id) {
return _exprFunctions.GetGlobalVariableValue(id).length;
};
_exprFunctions.GetWidgetText = function(ids) {
if($ax.placeholderManager.isActive(ids[0])) return '';
var input = $ax.INPUT(ids[0]);
return $ax('#' + ($jobj(input).length ? input : ids[0])).text();
};
_exprFunctions.GetFocusedWidgetText = function() {
if(window.lastFocusedControl) {
return $ax('#' + window.lastFocusedControl).text();
} else {
return "";
}
};
_exprFunctions.GetWidgetValueLength = function(ids) {
var id = ids[0];
if(!id) return undefined;
if($ax.placeholderManager.isActive(id)) return 0;
var obj = $jobj($ax.INPUT(id));
if(!obj.length) obj = $jobj(id);
var val = obj[0].value || _exprFunctions.GetWidgetText([id]);
return val.length;
};
_exprFunctions.GetPanelState = function(ids) {
var id = ids[0];
if(!id) return undefined;
var stateId = $ax.visibility.GetPanelState(id);
return stateId && String($jobj(stateId).data('label'));
};
_exprFunctions.GetWidgetVisibility = function(ids) {
var id = ids[0];
if(!id) return undefined;
return $ax.visibility.IsIdVisible(id);
};
// ***************** Validation Functions ***************** //
_exprFunctions.IsValueAlpha = function(val) {
var isAlphaRegex = new RegExp("^[a-z\\s]+$", "gi");
return isAlphaRegex.test(val);
};
_exprFunctions.IsValueNumeric = function(val) {
var isNumericRegex = new RegExp("^[0-9,\\.\\s]+$", "gi");
return isNumericRegex.test(val);
};
_exprFunctions.IsValueAlphaNumeric = function(val) {
var isAlphaNumericRegex = new RegExp("^[0-9a-z\\s]+$", "gi");
return isAlphaNumericRegex.test(val);
};
_exprFunctions.IsValueOneOf = function(val, values) {
for(var i = 0; i < values.length; i++) {
var option = values[i];
if(val == option) return true;
}
//by default, return false
return false;
};
_exprFunctions.IsValueNotAlpha = function(val) {
return !_exprFunctions.IsValueAlpha(val);
};
_exprFunctions.IsValueNotNumeric = function(val) {
return !_exprFunctions.IsValueNumeric(val);
};
_exprFunctions.IsValueNotAlphaNumeric = function(val) {
return !_exprFunctions.IsValueAlphaNumeric(val);
};
_exprFunctions.IsValueNotOneOf = function(val, values) {
return !_exprFunctions.IsValueOneOf(val, values);
};
_exprFunctions.GetKeyPressed = function(eventInfo) {
return eventInfo.keyInfo;
};
_exprFunctions.GetCursorRectangles = function() {
var rects = new Object();
rects.lastRect = new $ax.drag.Rectangle($ax.lastMouseLocation.x, $ax.lastMouseLocation.y, 1, 1);
rects.currentRect = new $ax.drag.Rectangle($ax.mouseLocation.x, $ax.mouseLocation.y, 1, 1);
return rects;
};
_exprFunctions.GetWidgetRectangles = function (elementIds, eventInfo) {
var elementId = elementIds[0];
var rects = new Object();
var jObj = $jobj(elementId);
var invalid = jObj.length == 0;
var parent = jObj;
// Or are in valid if no obj can be found, or if it is not visible.
while(parent.length != 0 && !parent.is('body')) {
if(parent.css('display') == 'none') {
invalid = true;
break;
}
parent = parent.parent();
}
if(invalid) {
rects.lastRect = rects.currentRect = new $ax.drag.Rectangle(-1, -1, -1, -1);
return rects;
}
var axObj = $ax('#' + elementId);
var boundingRect = axObj.viewportBoundingRect();
rects.lastRect = new $ax.drag.Rectangle(
boundingRect.left,
boundingRect.top,
boundingRect.width,
boundingRect.height);
//rects.lastRect = new $ax.drag.Rectangle(
// axObj.left(),
// axObj.top(),
// axObj.width(),
// axObj.height());
rects.currentRect = rects.lastRect;
return rects;
};
_exprFunctions.GetWidget = function(elementId) {
return $ax.getWidgetInfo(elementId[0]);
};
_exprFunctions.GetAdaptiveView = function (eventInfo) {
if (eventInfo && eventInfo.srcElement) {
var id = eventInfo.srcElement;
var diagramObject = $ax.getObjectFromElementId(id);
if (diagramObject.owner.type == 'Axure:Master') {
var viewIdChain = $ax.style.getViewIdChain($ax.adaptive.currentViewId || '', id, diagramObject);
if (viewIdChain.length > 0) return viewIdChain[viewIdChain.length - 1];
else return '19e82109f102476f933582835c373474';
}
}
return $ax.adaptive.currentViewId || '';
};
_exprFunctions.IsEntering = function(movingRects, targetRects) {
return !movingRects.lastRect.IntersectsWith(targetRects.currentRect) && movingRects.currentRect.IntersectsWith(targetRects.currentRect);
};
_exprFunctions.IsLeaving = function(movingRects, targetRects) {
return movingRects.lastRect.IntersectsWith(targetRects.currentRect) && !movingRects.currentRect.IntersectsWith(targetRects.currentRect);
};
var _IsOver = _exprFunctions.IsOver = function(movingRects, targetRects) {
return movingRects.currentRect.IntersectsWith(targetRects.currentRect);
};
_exprFunctions.IsNotOver = function(movingRects, targetRects) {
return !_IsOver(movingRects, targetRects);
};
_exprFunctions.ValueContains = function(inputString, value) {
return inputString.indexOf(value) > -1;
};
_exprFunctions.ValueNotContains = function(inputString, value) {
return !_exprFunctions.ValueContains(inputString, value);
};
_exprFunctions.ToString = function(value) {
if(value.isWidget) {
return value.text;
}
return String(value);
};
var _evaluateExpr = $ax.expr.evaluateExpr = function(expr, eventInfo, toString) {
if(expr === undefined || expr === null) return undefined;
var result = _exprHandlers[expr.exprType](expr, eventInfo);
return toString ? _exprFunctions.ToString(result) : result;
};
});

286
web/main/static/resources/scripts/axure/flyout.js

@ -1,286 +0,0 @@
// ******* Flyout MANAGER ******** //
$axure.internal(function($ax) {
var _flyoutManager = $ax.flyoutManager = {};
var getFlyoutLabel = function(panelId) {
return panelId + '_flyout';
};
var _unregisterPanel = function(panelId, keepShown) {
$ax.geometry.unregister(getFlyoutLabel(panelId));
if(panelToSrc[panelId]) {
$ax.style.RemoveRolloverOverride(panelToSrc[panelId]);
delete panelToSrc[panelId];
}
if(!keepShown) {
$ax.action.addAnimation(panelId, $ax.action.queueTypes.fade, function() {
$ax('#' + panelId).hide();
});
}
};
_flyoutManager.unregisterPanel = _unregisterPanel;
var genPoint = $ax.geometry.genPoint;
var _updateFlyout = function(panelId) {
var label = getFlyoutLabel(panelId);
if(!$ax.geometry.polygonRegistered(label)) return;
var info = $ax.geometry.getPolygonInfo(label);
var rects = info && info.rects;
var targetWidget = $ax.getWidgetInfo(panelId);
rects.target = $ax.geometry.genRect(targetWidget);
// Src will stay the same, just updating
$ax.flyoutManager.registerFlyout(rects, panelId, panelToSrc[panelId]);
if(!$ax.geometry.checkInsideRegion(label)) _unregisterPanel(panelId);
};
_flyoutManager.updateFlyout = _updateFlyout;
var panelToSrc = {};
var _registerFlyout = function(rects, panelId, srcId) {
var label = _getFlyoutLabel(panelId);
var callback = function(info) {
// If leaving object or already outside it, then unregister, otherwise just return
if(!info.exiting && !info.outside) return;
_unregisterPanel(panelId);
};
var points = [];
var lastSrcId = panelToSrc[panelId];
if(lastSrcId != srcId) {
if(lastSrcId) $ax.style.RemoveRolloverOverride(lastSrcId);
if(srcId) {
$ax.style.AddRolloverOverride(srcId);
panelToSrc[panelId] = srcId;
} else delete panelToSrc[panelId];
}
// rects should be one or two rectangles
if(!rects.src) {
var rect = rects.target;
points.push(genPoint(rect.Left(), rect.Top()));
points.push(genPoint(rect.Right(), rect.Top()));
points.push(genPoint(rect.Right(), rect.Bottom()));
points.push(genPoint(rect.Left(), rect.Bottom()));
} else {
var r0 = rects.src;
var r1 = rects.target;
// Right left of right, left right of left, top below top, bottom above bottom
var rlr = r0.Right() <= r1.Right();
var lrl = r0.Left() >= r1.Left();
var tbt = r0.Top() >= r1.Top();
var bab = r0.Bottom() <= r1.Bottom();
var info = { rlr: rlr, lrl: lrl, tbt: tbt, bab: bab };
if((rlr && lrl) || (tbt && bab)) {
points = getSmallPolygon(r0, r1, info);
} else {
points = getLargePolygon(r0, r1, info);
}
}
$ax.geometry.registerPolygon(label, points, callback, { rects: rects });
};
_flyoutManager.registerFlyout = _registerFlyout;
var _getFlyoutLabel = function(panelId) {
return panelId + '_flyout';
};
var _reregisterAllFlyouts = function() {
for(var panelId in panelToSrc) _reregisterFlyout(panelId);
};
_flyoutManager.reregisterAllFlyouts = _reregisterAllFlyouts;
var _reregisterFlyout = function(panelId) {
var rects = $ax.geometry.getPolygonInfo(getFlyoutLabel(panelId)).rects;
_registerFlyout(rects, panelId, panelToSrc[panelId]);
};
// This is the reduced size polygon connecting r0 to r1 by means of horizontal or vertical lines.
var getSmallPolygon = function(r0, r1, info) {
var points = [];
// NOTE: currently I make the assumption that if horizontal/vertical connecting lines from the src hit the target
// Meaning if horizontal, rlr and lrl are true, and if vertical, tbt and bab are true.
var r0Left = r0.Left();
var r0Right = r0.Right();
var r0Top = r0.Top();
var r0Bottom = r0.Bottom();
var r1Left = r1.Left();
var r1Right = r1.Right();
var r1Top = r1.Top();
var r1Bottom = r1.Bottom();
points.push(genPoint(r1Left, r1Top));
if(!info.tbt) {
points.push(genPoint(r0Left, r1Top));
points.push(genPoint(r0Left, r0Top));
points.push(genPoint(r0Right, r0Top));
points.push(genPoint(r0Right, r1Top));
}
points.push(genPoint(r1Right, r1Top));
if(!info.rlr) {
points.push(genPoint(r1Right, r0Top));
points.push(genPoint(r0Right, r0Top));
points.push(genPoint(r0Right, r0Bottom));
points.push(genPoint(r1Right, r0Bottom));
}
points.push(genPoint(r1Right, r1Bottom));
if(!info.bab) {
points.push(genPoint(r0Right, r1Bottom));
points.push(genPoint(r0Right, r0Bottom));
points.push(genPoint(r0Left, r0Bottom));
points.push(genPoint(r0Left, r1Bottom));
}
points.push(genPoint(r1Left, r1Bottom));
if(!info.lrl) {
points.push(genPoint(r1Left, r0Bottom));
points.push(genPoint(r0Left, r0Bottom));
points.push(genPoint(r0Left, r0Top));
points.push(genPoint(r1Left, r0Top));
}
return points;
};
// This is the original algorithm that connects the most extream corners to make polygon
var getLargePolygon = function(r0, r1, info) {
var points = [];
var r0Left = r0.Left();
var r0Right = r0.Right();
var r0Top = r0.Top();
var r0Bottom = r0.Bottom();
var r1Left = r1.Left();
var r1Right = r1.Right();
var r1Top = r1.Top();
var r1Bottom = r1.Bottom();
// Top lefts
if(info.tbt) {
if(!info.lrl) points.push(genPoint(r0Left, r0Top));
points.push(genPoint(r1Left, r1Top));
} else {
if(info.lrl) points.push(genPoint(r1Left, r1Top));
points.push(genPoint(r0Left, r0Top));
}
// Top rights
if(info.tbt) {
points.push(genPoint(r1Right, r1Top));
if(!info.rlr) points.push(genPoint(r0Right, r0Top));
} else {
points.push(genPoint(r0Right, r0Top));
if(info.rlr) points.push(genPoint(r1Right, r1Top));
}
// Bottom rights
if(info.bab) {
if(!info.rlr) points.push(genPoint(r0Right, r0Bottom));
points.push(genPoint(r1Right, r1Bottom));
} else {
if(info.rlr) points.push(genPoint(r1Right, r1Bottom));
points.push(genPoint(r0Right, r0Bottom));
}
// Bottom Lefts
if(info.bab) {
points.push(genPoint(r1Left, r1Bottom));
if(!info.lrl) points.push(genPoint(r0Left, r0Bottom));
} else {
points.push(genPoint(r0Left, r0Bottom));
if(info.lrl) points.push(genPoint(r1Left, r1Bottom));
}
return points;
};
});
// ******* Placeholder Manager ********* //
$axure.internal(function($ax) {
var _placeholderManager = $ax.placeholderManager = {};
var idToPlaceholderInfo = {};
var _registerPlaceholder = function(elementId, text, password) {
idToPlaceholderInfo[elementId] = { text: text, password: password, active: false };
};
_placeholderManager.registerPlaceholder = _registerPlaceholder;
_placeholderManager.refreshPlaceholder = function (elementId) {
var info = idToPlaceholderInfo[elementId];
if (!info || !info.active) return;
$ax.style.SetWidgetPlaceholder(elementId, true, info.text, info.password);
}
var _updatePlaceholder = function(elementId, active, clearText) {
var inputId = $ax.repeater.applySuffixToElementId(elementId, '_input');
var info = idToPlaceholderInfo[elementId];
if(!info || info.active == active) return;
info.active = active;
if(active) var text = info.text;
else if(!ANDROID) text = clearText ? '' : document.getElementById(inputId).value;
else {
var currentText = document.getElementById(inputId).value;
if(!clearText) text = currentText;
else if(currentText == info.text) text = "";
else {
var lastIndex = currentText.lastIndexOf(info.text);
//here i am assuming the text is always inserted in front
text = currentText.substring(0, lastIndex);
}
}
$ax.style.SetWidgetPlaceholder(elementId, active, text, info.password);
};
_placeholderManager.updatePlaceholder = _updatePlaceholder;
var _isActive = function(elementId) {
var info = idToPlaceholderInfo[elementId];
return Boolean(info && info.active);
};
_placeholderManager.isActive = _isActive;
var _selectRange = function(elementId, start, end) {
$jobj(elementId).each(function() {
if(this.setSelectionRange) {
var validTypes = ["text", "search", "url", "tel", "password"];
if(this.tagName.toLowerCase() != "input" || validTypes.indexOf(this.type) > -1) {
this.focus();
this.setSelectionRange(start, end);
}
} else if(this.createTextRange) {
var range = this.createTextRange();
range.collapse(true);
range.moveEnd('character', end);
range.moveStart('character', start);
range.select();
}
});
};
_placeholderManager.selectRange = _selectRange;
var _moveCaret = function(id, index) {
var inputIndex = id.indexOf('_input');
if(inputIndex == -1) return;
var inputId = id.substring(0, inputIndex);
if(!_isActive(inputId)) return;
_selectRange(id, index, index);
};
_placeholderManager.moveCaret = _moveCaret;
});

294
web/main/static/resources/scripts/axure/geometry.js

@ -1,294 +0,0 @@
// ******* Region MANAGER ******** //
$axure.internal(function($ax) {
var _geometry = $ax.geometry = {};
var regionMap = {};
var regionList = [];
var _unregister = function(label) {
var regionIndex = regionList.indexOf(label);
if(regionIndex != -1) {
var end = $ax.splice(regionList, regionIndex + 1);
$ax.splice(regionList, regionIndex, regionList.length - regionIndex);
regionList = regionList.concat(end);
}
delete regionMap[label];
};
_geometry.unregister = _unregister;
var clear = function() {
regionMap = {};
regionList = [];
};
var _polygonRegistered = function(label) {
return Boolean(regionMap[label]);
};
_geometry.polygonRegistered = _polygonRegistered;
// Must be counterclockwise, or enter/exit will be wrong
var _registerPolygon = function(label, points, callback, info) {
var regionIndex = regionList.indexOf(label);
if(regionIndex == -1) regionList.push(label);
regionMap[label] = { points: points, callback: callback, info: info };
};
_geometry.registerPolygon = _registerPolygon;
var _getPolygonInfo = function(label) {
if(!_polygonRegistered(label)) return undefined;
return regionMap[label].info;
};
_geometry.getPolygonInfo = _getPolygonInfo;
var _genRect = function(info, roundHalfPixel) {
var x = info.pagex();
var y = info.pagey();
var w = info.width();
var h = info.height();
if(roundHalfPixel) {
if(x % 1 != 0) {
x = Math.floor(x);
w++;
}
if(y % 1 != 0) {
y = Math.floor(y);
h++;
}
}
var r = x + w;
var b = y + h;
var rect = {
X: function() { return x; },
Y: function() { return y; },
Wigth: function() { return w; },
Height: function() { return h; },
Left: function() { return x; },
Right: function() { return r; },
Top: function() { return y; },
Bottom: function() { return b; }
};
return rect;
};
_geometry.genRect = _genRect;
var _genPoint = function(x, y) {
return { x: x, y: y };
};
_geometry.genPoint = _genPoint;
var oldPoint = _genPoint(0, 0);
_geometry.tick = function(x, y, end) {
var lastPoint = oldPoint;
var nextPoint = oldPoint = _genPoint(x, y);
var line = { p1: lastPoint, p2: nextPoint };
if(!regionList.length) return;
for(var i = 0; i < regionList.length; i++) {
var region = regionMap[regionList[i]];
var points = region.points;
for(var j = 0; j < points.length; j++) {
var startSegment = points[j];
var endSegment = points[(j + 1) % points.length];
var intersectInfo = linesIntersect(line, { p1: startSegment, p2: endSegment });
if(intersectInfo) {
region.callback(intersectInfo);
break;
}
}
}
if(end) clear();
};
// Info if the one line touches the other (even barely), false otherwise
// Info includes point, if l1 is entering or exiting l2, and any ties that happened, or parallel info
var linesIntersect = function(l1, l2) {
var retval = {};
var ties = {};
var l1p1 = l1.p1.x < l1.p2.x || (l1.p1.x == l1.p2.x && l1.p1.y < l1.p2.y) ? l1.p1 : l1.p2;
var l1p2 = l1.p1.x < l1.p2.x || (l1.p1.x == l1.p2.x && l1.p1.y < l1.p2.y) ? l1.p2 : l1.p1;
var m1 = (l1p2.y - l1p1.y) / (l1p2.x - l1p1.x);
var l2p1 = l2.p1.x < l2.p2.x || (l2.p1.x == l2.p2.x && l2.p1.y < l2.p2.y) ? l2.p1 : l2.p2;
var l2p2 = l2.p1.x < l2.p2.x || (l2.p1.x == l2.p2.x && l2.p1.y < l2.p2.y) ? l2.p2 : l2.p1;
var m2 = (l2p2.y - l2p1.y) / (l2p2.x - l2p1.x);
var l1Vert = l1.p1.x == l1.p2.x;
var l2Vert = l2.p1.x == l2.p2.x;
if(l1Vert || l2Vert) {
if(l1Vert && l2Vert) {
// If the lines don't follow the same path, return
if(l1p1.x != l2p1.x) return false;
// if they never meet, return
if(l1p2.y < l2p1.y || l1p1.y > l2p2.y) return false;
var firstVert = l1p1.y >= l2p1.y ? l1p1 : l2p1;
var secondVert = l1p2.y <= l2p2.y ? l1p2 : l2p2;
// First is from the perspective of l1
retval.parallel = {
first: l1p1 == l1.p1 ? firstVert : secondVert,
second: l1p2 == l1.p2 ? secondVert : firstVert,
sameDirection: (l1p1 == l1.p1) == (l2p1 == l2.p1)
};
return retval;
}
var x1 = l2Vert ? l1p1.x : l2p1.x;
var x2 = l2Vert ? l1p2.x : l2p2.x;
var xVert = l2Vert ? l2p1.x : l1p1.x;
var y = l2Vert ? l1p1.y + (xVert - x1) * m1 : l2p1.y + (xVert - x1) * m2;
var y1 = l2Vert ? l2p1.y : l1p1.y;
var y2 = l2Vert ? l2p2.y : l1p2.y;
if(xVert >= x1 && xVert <= x2 && y >= y1 && y <= y2) {
retval.point = { x: xVert, y: y };
retval.exiting = l2Vert == (y1 == (l2Vert ? l2.p1.y : l1.p1.y)) == (x1 == (l2Vert ? l1.p1.x : l2.p1.x));
retval.entering = !retval.exiting;
// Calculate ties
if(x1 == xVert) {
ties[l2Vert ? 'l1' : 'l2'] = (x1 == (l2Vert ? l1.p1.x : l2.p1.x)) ? 'start' : 'end';
retval.ties = ties;
} else if(x2 == xVert) {
ties[l2Vert ? 'l1' : 'l2'] = (x2 == (l2Vert ? l1.p2.x : l2.p2.x)) ? 'end' : 'start';
retval.ties = ties;
}
if(y1 == y) {
ties[l2Vert ? 'l2' : 'l1'] = (y1 == (l2Vert ? l2.p1.y : l1.p1.y)) ? 'start' : 'end';
retval.ties = ties;
} else if(y2 == y) {
ties[l2Vert ? 'l2' : 'l1'] = (y2 == (l2Vert ? l2.p2.y : l1.p2.y)) ? 'end' : 'start';
retval.ties = ties;
}
return retval;
}
return false;
}
// If here, no vertical lines
if(m1 == m2) {
// If the lines don't follow the same path, return
if(l1p1.y != (l2p1.y + (l1p1.x - l2p1.x) * m1)) return false;
// if they never meet, return
if(l1p2.x < l2p1.x || l1p1.x > l2p2.x) return false;
var first = l1p1.x >= l2p1.x ? l1p1 : l2p1;
var second = l1p2.x <= l2p2.x ? l1p2 : l2p2;
// First is from the perspective of l1
retval.parallel = {
first: l1p1 == l1.p1 ? first : second,
second: l1p2 == l1.p2 ? second : first,
sameDirection: (l1p1 == l1.p1) == (l2p1 == l2.p1)
};
return retval;
}
var x = (l2p1.y - l2p1.x * m2 - l1p1.y + l1p1.x * m1) / (m1 - m2);
// Check if x is out of bounds
if(x >= l1p1.x && x <= l1p2.x && x >= l2p1.x && x <= l2p2.x) {
var y = l1p1.y + (x - l1p1.x) * m1;
retval.point = { x: x, y: y };
retval.entering = m1 > m2 == (l1p1 == l1.p1) == (l2p1 == l2.p1);
retval.exiting = !retval.entering;
// Calculate ties
if(l1.p1.x == x) {
ties.l1 = 'start';
retval.ties = ties;
} else if(l1.p2.x == x) {
ties.l1 = 'end';
retval.ties = ties;
}
if(l2.p1.x == x) {
ties.l2 = 'start';
retval.ties = ties;
} else if(l2.p2.x == x) {
ties.l2 = 'end';
retval.ties = ties;
}
return retval;
}
return false;
};
var _checkInsideRegion = function(label, point) {
if(!_polygonRegistered(label)) return false;
return _checkInside(regionMap[label].points, point || $ax.mouseLocation);
};
_geometry.checkInsideRegion = _checkInsideRegion;
// Returns true if point is inside the polygon, including ties
var _checkInside = function(polygon, point) {
// Make horizontal line wider than the polygon, with the y of point to test location
var firstX = polygon[0].x;
var secondX = firstX;
var i;
for(i = 1; i < polygon.length; i++) {
var polyX = polygon[i].x;
firstX = Math.min(firstX, polyX);
secondX = Math.max(secondX, polyX);
}
var line = {
p1: _genPoint(--firstX, point.y),
p2: _genPoint(++secondX, point.y)
};
// If entered true, with closest intersection says you are inside the polygon.
var entered = false;
// Closest is the closest intersection to the left of the point
var closest = line.p1.x;
// This is for if intersections hit the same point, to find out which is correct
var cos = -2;
var getCos = function(line) {
var x = line.p2.x - line.p1.x;
var y = line.p2.y - line.p1.y;
return x / Math.sqrt(x * x + y * y);
};
for(i = 0; i < polygon.length; i++) {
var polyLine = { p1: polygon[i], p2: polygon[(i + 1) % polygon.length] };
var intersectInfo = linesIntersect(line, polyLine);
if(!intersectInfo) continue;
if(intersectInfo.parallel) {
// Only really care about this if it actually touches the point
if(intersectInfo.parallel.first.x <= point.x && intersectInfo.parallel.second.x >= point.x) return true;
continue;
}
var intersectionX = intersectInfo.point.x;
if(intersectionX > point.x || intersectionX < closest) continue;
if(intersectionX == point.x) return true;
// If closer than last time, reset cosine.
if(intersectionX != closest) cos = -2;
// For getting cosine, need to possibly reverse the direction of polyLine.
if(intersectInfo.ties) {
// Tie must be on l2, if the ties is end, reverse so cosine indicates how close the angle is to that of 'point' from here.
if(intersectInfo.ties.l2 == 'end') polyLine = { p1: polyLine.p2, p2: polyLine.p1 };
} else {
// It is on both side, so you can take the larger one
if(polyLine.p1.x > polyLine.p2.x) polyLine = { p1: polyLine.p2, p2: polyLine.p1 };
}
var currCos = getCos(polyLine);
if(currCos > cos) {
cos = currCos;
closest = intersectionX;
entered = intersectInfo.entering;
}
}
return entered;
};
_geometry.checkInside = _checkInside;
});

7
web/main/static/resources/scripts/axure/globals.js

@ -1,7 +0,0 @@
$axure.internal(function($ax) {
var _globals = $ax.globals = {};
$ax.globals.MaxZIndex = 1000;
$ax.globals.MinZIndex = -1000;
});

344
web/main/static/resources/scripts/axure/ie.js

@ -1,344 +0,0 @@

//// ******* Internet Explorer MANAGER ******** //
////this is to handle all the stupid IE Stuff
//$axure.internal(function($ax) {
// if(!IE_10_AND_BELOW) return;
// var _ieColorManager = {};
// if(Number(BROWSER_VERSION) < 9) $ax.ieColorManager = _ieColorManager;
// var _applyIEFixedPosition = function() {
// if(Number(BROWSER_VERSION) >= 7) return;
// $axure(function(diagramObject) { return diagramObject.fixedVertical; }).$()
// .appendTo($('body'))
// .css('position', 'absolute').css('margin-left', 0 + 'px').css('margin-top', 0 + 'px');
// var handleScroll = function() {
// $axure(function(diagramObject) { return diagramObject.fixedVertical; })
// .each(function(diagramObject, elementId) {
// var win = $(window);
// var windowWidth = win.width();
// var windowHeight = win.height();
// var windowScrollLeft = win.scrollLeft();
// var windowScrollTop = win.scrollTop();
// var newLeft = 0;
// var newTop = 0;
// var elementQuery = $('#' + elementId);
// var elementAxQuery = $ax('#' + elementId);
// var width = elementAxQuery.width();
// var height = elementAxQuery.height();
// var horz = diagramObject.fixedHorizontal;
// if(horz == 'left') {
// newLeft = windowScrollLeft + diagramObject.fixedMarginHorizontal;
// } else if(horz == 'center') {
// newLeft = windowScrollLeft + ((windowWidth - width) / 2) + diagramObject.fixedMarginHorizontal;
// } else if(horz == 'right') {
// newLeft = windowScrollLeft + windowWidth - width - diagramObject.fixedMarginHorizontal;
// }
// var vert = diagramObject.fixedVertical;
// if(vert == 'top') {
// newTop = windowScrollTop + diagramObject.fixedMarginVertical;
// } else if(vert == 'middle') {
// newTop = windowScrollTop + ((windowHeight - height) / 2) + diagramObject.fixedMarginVertical;
// } else if(vert == 'bottom') {
// newTop = windowScrollTop + windowHeight - height - diagramObject.fixedMarginVertical;
// }
// elementQuery.css('top', newTop + 'px').css('left', newLeft + 'px');
// });
// };
// $(window).scroll(handleScroll);
// $axure.resize(handleScroll);
// handleScroll();
// };
// var _applyBackground = function() {
// if(Number(BROWSER_VERSION) >= 9) return;
// var styleChain = $ax.adaptive.getAdaptiveIdChain($ax.adaptive.currentViewId);
// var argb = _getArgb($ax.pageData.page, styleChain);
// var hexColor = _getHexColor(argb, false);
// if(hexColor) $('body').css('background-color', hexColor);
// _applyBackgroundToQuery($ax('*'));
// };
// var _applyBackgroundToQuery = function(query) {
// if(Number(BROWSER_VERSION) >= 9) return;
// var styleChain = $ax.adaptive.getAdaptiveIdChain($ax.adaptive.currentViewId);
// query.each(function(obj, elementId) {
// if ($ax.public.fn.IsDynamicPanel(obj.type)) {
// var stateCount = obj.diagrams.length;
// for(var j = 0; j < stateCount; j++) {
// var stateId = $ax.repeater.applySuffixToElementId(elementId, '_state' + j);
// var argb = _getArgb(obj.diagrams[j], styleChain);
// var hexColor = _getHexColor(argb, true);
// if(hexColor) $jobj(stateId).css('background-color', hexColor);
// }
// } else if ($ax.public.fn.IsRepeater(obj.type)) {
// }
// });
// };
// _ieColorManager.applyBackground = _applyBackgroundToQuery;
// var _getArgb = function(diagram, styleChain) {
// var argb = undefined;
// for(var i = 0; i < styleChain.length && !argb; i++) {
// var style = diagram.adaptiveStyles[styleChain[i]];
// argb = style.fill && style.fill.color;
// }
// if(!argb) argb = diagram.style.fill.color;
// return argb;
// };
// var gMult = 256;
// var rMult = gMult * 256;
// var aMult = rMult * 256;
// var _getHexColor = function(argb, allowWhite) {
// var a = Math.floor(argb / aMult);
// argb -= a * aMult;
// var r = Math.floor(argb / rMult);
// argb -= r * rMult;
// var g = Math.floor(argb / gMult);
// var b = argb - g * gMult;
// return _getColorFromArgb(a, r, g, b, allowWhite);
// };
// var _getColorFromArgb = function(a, r, g, b, allowWhite) {
// if(Number(BROWSER_VERSION) >= 9) return undefined;
// //convert the color with alpha to a color with no alpha (assuming white background)
// r = Math.min((r * a) / 255 + 255 - a, 255);
// g = Math.min((g * a) / 255 + 255 - a, 255);
// b = Math.min((b * a) / 255 + 255 - a, 255);
// if(a == 0) return undefined;
// if(!allowWhite && (r == 255 && g == 255 && b == 255)) return undefined;
// var color = '#';
// color += Math.floor(r / 16).toString(16);
// color += Math.floor(r % 16).toString(16);
// color += Math.floor(g / 16).toString(16);
// color += Math.floor(g % 16).toString(16);
// color += Math.floor(b / 16).toString(16);
// color += Math.floor(b % 16).toString(16);
// return color;
// };
// _ieColorManager.getColorFromArgb = _getColorFromArgb;
// var getIEOffset = function(transform, rect) {
// var translatedVertexes = [
// $axure.utils.Vector2D(0, 0), //we dont translate, so the orgin is fixed
// transform.mul($axure.utils.Vector2D(0, rect.height)),
// transform.mul($axure.utils.Vector2D(rect.width, 0)),
// transform.mul($axure.utils.Vector2D(rect.width, rect.height))];
// var minX = 0, minY = 0, maxX = 0, maxY = 0;
// $.each(translatedVertexes, function(index, p) {
// minX = Math.min(minX, p.x);
// minY = Math.min(minY, p.y);
// maxX = Math.max(maxX, p.x);
// maxY = Math.max(maxY, p.y);
// });
// return $axure.utils.Vector2D(
// (maxX - minX - rect.width) / 2,
// (maxY - minY - rect.height) / 2);
// };
// var _filterFromTransform = function(transform) {
// return "progid:DXImageTransform.Microsoft.Matrix(M11=" + transform.m11 +
// ", M12=" + transform.m12 + ", M21=" + transform.m21 +
// ", M22=" + transform.m22 + ", SizingMethod='auto expand')";
// };
// var _applyIERotation = function() {
// if(Number(BROWSER_VERSION) >= 9) return;
// $axure(function(diagramObject) {
// return ((diagramObject.style.rotation && Math.abs(diagramObject.style.rotation) > 0.1)
// || (diagramObject.style.textRotation && Math.abs(diagramObject.style.textRotation) > 0.1))
// && !diagramObject.isContained;
// }).each(function(diagramObject, elementId) {
// var rotation = diagramObject.style.rotation || 0;
// var $element = $('#' + elementId);
// var axElement = $ax('#' + elementId);
// var width = axElement.width();
// var height = axElement.height();
// var originX = width / 2;
// var originY = height / 2;
// var shapeIeOffset;
// $element.children().each(function() {
// var $child = $(this);
// var axChild = $ax('#' + $child.attr('id'));
// var childWidth = axChild.width();
// var childHeight = axChild.height() + $child.position().top;
// var centerX = $child.position().left + (childWidth / 2);
// var centerY = $child.position().top + (childHeight / 2);
// var deltaX = centerX - originX;
// var deltaY = centerY - originY;
// var effectiveRotation = rotation;
// var textObject = $ax.getObjectFromElementId($child.attr('id'));
// if(textObject) {
// if(textObject.style.textRotation) effectiveRotation = textObject.style.textRotation;
// else return;
// }
// var transform = $ax.utils.Matrix2D.identity().rotate(effectiveRotation);
// var filter = _filterFromTransform(transform);
// $child.css('filter', filter)
// .width(childWidth + 1)
// .height(childHeight + 1);
// var p = transform.mul($ax.utils.Vector2D(deltaX, deltaY));
// var ieOffset = getIEOffset(transform, { width: childWidth, height: childHeight });
// if(!textObject) {
// shapeIeOffset = ieOffset;
// } else {
// // This is a close approximation, but not exact
// if(diagramObject.style.verticalAlignment != 'top') ieOffset.y -= shapeIeOffset.y + Math.abs(shapeIeOffset.x);
// }
// $child.css("margin-left", -ieOffset.x - deltaX + p.x).css("margin-top", -ieOffset.y - deltaY + p.y);
// });
// });
// };
// var _fixIEStretchBackground = function() {
// if(Number(BROWSER_VERSION) >= 9) return;
// var pageStyle = $ax.adaptive.getPageStyle();
// if(!pageStyle.imageRepeat || pageStyle.imageRepeat == 'auto') return;
// $('body').css('background-image', 'none');
// var viewId = $ax.adaptive.currentViewId;
// var imageInfo = viewId ? $ax.pageData.viewIdToBackgroundImageInfo && $ax.pageData.viewIdToBackgroundImageInfo[viewId] : $ax.pageData.defaultBackgroundImageInfo;
// if(imageInfo && imageInfo.path) {
// if($('#bg_img').length == 0) $('body').append('<img id="bg_img"/>');
// $('#bg_img').attr('src', imageInfo.path).css('position', 'fixed').css('z-index', '-10000');
// _resizeIEBackground();
// } else $('#bg_img').remove();
// };
// var _resizeIEBackground = function() {
// if(Number(BROWSER_VERSION) >= 9) return;
// //var page = $ax.pageData.page;
// var viewId = $ax.adaptive.currentViewId;
// var pageStyle = $ax.adaptive.getPageStyle();
// if(!$ax.pageData.defaultBackgroundImageInfo && !$ax.pageData.viewIdToBackgroundImageInfo) return;
// var imageInfo = viewId ? $ax.pageData.viewIdToBackgroundImageInfo[viewId] : $ax.pageData.defaultBackgroundImageInfo;
// if(!imageInfo) return;
// var imageWidth = imageInfo.width;
// var imageHeight = imageInfo.height;
// var windowWidth = $(window).width();
// var windowHeight = $(window).height();
// var isCover = pageStyle.imageRepeat == 'cover';
// var wRatio = windowWidth / imageWidth;
// var hRatio = windowHeight / imageHeight;
// var ratio = wRatio;
// if(isCover) {
// if(hRatio > wRatio) ratio = hRatio;
// } else {
// if(hRatio < wRatio) ratio = hRatio;
// }
// var width = imageWidth * ratio;
// var height = imageHeight * ratio;
// var left = '0px';
// if((isCover && width > windowWidth) || (!isCover && width < windowWidth)) {
// if(pageStyle.imageHorizontalAlignment == 'center') {
// left = ((windowWidth - width) / 2) + 'px';
// } else if(pageStyle.imageHorizontalAlignment == 'far') {
// left = (windowWidth - width) + 'px';
// }
// }
// var top = '0px';
// if((isCover && height > windowHeight) || (!isCover && height < windowHeight)) {
// if(pageStyle.imageVerticalAlignment == 'center') {
// top = ((windowHeight - height) / 2) + 'px';
// } else if(pageStyle.imageVerticalAlignment == 'far') {
// top = (windowHeight - height) + 'px';
// }
// }
// $('#bg_img').css('top', top).css('left', left).css('width', width).css('height', height);
// };
// var _fixAllPngs = function() {
// if(!(/MSIE ((5\.5)|6)/.test(window.navigator.userAgent) && window.navigator.platform == "Win32")) return;
// $('img[src$=".png"]').each(function() {
// if(!this.complete) {
// this.onload = function() { $axure.utils.fixPng(this); };
// } else {
// $axure.utils.fixPng(this);
// }
// });
// };
// var _fixInputSize = function() {
// if(Number(BROWSER_VERSION) >= 8 || window.navigator.userAgent.indexOf("Trident/4.0") > -1) return;
// var inputs = $('input').not(':input[type=button], :input[type=submit], :input[type=radio], :input[type=checkbox]');
// inputs.each(function() {
// var $input = $(this);
// var axInput = $ax('#' + $input.attr('id'));
// $input.css('height', (axInput.height() - 4 + 'px')).css('width', (axInput.width() - 2 + 'px'));
// });
// var textAreas = $($ax.constants.TEXT_AREA_TYPE);
// textAreas.each(function() {
// var $textArea = $(this);
// var axText = $ax('#' + $textArea.attr('id'));
// $textArea.css('height', (axText.height() - 6 + 'px')).css('width', (axText.width() - 6 + 'px'));
// });
// };
// var _fixInputBackground = function() {
// var inputs = $('input').not(':input[type=button], :input[type=submit], :input[type=radio], :input[type=checkbox]');
// inputs = inputs.add($($ax.constants.TEXT_AREA_TYPE));
// inputs.each(function() {
// var $input = $(this);
// if($input.css('background-color') == 'transparent') {
// $input.css('background-image', 'url(../../transparent.gif)');
// } else {
// $input.css('background-image', '');
// }
// });
// };
// $(document).ready(function() {
// _fixIEStretchBackground();
// _applyIEFixedPosition();
// $axure.resize(function() {
// _resizeIEBackground();
// });
// $ax.adaptive.bind('viewChanged', function() {
// _fixIEStretchBackground();
// _applyBackground();
// _fixInputBackground();
// });
// _fixAllPngs();
// _applyIERotation();
// _applyBackground();
// _fixInputSize();
// _fixInputBackground();
// });
//});

326
web/main/static/resources/scripts/axure/init.temp.js

@ -1,326 +0,0 @@
$axure.internal(function($ax) {
$(window.document).ready(function () {
//var readyStart = (new Date()).getTime();
//this is because the page id is not formatted as a guid
var pageId = $ax.pageData.page.packageId;
var pageData = {
id: pageId,
pageName: $ax.pageData.page.name,
location: window.location.toString(),
notes: $ax.pageData.page.notes,
widgetNotes: $ax.pageData.page.annotations,
//clipToView: $ax.pageData.clipToView,
defaultAdaptiveView: $ax.pageData.defaultAdaptiveView,
adaptiveViews: $ax.pageData.adaptiveViews,
masterNotes: []
};
var fnPrefix = '';
function pushNextPrefix() {
if (fnPrefix.length == 0) fnPrefix = 'A';
else fnPrefix = fnPrefix[0] == 'Z' ? 'A'.repeat(fnPrefix.length + 1) : String.fromCharCode(fnPrefix.charCodeAt(0) + 1).repeat(fnPrefix.length);
}
function populateNotes(pageForNotes) {
for (var master in pageForNotes.masters) {
//var master = pageForNotes.masters[i];
var masterData = pageForNotes.masters[master];
var hasWidgetNotes = masterData.annotations && masterData.annotations.length > 0;
if ((master.notes && !$.isEmptyObject(masterData.notes)) || hasWidgetNotes) {
if(hasWidgetNotes) pushNextPrefix();
var m = {};
m.pageName = masterData.name;
m.notes = masterData.notes;
m.widgetNotes = masterData.annotations;
pageData.masterNotes.push(m);
if(hasWidgetNotes) populateOwnerToFn(m.widgetNotes);
}
populateNotes(master);
}
}
var ownerToFns = {};
function populateOwnerToFn(widgetNotes) {
if(typeof widgetNotes == 'undefined') return false;
for (var i = 0; i < widgetNotes.length; i++) {
var widgetNote = widgetNotes[i];
widgetNote['fn'] = fnPrefix + widgetNote['fn'];
var fn = widgetNote['fn'];
var ownerId = widgetNote['ownerId'];
if (ownerId !== undefined && ownerId.length > 0) {
var ownerLabels = ownerToFns[ownerId];
if (ownerLabels == undefined) ownerLabels = [];
ownerLabels.push(fn);
ownerToFns[ownerId] = ownerLabels;
}
}
}
populateOwnerToFn(pageData.widgetNotes);
populateNotes($ax.pageData);
pageData.ownerToFns = ownerToFns;
$ax.pageData.notesData = pageData;
//var anns = [];
//$ax('*').each(function (dObj, elementId) {
// pushAnnotation(dObj, elementId);
//});
//function pushAnnotation(dObj, elementId) {
// var ann = dObj.annotation;
// if(ann) {
// ann = $ax.deepCopy(ann);
// ann["id"] = elementId;
// ann["label"] = dObj.label + " (" + dObj.friendlyType + ")";
// anns.push(ann);
// }
// if(dObj.type === 'repeater' && dObj.objects) {
// //if it's repeater, save the id as repeaterId@scriptId
// for(var i = 0, len = dObj.objects.length; i < len; i++) {
// var child = dObj.objects[i];
// var scriptId = $ax.getScriptIdFromPath([child.id], elementId);
// pushAnnotation(child, elementId + '@' + scriptId);
// }
// }
//}
//pageData.widgetNotes = anns;
//only trigger the page.data setting if the window is on the mainframe
var isMainFrame = false;
try {
if(window.name == 'mainFrame' ||
(!CHROME_5_LOCAL && window.parent.$ && window.parent.$('#mainFrame').length > 0)) {
isMainFrame = true;
$ax.messageCenter.addMessageListener(function(message, data) {
if(message == 'finishInit') {
_processTempInit();
}
});
$axure.messageCenter.setState('page.data', pageData);
window.focus();
}
} catch(e) { }
//attach here for chrome local
//$(window).on('load', function() {
// $ax.style.initializeObjectTextAlignment($ax('*'));
//});
if(!isMainFrame) _processTempInit();
});
var touchCount = 0;
var lastTouch = Date.now();
var _registerTouchCount = $ax.registerTouchCount = function (e) {
var now = Date.now();
if (now - lastTouch < 375) {
if (++touchCount === 3) {
$(':input').blur();
$ax.messageCenter.postMessage('tripleClick', true);
e.preventDefault();
};
} else {
touchCount = 1;
}
lastTouch = now;
};
// Block IOS stalling second tap.
// Stop third click from also clicking mobile card
var _clearTouchCount = $ax.clearTouchCount = function (e) {
if (touchCount === 3) {
touchCount = 0;
e.preventDefault();
}
};
var _processTempInit = function() {
//var start = (new Date()).getTime();
//var end = (new Date()).getTime();
//window.alert('elapsed ' + (end - start));
$('iframe').each(function() {
var origSrc = $(this).attr('basesrc');
var $this = $(this);
if(origSrc) {
var newSrcUrl = origSrc.toLowerCase().indexOf('http://') == -1 ? $ax.globalVariableProvider.getLinkUrl(origSrc) : origSrc;
$this.attr('src', newSrcUrl);
}
if(IOS) {
$this.parent().css('overflow', 'auto').css('-webkit-overflow-scrolling', 'touch').css('-ms-overflow-x', 'hidden').css('overflow-x', 'hidden');
}
});
$axure.messageCenter.addMessageListener(function(message, data) {
if(message == 'setGlobalVar') {
$ax.globalVariableProvider.setVariableValue(data.globalVarName, data.globalVarValue, true);
}
});
window.lastFocusedClickable = null;
var _lastFocusedClickableSelector = 'input, a';
var shouldOutline = true;
$ax(function (dObj) { return dObj.tabbable; }).each(function (dObj, elementId) {
if ($ax.public.fn.IsLayer(dObj.type)) $ax.event.layerMapFocus(dObj, elementId);
var focusableId = $ax.event.getFocusableWidgetOrChildId(elementId);
var $focusable = $('#' + focusableId);
$focusable.attr("tabIndex", 0);
if($focusable.is('div') || $focusable.is('img')) {
$focusable.bind($ax.features.eventNames.mouseDownName, function() {
shouldOutline = false;
});
attachFocusAndBlur($focusable);
}
});
$(window.document).bind($ax.features.eventNames.mouseUpName, function() {
shouldOutline = true;
});
attachFocusAndBlur($(_lastFocusedClickableSelector));
function attachFocusAndBlur($query) {
$query.focus(function () {
if(shouldOutline) {
$(this).css('outline', '');
} else {
$(this).css('outline', 'none');
}
window.lastFocusedClickable = this;
}).blur(function () {
if(window.lastFocusedClickable == this) window.lastFocusedClickable = null;
});
}
$(window.document).bind('keyup', function (e) {
switch(e.which) {
case 13:
case 32:
if(window.lastFocusedClickable) $(window.lastFocusedClickable).click();
break;
default: return; // exit this handler for other keys
}
});
//if($ax.document.configuration.hideAddress) {
// $(window).on('load', function() {
// window.setTimeout(function() {
// window.scrollTo(0, 0.9);
// }, 0);
// });
//}
//if($ax.document.configuration.preventScroll) {
// $(window.document).bind('touchmove', function(e) {
// var inScrollable = $ax.legacy.GetScrollable(e.target) != window.document.body;
// if(!inScrollable) {
// e.preventDefault();
// }
// });
// $ax(function(diagramObject) {
// return $ax.public.fn.IsDynamicPanel(diagramObject.type) && diagramObject.scrollbars != 'none';
// }).$().children().bind('touchstart', function() {
// var target = this;
// var top = target.scrollTop;
// if(top <= 0) target.scrollTop = 1;
// if(top + target.offsetHeight >= target.scrollHeight) target.scrollTop = target.scrollHeight - target.offsetHeight - 1;
// });
//}
if(OS_MAC && WEBKIT) {
$ax(function(diagramObject) {
return $ax.public.fn.IsComboBox(diagramObject.type);
}).each(function(obj, id) {
$jobj($ax.INPUT(id)).css('-webkit-appearance', 'menulist-button');
});
}
if($ax.features.supports.mobile) {
$('html').first().on('touchstart', _registerTouchCount);
$('html').first().on('touchend', _clearTouchCount);
// Stop pinch zoom (stopping all gestures for now)
// Gesturestart is only supported in Safari
if (SAFARI) {
document.addEventListener("gesturestart", function (e) {
e.preventDefault();
});
}
}
$ax.annotation.initialize();
$ax.legacy.BringFixedToFront();
$ax.event.initialize();
$ax.style.initialize();
$ax.visibility.initialize();
$ax.repeater.initialize();
$ax.dynamicPanelManager.initialize(); //needs to be called after visibility is initialized
$ax.adaptive.initialize();
$ax.loadDynamicPanelsAndMasters();
$ax.adaptive.loadFinished();
var start = (new Date()).getTime();
$ax.repeater.initRefresh();
var end = (new Date()).getTime();
console.log('loadTime: ' + (end - start) / 1000);
$ax.style.prefetch();
$(window).resize();
//var readyEnd = (new Date()).getTime();
//window.alert('elapsed ' + (readyEnd - readyStart));
};
});
/* extend canvas */
var gv_hasCanvas = false;
(function() {
var _canvas = document.createElement('canvas'), proto, abbrev;
if(gv_hasCanvas = !!(_canvas.getContext && _canvas.getContext('2d')) && typeof (CanvasGradient) !== 'undefined') {
function chain(func) {
return function() {
return func.apply(this, arguments) || this;
};
}
with(proto = CanvasRenderingContext2D.prototype) for(var func in abbrev = {
a: arc,
b: beginPath,
n: clearRect,
c: clip,
p: closePath,
g: createLinearGradient,
f: fill,
j: fillRect,
z: function(s) { this.fillStyle = s; },
l: lineTo,
w: function(w) { this.lineWidth = w; },
m: moveTo,
q: quadraticCurveTo,
h: rect,
r: restore,
o: rotate,
s: save,
x: scale,
y: function(s) { this.strokeStyle = s; },
u: setTransform,
k: stroke,
i: strokeRect,
t: translate
}) proto[func] = chain(abbrev[func]);
CanvasGradient.prototype.a = chain(CanvasGradient.prototype.addColorStop);
}
})();

91
web/main/static/resources/scripts/axure/ios.js

@ -1,91 +0,0 @@
$axure.internal(function ($ax) {
if ((IOS && SAFARI) || SHARE_APP) {
var outerHtml = document.documentElement;
outerHtml.id = 'ios-safari';
var html = document.createElement('html');
html.id = 'ios-safari-html';
outerHtml.appendChild(html);
var body = document.body;
html.appendChild(body);
Object.defineProperty(document, 'body', {
get: function () {
return body;
}
});
var fixedBody = document.createElement('body');
fixedBody.id = 'ios-safari-fixed';
outerHtml.appendChild(fixedBody);
var fixedBase = document.createElement('div');
fixedBase.id = 'base-fixed';
fixedBody.appendChild(fixedBase);
var isDevice = false;
var deviceWidth = 0;
var updateHtmlWidth = function (panelWidthOffset, scale, height, scaleN) {
var iosSafHtml = $('#ios-safari-html');
iosSafHtml.css('overflow', '');
iosSafHtml.css('overflow-x', '');
iosSafHtml.css('height', '');
if (isDevice) {
iosSafHtml.width(deviceWidth / scaleN);
iosSafHtml.css('overflow-x', 'hidden');
} else {
var isLandscape = window.orientation != 0 && window.orientation != 180;
var mobileWidth = isLandscape ? window.screen.height : window.screen.width
iosSafHtml.width((mobileWidth - panelWidthOffset) / scaleN);
}
if (scale == 1) {
iosSafHtml.css('overflow-x', 'hidden');
iosSafHtml.css('height', (height / scaleN) + 'px');
} else if (scale == 2) iosSafHtml.css('overflow', 'hidden');
};
updateHtmlWidth(0);
$axure('*').each(function (obj, element) {
if (obj && obj.fixedVertical && obj.fixedKeepInFront) {
var parent = $axure('#' + element).getParents(false, ['item', 'state'])[0];
if (!parent) {
$('#base-fixed').append($('#' + element));
}
}
});
$axure.messageCenter.addMessageListener(function (message, data) {
if (message == "setContentScale") {
updateHtmlWidth(data.panelWidthOffset, data.scale, data.viewportHeight, data.scaleN);
} else if (message == "setDeviceMode") {
isDevice = data.device && !data.scaleToWidth;
if (isDevice) deviceWidth = data.width;
updateHtmlWidth(0);
}
});
$('#ios-safari-html').scroll(function () {
$axure.updateWindowInfo();
});
var scrollStartY;
var maxScrollY
var touchStart;
$axure('*').each(function (obj, element) {
if (obj && obj.scrollbars && obj.scrollbars.toLowerCase() != 'none') {
if (obj.scrollbars == 'horizontalAsNeeded') return;
$('#' + element).on('touchstart', function (e) {
touchStart = e.pageY;
var stateId = $ax.visibility.GetPanelState($('#' + element).attr('id'));
scrollStartY = $('#' + stateId).scrollTop();
maxScrollY = $('#' + stateId)[0].scrollHeight - $('#' + stateId).height();
});
$('#' + element).on('touchmove', function (e) {
if (maxScrollY <= 0) return false;
if (scrollStartY == 0 && e.pageY > touchStart) e.preventDefault();
if (scrollStartY == maxScrollY && e.pageY < touchStart) e.preventDefault();
});
}
});
}
});

1
web/main/static/resources/scripts/axure/jquery.nicescroll.min.js

File diff suppressed because one or more lines are too long

166
web/main/static/resources/scripts/axure/legacy.js

@ -1,166 +0,0 @@
//stored on each browser event
var windowEvent;
$axure.internal(function($ax) {
var _legacy = {};
$ax.legacy = _legacy;
var Forms = window.document.getElementsByTagName("FORM");
for(var i = 0; i < Forms.length; i++) {
var Form = Forms[i];
Form.onclick = $ax.legacy.SuppressBubble;
}
$ax.legacy.SuppressBubble = function(event) {
if(IE_10_AND_BELOW) {
window.event.cancelBubble = true;
window.event.returnValue = false;
} else {
if(event) {
event.stopPropagation();
}
}
};
$ax.legacy.BringToFront = function(id, skipFixed) {
_bringToFrontHelper(id);
if(!skipFixed) $ax.legacy.BringFixedToFront();
};
var _bringToFrontHelper = function(id) {
var target = window.document.getElementById(id);
if(target == null) return;
$ax.globals.MaxZIndex = $ax.globals.MaxZIndex + 1;
target.style.zIndex = $ax.globals.MaxZIndex;
};
$ax.legacy.BringFixedToFront = function() {
$ax(function(diagramObject) { return diagramObject.fixedKeepInFront; }).each(function(diagramObject, scriptId) {
_bringToFrontHelper(scriptId);
});
};
$ax.legacy.SendToBack = function(id) {
var target = window.document.getElementById(id);
if(target == null) return;
target.style.zIndex = $ax.globals.MinZIndex = $ax.globals.MinZIndex - 1;
};
$ax.legacy.RefreshScreen = function() {
var oldColor = window.document.body.style.backgroundColor;
var setColor = (oldColor == "rgb(0,0,0)") ? "#FFFFFF" : "#000000";
window.document.body.style.backgroundColor = setColor;
window.document.body.style.backgroundColor = oldColor;
};
$ax.legacy.getAbsoluteLeft = function(currentNode, elementId) {
var oldDisplay = currentNode.css('display');
var displaySet = false;
if(oldDisplay == 'none') {
currentNode.css('display', '');
displaySet = true;
}
var left = currentNode.offset().left;
// Special Layer code
if($ax.getTypeFromElementId(elementId) == 'layer') {
var first = true;
var children = currentNode.children();
for(var i = 0; i < children.length; i++) {
var child = $(children[i]);
var subDisplaySet = false;
if(child.css('display') == 'none') {
child.css('display', '');
subDisplaySet = true;
}
if(first) left = child.offset().left;
else left = Math.min(child.offset().left, left);
first = false;
if(subDisplaySet) child.css('display', 'none');
}
}
if (displaySet) currentNode.css('display', oldDisplay);
return $axure.fn.bodyToWorld(left, true);
};
$ax.legacy.getAbsoluteTop = function(currentNode, elementId) {
var oldDisplay = currentNode.css('display');
var displaySet = false;
if(oldDisplay == 'none') {
currentNode.css('display', '');
displaySet = true;
}
var top = currentNode.offset().top;
// Special Layer code
if ($ax.getTypeFromElementId(elementId) == 'layer') {
var first = true;
var children = currentNode.children();
for (var i = 0; i < children.length; i++) {
var child = $(children[i]);
var subDisplaySet = false;
if (child.css('display') == 'none') {
child.css('display', '');
subDisplaySet = true;
}
if (first) top = child.offset().top;
else top = Math.min(child.offset().top, top);
first = false;
if (subDisplaySet) child.css('display', 'none');
}
}
if(displaySet) currentNode.css('display', oldDisplay);
return top;
};
// ****************** Annotation and Link Functions ****************** //
$ax.legacy.GetAnnotationHtml = function(annJson) {
var retVal = "";
for(var noteName in annJson) {
if(noteName != "label" && noteName != "id") {
retVal += "<div class='annotationName'>" + noteName + "</div>";
retVal += "<div class='annotationValue'>" + linkify(annJson[noteName]) + "</div>";
}
}
return retVal;
function linkify(text) {
var urlRegex = /(\b(((https?|ftp|file):\/\/)|(www\.))[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;
return text.replace(urlRegex, function (url, b, c) {
var url2 = (c == 'www.') ? 'http://' + url : url;
return '<a href="' + url2 + '" target="_blank" class="noteLink">' + url + '</a>';
});
}
};
$ax.legacy.GetScrollable = function(target) {
var $target = $(target);
var last = $target;
// Start past inital target. Can't scroll to target in itself, must be some ancestor.
var current = last.parent();
while(!current.is('body') && !current.is('html')) {
var elementId = current.attr('id');
var diagramObject = elementId && $ax.getObjectFromElementId(elementId);
if (diagramObject && $ax.public.fn.IsDynamicPanel(diagramObject.type) && diagramObject.scrollbars != 'none') {
//returns the panel diagram div which handles scrolling
return $ax.dynamicPanelManager.getShownState(current.attr('id'))[0];
}
last = current;
current = current.parent();
}
// Need to do this because of ie
if(IE_10_AND_BELOW) return window.document.documentElement;
else return window.document.body;
};
});

554
web/main/static/resources/scripts/axure/math.js

@ -1,554 +0,0 @@
$axure.internal(function($ax) {
$ax.public.fn.matrixMultiply = function(matrix, vector) {
if(!matrix.tx) matrix.tx = 0;
if(!matrix.ty) matrix.ty = 0;
var outX = matrix.m11 * vector.x + matrix.m12 * vector.y + matrix.tx;
var outY = matrix.m21 * vector.x + matrix.m22 * vector.y + matrix.ty;
return { x: outX, y: outY };
}
$ax.public.fn.matrixInverse = function(matrix) {
if(!matrix.tx) matrix.tx = 0;
if(!matrix.ty) matrix.ty = 0;
var determinant = matrix.m11*matrix.m22 - matrix.m12*matrix.m21;
//var threshold = (M11 * M11 + M22 *M22 + M12 *M12+ M21 *M21) / 100000;
//if(determinant.DeltaEquals(0, threshold) && determinant < 0.01) {
// return Invalid;
//}
return {
m11 : matrix.m22/determinant,
m12 : -matrix.m12/determinant,
tx : (matrix.ty*matrix.m12 - matrix.tx*matrix.m22)/determinant,
m21: -matrix.m21 / determinant,
m22: matrix.m11 / determinant,
ty: (matrix.tx * matrix.m21 - matrix.ty * matrix.m11) / determinant
};
}
$ax.public.fn.matrixMultiplyMatrix = function (matrix1, matrix2) {
if (!matrix1.tx) matrix1.tx = 0;
if (!matrix1.ty) matrix1.ty = 0;
if (!matrix2.tx) matrix2.tx = 0;
if (!matrix2.ty) matrix2.ty = 0;
return {
m11: matrix1.m12*matrix2.m21 + matrix1.m11*matrix2.m11,
m12: matrix1.m12*matrix2.m22 + matrix1.m11*matrix2.m12,
tx: matrix1.m12 * matrix2.ty + matrix1.m11 * matrix2.tx + matrix1.tx,
m21: matrix1.m22 * matrix2.m21 + matrix1.m21 * matrix2.m11,
m22: matrix1.m22 * matrix2.m22 + matrix1.m21 * matrix2.m12,
ty: matrix1.m22 * matrix2.ty + matrix1.m21 * matrix2.tx + matrix1.ty,
};
}
$ax.public.fn.transformFromElement = function (element) {
var st = window.getComputedStyle(element, null);
var tr = st.getPropertyValue("-webkit-transform") ||
st.getPropertyValue("-moz-transform") ||
st.getPropertyValue("-ms-transform") ||
st.getPropertyValue("-o-transform") ||
st.getPropertyValue("transform");
if (tr.indexOf('none') < 0) {
var matrix = tr.split('(')[1];
matrix = matrix.split(')')[0];
matrix = matrix.split(',');
for (var l = 0; l < matrix.length; l++) {
matrix[l] = Number(matrix[l]);
}
} else { matrix = [1.0, 0.0, 0.0, 1.0, 0.0, 0.0]; }
return matrix;
// matrix[0] = cosine, matrix[1] = sine.
// Assuming the element is still orthogonal.
}
$ax.public.fn.vectorMinus = function(vector1, vector2) { return { x: vector1.x - vector2.x, y: vector1.y - vector2.y }; }
$ax.public.fn.vectorPlus = function (vector1, vector2) { return { x: vector1.x + vector2.x, y: vector1.y + vector2.y }; }
$ax.public.fn.vectorMidpoint = function (vector1, vector2) { return { x: (vector1.x + vector2.x) / 2.0, y: (vector1.y + vector2.y) / 2.0 }; }
$ax.public.fn.fourCornersToBasis = function (fourCorners) {
return {
widthVector: $ax.public.fn.vectorMinus(fourCorners.widgetTopRight, fourCorners.widgetTopLeft),
heightVector: $ax.public.fn.vectorMinus(fourCorners.widgetBottomLeft, fourCorners.widgetTopLeft)
};
}
$ax.public.fn.matrixString = function(m11, m21, m12, m22, tx, ty) {
return "Matrix(" + m11 + "," + m21 + "," + m12 + "," + m22 + ", " + tx + ", " + ty + ")";
}
//$ax.public.fn.getWidgetBoundingRect = function (widgetId) {
// var emptyRect = { left: 0, top: 0, centerPoint: { x: 0, y: 0 }, width: 0, height: 0 };
// var element = document.getElementById(widgetId);
// if (!element) return emptyRect;
// var object = $obj(widgetId);
// if (object && object.type && $ax.public.fn.IsLayer(object.type)) {
// var layerChildren = _getLayerChildrenDeep(widgetId);
// if (!layerChildren) return emptyRect;
// else return _getBoundingRectForMultipleWidgets(layerChildren);
// }
// return _getBoundingRectForSingleWidget(widgetId);
//};
var _getLayerChildrenDeep = $ax.public.fn.getLayerChildrenDeep = function (layerId, includeLayers, includeHidden) {
var deep = [];
var children = $ax('#' + layerId).getChildren()[0].children;
for (var index = 0; index < children.length; index++) {
var childId = children[index];
if(!includeHidden && !$ax.visibility.IsIdVisible(childId)) continue;
if ($ax.public.fn.IsLayer($obj(childId).type)) {
if (includeLayers) deep.push(childId);
var recursiveChildren = _getLayerChildrenDeep(childId, includeLayers, includeHidden);
for (var j = 0; j < recursiveChildren.length; j++) deep.push(recursiveChildren[j]);
} else deep.push(childId);
}
return deep;
};
//var _getBoundingRectForMultipleWidgets = function (widgetsIdArray, relativeToPage) {
// if (!widgetsIdArray || widgetsIdArray.constructor !== Array) return undefined;
// if (widgetsIdArray.length == 0) return { left: 0, top: 0, centerPoint: { x: 0, y: 0 }, width: 0, height: 0 };
// var widgetRect = _getBoundingRectForSingleWidget(widgetsIdArray[0], relativeToPage, true);
// var boundingRect = { left: widgetRect.left, right: widgetRect.right, top: widgetRect.top, bottom: widgetRect.bottom };
// for (var index = 1; index < widgetsIdArray.length; index++) {
// widgetRect = _getBoundingRectForSingleWidget(widgetsIdArray[index], relativeToPage);
// boundingRect.left = Math.min(boundingRect.left, widgetRect.left);
// boundingRect.top = Math.min(boundingRect.top, widgetRect.top);
// boundingRect.right = Math.max(boundingRect.right, widgetRect.right);
// boundingRect.bottom = Math.max(boundingRect.bottom, widgetRect.bottom);
// }
// boundingRect.centerPoint = { x: (boundingRect.right + boundingRect.left) / 2.0, y: (boundingRect.bottom + boundingRect.top) / 2.0 };
// boundingRect.width = boundingRect.right - boundingRect.left;
// boundingRect.height = boundingRect.bottom - boundingRect.top;
// return boundingRect;
//};
//var _getBoundingRectForSingleWidget = function (widgetId, relativeToPage, justSides) {
// var element = document.getElementById(widgetId);
// var boundingRect, tempBoundingRect, position;
// var displayChanged = _displayHackStart(element);
// if (_isCompoundVectorHtml(element)) {
// //tempBoundingRect = _getCompoundImageBoundingClientSize(widgetId);
// //position = { left: tempBoundingRect.left, top: tempBoundingRect.top };
// position = $(element).position();
// tempBoundingRect = {};
// tempBoundingRect.left = position.left; //= _getCompoundImageBoundingClientSize(widgetId);
// tempBoundingRect.top = position.top;
// tempBoundingRect.width = Number(element.getAttribute('data-width'));
// tempBoundingRect.height = Number(element.getAttribute('data-height'));
// } else {
// var boundingElement = element;
// if($ax.dynamicPanelManager.isIdFitToContent(widgetId)) {
// var stateId = $ax.visibility.GetPanelState(widgetId);
// if(stateId != '') boundingElement = document.getElementById(stateId);
// }
// tempBoundingRect = boundingElement.getBoundingClientRect();
// var jElement = $(element);
// position = jElement.position();
// if(jElement.css('position') == 'fixed') {
// position.left += Number(jElement.css('margin-left').replace("px", ""));
// position.top += Number(jElement.css('margin-top').replace("px", ""));
// }
// }
// var layers = $ax('#' + widgetId).getParents(true, ['layer'])[0];
// var flip = '';
// var mirrorWidth = 0;
// var mirrorHeight = 0;
// for (var i = 0; i < layers.length; i++) {
// //should always be 0,0
// var layerPos = $jobj(layers[i]).position();
// position.left += layerPos.left;
// position.top += layerPos.top;
// var outer = $ax.visibility.applyWidgetContainer(layers[i], true, true);
// if (outer.length) {
// var outerPos = outer.position();
// position.left += outerPos.left;
// position.top += outerPos.top;
// }
// //when a group is flipped we find the unflipped position
// var inner = $jobj(layers[i] + '_container_inner');
// var taggedFlip = inner.data('flip');
// if (inner.length && taggedFlip) {
// //only account for flip if transform is applied
// var matrix = taggedFlip && (inner.css("-webkit-transform") || inner.css("-moz-transform") ||
// inner.css("-ms-transform") || inner.css("-o-transform") || inner.css("transform"));
// if (matrix !== 'none') {
// flip = taggedFlip;
// mirrorWidth = $ax.getNumFromPx(inner.css('width'));
// mirrorHeight = $ax.getNumFromPx(inner.css('height'));
// }
// }
// }
// //Now account for flip
// if (flip == 'x') position.top = mirrorHeight - position.top - element.getBoundingClientRect().height;
// else if (flip == 'y') position.left = mirrorWidth - position.left - element.getBoundingClientRect().width;
// boundingRect = {
// left: position.left,
// right: position.left + tempBoundingRect.width,
// top: position.top,
// bottom: position.top + tempBoundingRect.height
// };
// _displayHackEnd(displayChanged);
// if (justSides) return boundingRect;
// boundingRect.width = boundingRect.right - boundingRect.left;
// boundingRect.height = boundingRect.bottom - boundingRect.top;
// boundingRect.centerPoint = {
// x: boundingRect.width / 2 + boundingRect.left,
// y: boundingRect.height / 2 + boundingRect.top
// };
// return boundingRect;
//};
var _getPointAfterRotate = $ax.public.fn.getPointAfterRotate = function (angleInDegrees, pointToRotate, centerPoint) {
var displacement = $ax.public.fn.vectorMinus(pointToRotate, centerPoint);
var rotationMatrix = $ax.public.fn.rotationMatrix(angleInDegrees);
rotationMatrix.tx = centerPoint.x;
rotationMatrix.ty = centerPoint.y;
return $ax.public.fn.matrixMultiply(rotationMatrix, displacement);
};
$ax.public.fn.getBoundingSizeForRotate = function(width, height, rotation) {
// point to rotate around doesn't matter since we just care about size, if location matter we need more args and location matters.
var origin = { x: 0, y: 0 };
var corner1 = { x: width, y: 0 };
var corner2 = { x: 0, y: height };
var corner3 = { x: width, y: height };
corner1 = _getPointAfterRotate(rotation, corner1, origin);
corner2 = _getPointAfterRotate(rotation, corner2, origin);
corner3 = _getPointAfterRotate(rotation, corner3, origin);
var left = Math.min(0, corner1.x, corner2.x, corner3.x);
var right = Math.max(0, corner1.x, corner2.x, corner3.x);
var top = Math.min(0, corner1.y, corner2.y, corner3.y);
var bottom = Math.max(0, corner1.y, corner2.y, corner3.y);
return { width: right - left, height: bottom - top };
}
$ax.public.fn.getBoundingRectForRotate = function (boundingRect, rotation) {
var centerPoint = boundingRect.centerPoint;
var corner1 = { x: boundingRect.left, y: boundingRect.top };
var corner2 = { x: boundingRect.right, y: boundingRect.top };
var corner3 = { x: boundingRect.right, y: boundingRect.bottom };
var corner4 = { x: boundingRect.left, y: boundingRect.bottom };
corner1 = _getPointAfterRotate(rotation, corner1, centerPoint);
corner2 = _getPointAfterRotate(rotation, corner2, centerPoint);
corner3 = _getPointAfterRotate(rotation, corner3, centerPoint);
corner4 = _getPointAfterRotate(rotation, corner4, centerPoint);
var left = Math.min(corner1.x, corner2.x, corner3.x, corner4.x);
var right = Math.max(corner1.x, corner2.x, corner3.x, corner4.x);
var top = Math.min(corner1.y, corner2.y, corner3.y, corner4.y);
var bottom = Math.max(corner1.y, corner2.y, corner3.y, corner4.y);
return { left: left, top: top, width: right - left, height: bottom - top };
}
//$ax.public.fn.getPositionRelativeToParent = function (elementId) {
// var element = document.getElementById(elementId);
// var list = _displayHackStart(element);
// var position = $(element).position();
// _displayHackEnd(list);
// return position;
//};
//var _displayHackStart = $ax.public.fn.displayHackStart = function (element) {
// // TODO: Options: 1) stop setting display none. Big change for this late in the game. 2) Implement our own bounding.
// // TODO: 3) Current method is look for any parents that are set to none, and and temporarily unblock. Don't like it, but it works.
// var parent = element;
// var displays = [];
// while (parent) {
// if (parent.style.display == 'none') {
// displays.push(parent);
// //use block to overwrites default hidden objects' display
// parent.style.display = 'block';
// }
// parent = parent.parentElement;
// }
// return displays;
//};
//var _displayHackEnd = $ax.public.fn.displayHackEnd = function (displayChangedList) {
// for (var i = 0; i < displayChangedList.length; i++) displayChangedList[i].style.display = 'none';
//};
var _isCompoundVectorHtml = $ax.public.fn.isCompoundVectorHtml = function(hElement) {
return hElement.hasAttribute('compoundmode') && hElement.getAttribute('compoundmode') == "true";
}
$ax.public.fn.removeCompound = function (jobj) { if(_isCompoundVectorHtml(jobj[0])) jobj.removeClass('compound'); }
$ax.public.fn.restoreCompound = function (jobj) { if (_isCompoundVectorHtml(jobj[0])) jobj.addClass('compound'); }
$ax.public.fn.compoundIdFromComponent = function(id) {
var pPos = id.indexOf('p');
var dashPos = id.indexOf('-');
if (pPos < 1) return id;
else if (dashPos < 0) return id.substring(0, pPos);
else return id.substring(0, pPos) + id.substring(dashPos);
}
$ax.public.fn.l2 = function (x, y) { return Math.sqrt(x * x + y * y); }
$ax.public.fn.convertToSingleImage = function (jobj) {
if(!jobj[0]) return;
var widgetId = jobj[0].id;
var object = $obj(widgetId);
if ($ax.public.fn.IsLayer(object.type)) {
var recursiveChildren = _getLayerChildrenDeep(widgetId, true);
for (var j = 0; j < recursiveChildren.length; j++)
$ax.public.fn.convertToSingleImage($jobj(recursiveChildren[j]));
return;
}
//var layer =
if(!_isCompoundVectorHtml(jobj[0])) return;
$('#' + widgetId).removeClass("compound");
$('#' + widgetId + '_img').removeClass("singleImg");
jobj[0].setAttribute('compoundmode', 'false');
var components = object.compoundChildren;
delete object.generateCompound;
for (var i = 0; i < components.length; i++) {
var componentJobj = $jobj($ax.public.fn.getComponentId(widgetId, components[i]));
componentJobj.css('display', 'none');
componentJobj.css('visibility', 'hidden');
}
}
$ax.public.fn.getContainerDimensions = function(query) {
// returns undefined if no containers found.
var containerDimensions;
for (var i = 0; i < query[0].children.length; i++) {
var node = query[0].children[i];
if (node.id.indexOf(query[0].id) >= 0 && node.id.indexOf('container') >= 0) {
containerDimensions = node.style;
}
}
return containerDimensions;
}
$ax.public.fn.rotationMatrix = function (angleInDegrees) {
var angleInRadians = angleInDegrees * (Math.PI / 180);
var cosTheta = Math.cos(angleInRadians);
var sinTheta = Math.sin(angleInRadians);
return { m11: cosTheta, m12: -sinTheta, m21: sinTheta, m22: cosTheta, tx: 0.0, ty: 0.0 };
}
$ax.public.fn.GetFieldFromStyle = function (query, field) {
var raw = query[0].style[field];
if (!raw) raw = query.css(field);
return Number(raw.replace('px', ''));
}
$ax.public.fn.setTransformHowever = function (transformString) {
return {
'-webkit-transform': transformString,
'-moz-transform': transformString,
'-ms-transform': transformString,
'-o-transform': transformString,
'transform': transformString
};
}
$ax.public.fn.getCornersFromComponent = function (id) {
var element = document.getElementById(id);
var matrix = element ? $ax.public.fn.transformFromElement(element) : [1.0, 0.0, 0.0, 1.0, 0.0, 0.0];
var currentMatrix = { m11: matrix[0], m21: matrix[1], m12: matrix[2], m22: matrix[3], tx: matrix[4], ty: matrix[5] };
var dimensions = {};
var axObj = $ax('#' + id);
var viewportLocation = axObj.offsetLocation();
dimensions.left = viewportLocation.left;
dimensions.top = viewportLocation.top;
//dimensions.left = axObj.left(true);
//dimensions.top = axObj.top(true);
var size = axObj.size();
dimensions.width = size.width;
dimensions.height = size.height;
//var transformMatrix1 = { m11: 1, m12: 0, m21: 0, m22: 1, tx: -invariant.x, ty: -invariant.y };
//var transformMatrix2 = { m11: 1, m12: 0, m21: 0, m22: 1, tx: 500, ty: 500 };
var halfWidth = dimensions.width * 0.5;
var halfHeight = dimensions.height * 0.5;
//var preTransformTopLeft = { x: -halfWidth, y: -halfHeight };
//var preTransformBottomLeft = { x: -halfWidth, y: halfHeight };
var preTransformTopRight = { x: halfWidth, y: -halfHeight };
var preTransformBottomRight = { x: halfWidth, y: halfHeight };
return {
//relativeTopLeft: $ax.public.fn.matrixMultiply(currentMatrix, preTransformTopLeft),
//relativeBottomLeft: $ax.public.fn.matrixMultiply(currentMatrix, preTransformBottomLeft),
relativeTopRight: $ax.public.fn.matrixMultiply(currentMatrix, preTransformTopRight),
relativeBottomRight: $ax.public.fn.matrixMultiply(currentMatrix, preTransformBottomRight),
centerPoint: { x: dimensions.left + halfWidth, y: dimensions.top + halfHeight }
//originalDimensions: dimensions,
//transformShift: { x: matrix[4], y: matrix[5] }
}
}
$ax.public.fn.inversePathLengthFunction = function (pathFunction) {
// these are for computing the inverse functions of path integrals.
var makeDivisionNode = function(node1, node2) {
var param = 0.5 * (node1.Param + node2.Param);
var inBetweenNode = {
LowerStop: node1,
HigherStop: node2,
Param: param,
Position: pathFunction(param),
Cumulative: 0.0
};
var lowerDisplacement = $ax.public.fn.vectorMinus(node1.Position, inBetweenNode.Position);
inBetweenNode.LowerInterval = {
Length: $ax.public.fn.l2(lowerDisplacement.x, lowerDisplacement.y),
Node: inBetweenNode,
IsHigher: false
};
var higherDisplacement = $ax.public.fn.vectorMinus(node2.Position, inBetweenNode.Position);
inBetweenNode.HigherInterval = {
Length: $ax.public.fn.l2(higherDisplacement.x, higherDisplacement.y),
Node: inBetweenNode,
IsHigher: true
};
return inBetweenNode;
};
var expandLower = function(node) {
node.LowerChild = makeDivisionNode(node.LowerStop, node);
node.LowerChild.Parent = node;
};
var expandHigher = function(node) {
node.HigherChild = makeDivisionNode(node, node.HigherStop);
node.HigherChild.Parent = node;
};
// for this function, cumulative is a global variable
var cumulative = 0.0;
var labelCumulativeLength = function(node) {
if(!node.LowerChild) {
node.LowerStop.Cumulative = cumulative;
cumulative += node.LowerInterval.Length;
node.Cumulative = cumulative;
} else labelCumulativeLength(node.LowerChild);
if(!node.HigherChild) {
node.Cumulative = cumulative;
cumulative += node.HigherInterval.Length;
node.HigherStop.Cumulative = cumulative;
} else labelCumulativeLength(node.HigherChild);
};
var getIntervalFromPathLength = function(node, length) {
if(length < node.Cumulative) {
return node.LowerChild ? getIntervalFromPathLength(node.LowerChild, length) : node.LowerInterval;
} else return node.HigherChild ? getIntervalFromPathLength(node.HigherChild, length) : node.HigherInterval;
};
var intervalLowerEnd = function(interval) {
return interval.IsHigher ? interval.Node : interval.Node.LowerStop;
};
var intervalHigherEnd = function(interval) {
return interval.IsHigher ? interval.Node.HigherStop : interval.Node;
};
var getParameterFromPathLength = function (node, length) {
var interval = getIntervalFromPathLength(node, length);
var lowerNode = intervalLowerEnd(interval);
var higherNode = intervalHigherEnd(interval);
return lowerNode.Param + (higherNode.Param - lowerNode.Param) * (length - lowerNode.Cumulative) / (higherNode.Cumulative - lowerNode.Cumulative);
};
var insertIntoSortedList = function (longer, shorter, toInsert) {
while (true) {
if (!longer) {
longer = shorter;
shorter = shorter.NextLongest;
continue;
} else if (!shorter) longer.NextLongest = toInsert;
else {
if (longer.Length >= toInsert.Length && shorter.Length <= toInsert.Length) {
longer.NextLongest = toInsert;
toInsert.NextLongest = shorter;
} else {
longer = shorter;
shorter = shorter.NextLongest;
continue;
}
}
break;
}
}
var head = {Param: 0.0, Position: pathFunction(0.0) };
var tail = { Param: 1.0, Position: pathFunction(1.0) };
var root = makeDivisionNode(head, tail);
var currentCurveLength = root.LowerInterval.Length + root.HigherInterval.Length;
var longestInterval;
if (root.LowerInterval.Length < root.HigherInterval.Length) {
longestInterval = root.HigherInterval;
longestInterval.NextLongest = root.LowerInterval;
} else {
longestInterval = root.LowerInterval;
longestInterval.NextLongest = root.HigherInterval;
}
while (longestInterval.Length * 100.0 > currentCurveLength) {
var newNode;
if (longestInterval.IsHigher) {
expandHigher(longestInterval.Node);
newNode = longestInterval.Node.HigherChild;
} else {
expandLower(longestInterval.Node);
newNode = longestInterval.Node.LowerChild;
}
currentCurveLength += (newNode.LowerInterval.Length + newNode.HigherInterval.Length - longestInterval.Length);
insertIntoSortedList(null, longestInterval, newNode.LowerInterval);
insertIntoSortedList(null, longestInterval, newNode.HigherInterval);
longestInterval = longestInterval.NextLongest;
}
labelCumulativeLength(root);
return function(lengthParam) {
return getParameterFromPathLength(root, lengthParam * cumulative);
};
}
});

53
web/main/static/resources/scripts/axure/model.js

@ -1,53 +0,0 @@
// ******* Object Model ******** //
$axure.internal(function($ax) {
var _implementations = {};
var _initializeObject = function(type, obj) {
$.extend(obj, _implementations[type]);
};
$ax.initializeObject = _initializeObject;
var _model = $ax.model = {};
_model.idsInRdoToHideOrLimbo = function(rdoId, scriptIds) {
var rdoScriptId = $ax.repeater.getScriptIdFromElementId(rdoId);
var path = $ax.getPathFromScriptId(rdoScriptId);
if(!scriptIds) scriptIds = [];
var rdo = $ax.getObjectFromElementId(rdoId);
var master = $ax.pageData.masters[rdo.masterId];
var masterChildren = master.diagram.objects;
for(var i = 0; i < masterChildren.length; i++) {
var obj = masterChildren[i];
var objScriptIds = obj.scriptIds;
for(var j = 0; j < objScriptIds.length; j++) {
var scriptId = objScriptIds[j];
// Anything in a layer is already handled by the layer
if($ax.getLayerParentFromElementId(scriptId)) continue;
// Make sure in same rdo
var elementPath = $ax.getPathFromScriptId(scriptId);
// This is because last part of path is for the obj itself.
elementPath.pop();
if(elementPath.length != path.length) continue;
var samePath = true;
for(var k = 0; k < path.length; k++) {
if(elementPath[k] != path[k]) {
samePath = false;
break;
}
}
if(!samePath) continue;
if($ax.public.fn.IsReferenceDiagramObject(obj.type)) _model.idsInRdoToHideOrLimbo(scriptId, scriptIds);
else if(scriptIds.indexOf(scriptId) == -1) scriptIds.push(scriptId);
break;
}
}
return scriptIds;
};
});

467
web/main/static/resources/scripts/axure/move.js

@ -1,467 +0,0 @@
$axure.internal(function($ax) {
var _move = {};
$ax.move = _move;
var widgetMoveInfo = {};
//register and return move info, also create container for rootlayer if needed
$ax.move.PrepareForMove = function (id, x, y, to, options, jobj, rootLayer, skipContainerForRootLayer) {
var fixedInfo = jobj ? {} : $ax.dynamicPanelManager.getFixedInfo(id);
var widget = $jobj(id);
var query = $ax('#' + id);
var isLayer = $ax.getTypeFromElementId(id) == $ax.constants.LAYER_TYPE;
if(!rootLayer) {
rootLayer = _move.getRootLayer(id);
if (rootLayer && !skipContainerForRootLayer) {
$ax.visibility.pushContainer(rootLayer, false);
if (isLayer) widget = $ax.visibility.applyWidgetContainer(id, true);
}
}
if (!jobj) jobj = widget;
var horzProp = 'left';
var vertProp = 'top';
var offsetLocation = to ? query.offsetLocation() : undefined;
var horzX = to ? x - offsetLocation.x : x;
var vertY = to ? y - offsetLocation.y : y;
//var horzX = to ? x - query.locRelativeIgnoreLayer(false) : x;
//var vertY = to ? y - query.locRelativeIgnoreLayer(true) : y;
if (fixedInfo.horizontal == 'right') {
horzProp = 'right';
horzX = to ? $(window).width() - x - $ax.getNumFromPx(jobj.css('right')) - query.width() : -x;
var leftChanges = -horzX;
} else if(fixedInfo.horizontal == 'center') {
horzProp = 'margin-left';
if (to) horzX = x - $(window).width() / 2;
}
if (fixedInfo.vertical == 'bottom') {
vertProp = 'bottom';
vertY = to ? $(window).height() - y - $ax.getNumFromPx(jobj.css('bottom')) - query.height() : -y;
var topChanges = -vertY;
} else if (fixedInfo.vertical == 'middle') {
vertProp = 'margin-top';
if (to) vertY = y - $(window).height() / 2;
}
//todo currently this always save the info, which is not needed for compound vector children and maybe some other cases
//let's optimize it later, only register if registerid is valid..
widgetMoveInfo[id] = {
x: leftChanges === undefined ? horzX : leftChanges,
y: topChanges === undefined ? vertY : topChanges,
options: options
};
return {
horzX: horzX,
vertY: vertY,
horzProp: horzProp,
vertProp: vertProp,
rootLayer: rootLayer,
jobj: jobj
};
};
$ax.move.GetWidgetMoveInfo = function() {
return $.extend({}, widgetMoveInfo);
};
_move.getRootLayer = function (id) {
var isLayer = $ax.getTypeFromElementId(id) == $ax.constants.LAYER_TYPE;
var rootLayer = isLayer ? id : '';
var parentIds = $ax('#' + id).getParents(true, '*')[0];
for(var i = 0; i < parentIds.length; i++) {
var parentId = parentIds[i];
// Keep climbing up layers until you hit a non-layer. At that point you have your root layer
if($ax.public.fn.IsLayer($ax.getTypeFromElementId(parentId))) rootLayer = parentId;
else break;
}
return rootLayer;
};
$ax.move.MoveWidget = function (id, x, y, options, to, animationCompleteCallback, shouldFire, jobj, skipOnMoveEvent) {
var moveInfo = $ax.move.PrepareForMove(id, x, y, to, options, jobj);
$ax.drag.LogMovedWidgetForDrag(id, options.dragInfo);
var object = $obj(id);
if(object && $ax.public.fn.IsLayer(object.type)) {
var childrenIds = $ax.public.fn.getLayerChildrenDeep(id, true);
//don't push container when register moveinfo for child
if(!skipOnMoveEvent) {
for(var i = 0; i < childrenIds.length; i++) $ax.move.PrepareForMove(childrenIds[i], x, y, to, options, null, moveInfo.rootLayer, true);
}
}
//if(!moveInfo) moveInfo = _getMoveInfo(id, x, y, to, options, jobj);
jobj = moveInfo.jobj;
_moveElement(id, options, animationCompleteCallback, shouldFire, jobj, moveInfo);
if(skipOnMoveEvent) return;
$ax.event.raiseSyntheticEvent(id, "onMove");
if(childrenIds) {
for(var i = 0; i < childrenIds.length; i++) $ax.event.raiseSyntheticEvent(childrenIds[i], 'onMove');
}
};
var _moveElement = function (id, options, animationCompleteCallback, shouldFire, jobj, moveInfo){
var cssStyles = {};
if(!$ax.dynamicPanelManager.isPercentWidthPanel($obj(id))) cssStyles[moveInfo.horzProp] = '+=' + moveInfo.horzX;
cssStyles[moveInfo.vertProp] = '+=' + moveInfo.vertY;
$ax.visibility.moveMovedLocation(id, moveInfo.horzX, moveInfo.vertY);
// I don't think root layer is necessary anymore after changes to layer container structure.
// Wait to try removing it until more stable.
var rootLayer = moveInfo.rootLayer;
var query = $addAll(jobj, id);
var completeCount = query.length;
var completeAnimation = function() {
completeCount--;
if(completeCount == 0 && rootLayer) $ax.visibility.popContainer(rootLayer, false);
if(animationCompleteCallback) animationCompleteCallback();
if(shouldFire) $ax.action.fireAnimationFromQueue(id, $ax.action.queueTypes.move);
};
if (options.easing === 'none') {
//if not having this requestAnimationFrame causes performance issues,
//add it back and move the above call to moveMovedLocation into it and the
//query.animate calls below
//window.requestAnimationFrame(function () {
query.css(cssStyles);
if (rootLayer) $ax.visibility.popContainer(rootLayer, false);
if (animationCompleteCallback) animationCompleteCallback();
//});
//if this widget is inside a layer, we should just remove the layer from the queue
if(shouldFire) $ax.action.fireAnimationFromQueue(id, $ax.action.queueTypes.move);
} else if (options.trajectory === 'straight' || moveInfo.horzX === 0 || moveInfo.vertY === 0) {
query.animate(cssStyles, {
duration: options.duration, easing: options.easing, queue: false, complete: completeAnimation});
} else {
var initialHorzProp = $ax.getNumFromPx(query.css(moveInfo.horzProp));
var initialVertProp = $ax.getNumFromPx(query.css(moveInfo.vertProp));
var state = { parameter: 0 };
var ellipseArcFunctionY = function(param) {
return {
x: initialHorzProp + (1.0 - Math.cos(param * Math.PI * 0.5)) * moveInfo.horzX,
y: initialVertProp + Math.sin(param * Math.PI * 0.5) * moveInfo.vertY
};
};
var ellipseArcFunctionX = function (param) {
return {
x: initialHorzProp + Math.sin(param * Math.PI * 0.5) * moveInfo.horzX,
y: initialVertProp + (1.0 - Math.cos(param * Math.PI * 0.5)) * moveInfo.vertY
};
};
var ellipseArcFunction = (moveInfo.horzX > 0) ^ (moveInfo.vertY > 0) ^ options.trajectory === 'arcClockwise'
? ellipseArcFunctionX : ellipseArcFunctionY;
var inverseFunction = $ax.public.fn.inversePathLengthFunction(ellipseArcFunction);
$(state).animate({ parameter: 1.0 }, {
duration: options.duration, easing: options.easing, queue: false,
step: function (now) {
var newPos = ellipseArcFunction(inverseFunction(now));
var changeFields = {};
changeFields[moveInfo.horzProp] = newPos.x;
changeFields[moveInfo.vertProp] = newPos.y;
query.css(changeFields);
},
complete: completeAnimation});
}
// //moveinfo is used for moving 'with this'
// var moveInfo = new Object();
// moveInfo.x = horzX;
// moveInfo.y = vertY;
// moveInfo.options = options;
// widgetMoveInfo[id] = moveInfo;
};
_move.nopMove = function(id, options) {
var moveInfo = new Object();
moveInfo.x = 0;
moveInfo.y = 0;
moveInfo.options = {};
moveInfo.options.easing = 'none';
moveInfo.options.duration = 0;
widgetMoveInfo[id] = moveInfo;
// Layer move using container now.
var obj = $obj(id);
if($ax.public.fn.IsLayer(obj.type)) if(options.onComplete) options.onComplete();
$ax.event.raiseSyntheticEvent(id, "onMove");
};
//rotationDegree: total degree to rotate
//centerPoint: the center of the circular path
var _noRotateOnlyMove = function (id, moveDelta, rotatableMove, fireAnimationQueue, easing, duration, completionCallback) {
moveDelta.x += rotatableMove.x;
moveDelta.y += rotatableMove.y;
if (moveDelta.x == 0 && moveDelta.y == 0) {
if(fireAnimationQueue) {
$ax.action.fireAnimationFromQueue(id, $ax.action.queueTypes.rotate);
$ax.action.fireAnimationFromQueue(id, $ax.action.queueTypes.move);
}
if (completionCallback) completionCallback();
} else {
$jobj(id).animate({ top: '+=' + moveDelta.y, left: '+=' + moveDelta.x }, {
duration: duration,
easing: easing,
queue: false,
complete: function () {
if(fireAnimationQueue) {
$ax.action.fireAnimationFromQueue(id, $ax.action.queueTypes.move);
$ax.action.fireAnimationFromQueue(id, $ax.action.queueTypes.rotate);
}
if (completionCallback) completionCallback();
}
});
}
}
_move.circularMove = function (id, degreeDelta, centerPoint, moveDelta, rotatableMove, resizeOffset, options, fireAnimationQueue, completionCallback, willDoRotation) {
var elem = $jobj(id);
if(!willDoRotation) elem = $addAll(elem, id);
var moveInfo = $ax.move.PrepareForMove(id, moveDelta.x, moveDelta.y, false, options);
// If not rotating, still need to check moveDelta and may need to handle that.
if (degreeDelta === 0) {
_noRotateOnlyMove(id, moveDelta, rotatableMove, fireAnimationQueue, options.easing, options.duration, completionCallback);
return;
}
var stepFunc = function(newDegree) {
var deg = newDegree - rotation.degree;
var widgetCenter = $ax('#' + id).offsetBoundingRect().centerPoint;
//var widgetCenter = $ax.public.fn.getWidgetBoundingRect(id).centerPoint;
//console.log("widget center of " + id + " x " + widgetCenter.x + " y " + widgetCenter.y);
var widgetNewCenter = $axure.fn.getPointAfterRotate(deg, widgetCenter, centerPoint);
// Start by getting the move not related to rotation, and make sure to update center point to move with it.
var ratio = deg / degreeDelta;
var xdelta = (moveDelta.x + rotatableMove.x) * ratio;
var ydelta = (moveDelta.y + rotatableMove.y) * ratio;
if(resizeOffset) {
var resizeShift = {};
resizeShift.x = resizeOffset.x * ratio;
resizeShift.y = resizeOffset.y * ratio;
$axure.fn.getPointAfterRotate(rotation.degree, resizeShift, { x: 0, y: 0 });
xdelta += resizeShift.x;
ydelta += resizeShift.y;
}
centerPoint.x += xdelta;
centerPoint.y += ydelta;
// Now for the move that is rotatable, it must be rotated
rotatableMove = $axure.fn.getPointAfterRotate(deg, rotatableMove, { x: 0, y: 0 });
// Now add in circular move to the mix.
xdelta += widgetNewCenter.x - widgetCenter.x;
ydelta += widgetNewCenter.y - widgetCenter.y;
$ax.visibility.moveMovedLocation(id, xdelta, ydelta);
if(xdelta < 0) elem.css('left', '-=' + -xdelta);
else if(xdelta > 0) elem.css('left', '+=' + xdelta);
if(ydelta < 0) elem.css('top', '-=' + -ydelta);
else if(ydelta > 0) elem.css('top', '+=' + ydelta);
};
var onComplete = function() {
if(fireAnimationQueue) $ax.action.fireAnimationFromQueue(id, $ax.action.queueTypes.move);
if(completionCallback) completionCallback();
if(moveInfo.rootLayer) $ax.visibility.popContainer(moveInfo.rootLayer, false);
var isPercentWidthPanel = $ax.dynamicPanelManager.isPercentWidthPanel($obj(id));
if(isPercentWidthPanel) {
$ax.dynamicPanelManager.updatePanelPercentWidth(id);
$ax.dynamicPanelManager.updatePanelContentPercentWidth(id);
}
if(elem.css('position') == 'fixed') {
if(!isPercentWidthPanel) elem.css('left', '');
elem.css('top', '');
}
};
var rotation = { degree: 0 };
if(!options.easing || options.easing === 'none' || options.duration <= 0) {
stepFunc(degreeDelta);
onComplete();
} else {
$(rotation).animate({ degree: degreeDelta }, {
duration: options.duration,
easing: options.easing,
queue: false,
step: stepFunc,
complete: onComplete
});
}
};
//rotate a widget by degree, center is 50% 50%
_move.rotate = function (id, degree, easing, duration, to, shouldFire, completionCallback) {
var currentDegree = _move.getRotationDegree(id);
if(to) degree = degree - currentDegree;
if(degree === 0) {
if (shouldFire) $ax.action.fireAnimationFromQueue(id, $ax.action.queueTypes.rotate);
return;
}
var query = $jobj(id);
var stepFunc = function(now) {
var degreeDelta = now - rotation.degree;
var newDegree = currentDegree + degreeDelta;
query.css($ax.public.fn.setTransformHowever("rotate(" + newDegree + "deg)"));
currentDegree = newDegree;
};
var onComplete = function() {
if(shouldFire) {
$ax.action.fireAnimationFromQueue($ax.public.fn.compoundIdFromComponent(id), $ax.action.queueTypes.rotate);
}
if(completionCallback) completionCallback();
$ax.annotation.adjustIconLocation(id);
};
var rotation = { degree: 0 };
$ax.visibility.setRotatedAngle(id, currentDegree + degree);
//if no animation, setting duration to 1, to prevent RangeError in rotation loops without animation
if(!easing || easing === 'none' || duration <= 0) {
stepFunc(degree);
onComplete();
} else {
$(rotation).animate({ degree: degree }, {
duration: duration,
easing: easing,
queue: false,
step: stepFunc,
complete: onComplete
});
}
};
_move.compoundRotateAround = function (id, degreeDelta, centerPoint, moveDelta, rotatableMove, resizeOffset, easing, duration, fireAnimationQueue, completionCallback) {
if (degreeDelta === 0) {
_noRotateOnlyMove($ax.public.fn.compoundIdFromComponent(id), moveDelta, rotatableMove, fireAnimationQueue, easing, duration, completionCallback, $ax.action.queueTypes.rotate);
return;
}
var elem = $jobj(id);
var rotation = { degree: 0 };
if (!easing || easing === 'none' || duration <= 0) {
duration = 1;
easing = 'linear'; //it doesn't matter anymore here...
}
var originalWidth = $ax.getNumFromPx(elem.css('width'));
var originalHeight = $ax.getNumFromPx(elem.css('height'));
var originalLeft = $ax.getNumFromPx(elem.css('left'));
var originalTop = $ax.getNumFromPx(elem.css('top'));
$(rotation).animate({ degree: degreeDelta }, {
duration: duration,
easing: easing,
queue: false,
step: function (newDegree) {
var transform = $ax.public.fn.transformFromElement(elem[0]);
var originalCenter = { x: originalLeft + 0.5 * originalWidth, y: originalTop + 0.5 * originalHeight};
var componentCenter = { x: originalCenter.x + transform[4], y: originalCenter.y + transform[5] };
var deg = newDegree - rotation.degree;
var ratio = deg / degreeDelta;
var xdelta = (moveDelta.x + rotatableMove.x) * ratio;
var ydelta = (moveDelta.y + rotatableMove.y) * ratio;
if (resizeOffset) {
var resizeShift = {};
resizeShift.x = resizeOffset.x * ratio;
resizeShift.y = resizeOffset.y * ratio;
$axure.fn.getPointAfterRotate(rotation.degree, resizeShift, { x: 0, y: 0 });
xdelta += resizeShift.x;
ydelta += resizeShift.y;
}
var rotationMatrix = $ax.public.fn.rotationMatrix(deg);
var compositionTransform = $ax.public.fn.matrixMultiplyMatrix(rotationMatrix,
{ m11: transform[0], m21: transform[1], m12: transform[2], m22: transform[3] });
//console.log("widget center of " + id + " x " + widgetCenter.x + " y " + widgetCenter.y);
var widgetNewCenter = $axure.fn.getPointAfterRotate(deg, componentCenter, centerPoint);
var newMatrix = $ax.public.fn.matrixString(compositionTransform.m11, compositionTransform.m21, compositionTransform.m12, compositionTransform.m22,
widgetNewCenter.x - originalCenter.x + xdelta, widgetNewCenter.y - originalCenter.y + ydelta);
elem.css($ax.public.fn.setTransformHowever(newMatrix));
},
complete: function () {
if (fireAnimationQueue) {
$ax.action.fireAnimationFromQueue(elem.parent()[0].id, $ax.action.queueTypes.rotate);
}
if(completionCallback) completionCallback();
}
});
};
_move.getRotationDegreeFromElement = function(element) {
if(element == null) return NaN;
var transformString = element.style['transform'] ||
element.style['-o-transform'] ||
element.style['-ms-transform'] ||
element.style['-moz-transform'] ||
element.style['-webkit-transform'];
if(transformString) {
var rotateRegex = /rotate\(([-?0-9]+)deg\)/;
var degreeMatch = rotateRegex.exec(transformString);
if(degreeMatch && degreeMatch[1]) return parseFloat(degreeMatch[1]);
}
if(window.getComputedStyle) {
var st = window.getComputedStyle(element, null);
} else {
console.log('rotation is not supported for ie 8 and below in this version of axure rp');
return 0;
}
var tr = st.getPropertyValue("transform") ||
st.getPropertyValue("-o-transform") ||
st.getPropertyValue("-ms-transform") ||
st.getPropertyValue("-moz-transform") ||
st.getPropertyValue("-webkit-transform");
if(!tr || tr === 'none') return 0;
var values = tr.split('(')[1];
values = values.split(')')[0],
values = values.split(',');
var a = values[0];
var b = values[1];
var radians = Math.atan2(b, a);
if(radians < 0) {
radians += (2 * Math.PI);
}
return radians * (180 / Math.PI);
};
_move.getRotationDegree = function(elementId) {
if($ax.public.fn.IsLayer($obj(elementId).type)) {
return $jobj(elementId).data('layerDegree');
}
return _move.getRotationDegreeFromElement(document.getElementById(elementId));
}
});

94
web/main/static/resources/scripts/axure/recording.js

@ -1,94 +0,0 @@
// ******* Recording MANAGER ******** //
$axure.internal(function($ax) {
var _recording = $ax.recording = {};
$ax.recording.recordEvent = function(element, eventInfo, axEventObject, timeStamp) {
var elementHtml = $jobj(element);
var className = elementHtml.attr('class');
var inputValue;
if(className === 'ax_checkbox') {
inputValue = elementHtml.find('#' + element + '_input')[0].checked;
eventInfo.inputType = className;
eventInfo.inputValue = inputValue;
}
if(className === 'ax_text_field') {
inputValue = elementHtml.find('#' + element + '_input').val();
eventInfo.inputType = className;
eventInfo.inputValue = inputValue;
}
var scriptId = $ax.repeater.getScriptIdFromElementId(element);
var diagramObjectPath = $ax.getPathFromScriptId(scriptId);
var form = {
recordingId: $ax.recording.recordingId,
elementID: element,
eventType: axEventObject.description,
'eventInfo': eventInfo,
// eventObject: axEventObject,
'timeStamp': timeStamp,
'path': diagramObjectPath
// ,
// 'trigger': function() {
// $ax.event.handleEvent(element, eventInfo, axEventObject);
// return false;
// }
};
$ax.messageCenter.postMessage('logEvent', form);
};
$ax.recording.maybeRecordEvent = function(element, eventInfo, axEventObject, timeStamp) {
};
$ax.recording.recordingId = "";
$ax.recording.recordingName = "";
$ax.messageCenter.addMessageListener(function(message, data) {
if(message === 'startRecording') {
$ax.recording.maybeRecordEvent = $ax.recording.recordEvent;
$ax.recording.recordingId = data.recordingId;
$ax.recording.recordingName = data.recordingName;
} else if(message === 'stopRecording') {
$ax.recording.maybeRecordEvent = function(element, eventInfo, axEventObject, timeStamp) {
};
}
else if(message === 'playEvent') {
var eventType = makeFirstLetterLower(data.eventType);
var inputElement;
var dObj = data.element === '' ? $ax.pageData.page : $ax.getObjectFromElementId(data.element);
if(!data.axEventObject) {
data.axEventObject = dObj && dObj.interactionMap && dObj.interactionMap[eventType];
}
data.eventInfo.thiswidget = $ax.getWidgetInfo(data.element);
data.eventInfo.item = $ax.getItemInfo(data.element);
if(data.eventInfo.inputType && data.eventInfo.inputType === 'ax_checkbox') {
inputElement = $jobj(data.element + '_input');
inputElement[0].checked = data.eventInfo.inputValue;
}
if(data.eventInfo.inputType && data.eventInfo.inputType === 'ax_text_field') {
inputElement = $jobj(data.element + '_input');
inputElement.val(data.eventInfo.inputValue);
}
$ax.event.handleEvent(data.element, data.eventInfo, data.axEventObject, false, true);
}
});
var makeFirstLetterLower = function(eventName) {
return eventName.substr(0, 1).toLowerCase() + eventName.substr(1);
};
});

2413
web/main/static/resources/scripts/axure/repeater.js

File diff suppressed because it is too large

241
web/main/static/resources/scripts/axure/sto.js

@ -1,241 +0,0 @@

$axure.internal(function($ax) {
var funcs = {};
var weekday = new Array(7);
weekday[0] = "Sunday";
weekday[1] = "Monday";
weekday[2] = "Tuesday";
weekday[3] = "Wednesday";
weekday[4] = "Thursday";
weekday[5] = "Friday";
weekday[6] = "Saturday";
funcs.getDayOfWeek = function() {
return _getDayOfWeek(this.getDay());
};
var _getDayOfWeek = $ax.getDayOfWeek = function(day) {
return weekday[day];
};
var month = new Array(12);
month[0] = "January";
month[1] = "February";
month[2] = "March";
month[3] = "April";
month[4] = "May";
month[5] = "June";
month[6] = "July";
month[7] = "August";
month[8] = "September";
month[9] = "October";
month[10] = "November";
month[11] = "December";
funcs.getMonthName = function() {
return _getMonthName(this.getMonth());
};
var _getMonthName = $ax.getMonthName = function(monthNum) {
return month[monthNum];
};
funcs.getMonth = function() {
return this.getMonth() + 1;
};
funcs.addYears = function(years) {
var retVal = new Date(this.valueOf());
retVal.setFullYear(this.getFullYear() + Number(years));
return retVal;
};
funcs.addMonths = function(months) {
var retVal = new Date(this.valueOf());
retVal.setMonth(this.getMonth() + Number(months));
return retVal;
};
funcs.addDays = function(days) {
var retVal = new Date(this.valueOf());
retVal.setDate(this.getDate() + Number(days));
return retVal;
};
funcs.addHours = function(hours) {
var retVal = new Date(this.valueOf());
retVal.setHours(this.getHours() + Number(hours));
return retVal;
};
funcs.addMinutes = function(minutes) {
var retVal = new Date(this.valueOf());
retVal.setMinutes(this.getMinutes() + Number(minutes));
return retVal;
};
funcs.addSeconds = function(seconds) {
var retVal = new Date(this.valueOf());
retVal.setSeconds(this.getSeconds() + Number(seconds));
return retVal;
};
funcs.addMilliseconds = function(milliseconds) {
var retVal = new Date(this.valueOf());
retVal.setMilliseconds(this.getMilliseconds() + Number(milliseconds));
return retVal;
};
var _stoHandlers = {};
_stoHandlers.literal = function(sto, scope, eventInfo) {
return sto.value;
};
//need angle bracket syntax because var is a reserved word
_stoHandlers['var'] = function(sto, scope, eventInfo) {
// Can't us 'A || B' here, because the first value can be false, true, or empty string and still be valid.
var retVal = scope.hasOwnProperty(sto.name) ? scope[sto.name] : $ax.globalVariableProvider.getVariableValue(sto.name, eventInfo);
// Handle desired type here?
if(retVal && retVal.exprType) {
retVal = $ax.expr.evaluateExpr(retVal, eventInfo);
}
if((sto.desiredType == 'int' || sto.desiredType == 'float')) {
var num = new Number(retVal);
retVal = isNaN(num.valueOf()) ? retVal : num;
}
return retVal;
};
//TODO: Perhaps repeaterId can be detirmined at generation, and stored in the sto info.
_stoHandlers.item = function(sto, scope, eventInfo, prop) {
prop = prop || (eventInfo.data ? 'data' : eventInfo.link ? 'url' : eventInfo.image ? 'img' : 'text');
var id = sto.isTarget || !$ax.repeater.hasData(eventInfo.srcElement, sto.name) ? eventInfo.targetElement : eventInfo.srcElement;
return getData(eventInfo, id, sto.name, prop);
};
var getData = function(eventInfo, id, name, prop) {
var repeaterId = $ax.getParentRepeaterFromScriptId($ax.repeater.getScriptIdFromElementId(id));
var itemId = $ax.repeater.getItemIdFromElementId(id);
return $ax.repeater.getData(eventInfo, repeaterId, itemId, name, prop);
};
_stoHandlers.paren = function(sto, scope, eventInfo) {
return _evaluateSTO(sto.innerSTO, scope, eventInfo);
};
_stoHandlers.fCall = function(sto, scope, eventInfo) {
//TODO: [mas] handle required type
var thisObj = _evaluateSTO(sto.thisSTO, scope, eventInfo);
if(sto.thisSTO.desiredType == 'string' && sto.thisSTO.computedType != 'string') thisObj = thisObj.toString();
var args = [];
for(var i = 0; i < sto.arguments.length; i++) {
args[i] = _evaluateSTO(sto.arguments[i], scope, eventInfo);
}
var fn = (funcs.hasOwnProperty(sto.func) && funcs[sto.func]) || thisObj[sto.func];
return fn.apply(thisObj, args);
};
_stoHandlers.propCall = function(sto, scope, eventInfo) {
//TODO: [mas] handle required type
if((sto.prop == 'url' || sto.prop == 'img') && sto.thisSTO.sto == 'item') return _stoHandlers.item(sto.thisSTO, scope, eventInfo, sto.prop);
var thisObj = _evaluateSTO(sto.thisSTO, scope, eventInfo);
// calculate cursor offset for elements that are located relative to their parents
if (sto.thisSTO.name == 'cursor') {
var cursorOffset = $ax.public.fn.getCursorOffset(eventInfo.targetElement);
thisObj = {
x: thisObj.x - cursorOffset.x,
y: thisObj.y - cursorOffset.y,
};
}
var prop = thisObj[sto.prop] instanceof Function ? thisObj[sto.prop]() : thisObj[sto.prop];
return prop;
};
var _binOps = {};
_binOps['+'] = function(left, right) {
if(left instanceof Date) return addDayToDate(left, right);
if(right instanceof Date) return addDayToDate(right, left);
var num = Number(left) + Number(right);
return isNaN(num) ? (String(left) + String(right)) : num;
};
_binOps['-'] = function(left, right) {
if(left instanceof Date) return addDayToDate(left, -right);
return left - right;
};
_binOps['*'] = function(left, right) { return Number(left) * Number(right); };
_binOps['/'] = function(left, right) { return Number(left) / Number(right); };
_binOps['%'] = function(left, right) { return Number(left) % Number(right); };
_binOps['=='] = function(left, right) { return _getBool(left) == _getBool(right); };
_binOps['!='] = function(left, right) { return _getBool(left) != _getBool(right); };
_binOps['<'] = function(left, right) { return Number(left) < Number(right); };
_binOps['<='] = function(left, right) { return Number(left) <= Number(right); };
_binOps['>'] = function(left, right) { return Number(left) > Number(right); };
_binOps['>='] = function(left, right) { return Number(left) >= Number(right); };
_binOps['&&'] = function(left, right) { return _getBool(left) && _getBool(right); };
_binOps['||'] = function(left, right) { return _getBool(left) || _getBool(right); };
// TODO: Move this to generic place to be used.
var addDayToDate = function(date, days) {
var retVal = new Date(date.valueOf());
retVal.setDate(date.getDate() + days);
return retVal;
};
var _unOps = {};
_unOps['+'] = function(arg) { return +arg; };
_unOps['-'] = function(arg) { return -arg; };
_unOps['!'] = function(arg) { return !_getBool(arg); };
_stoHandlers.binOp = function(sto, scope, eventInfo) {
var left = _evaluateSTO(sto.leftSTO, scope, eventInfo);
var right = _evaluateSTO(sto.rightSTO, scope, eventInfo);
return _binOps[sto.op](left, right);
};
_stoHandlers.unOp = function(sto, scope, eventInfo) {
var input = _evaluateSTO(sto.inputSTO, scope, eventInfo);
return _unOps[sto.op](input);
};
var _getBool = function(val) {
var lowerVal = val.toLowerCase ? val.toLowerCase() : val;
return lowerVal == "false" ? false : lowerVal == "true" ? true : val;
};
$ax.getBool = _getBool;
var _evaluateSTO = function(sto, scope, eventInfo) {
if(sto.sto == 'error') return undefined;
return _tryEscapeRichText(castSto(_stoHandlers[sto.sto](sto, scope, eventInfo), sto), eventInfo);
};
$ax.evaluateSTO = _evaluateSTO;
var castSto = function(val, sto) {
var type = sto.computedType || sto.desiredType;
if(type == 'string') val = String(val);
else if(type == 'date' && !(val instanceof Date)) val = new Date(val);
else if(type == 'int' || type == 'float') val = Number(val);
else if(type == 'bool') val = Boolean(val);
return val;
};
var _tryEscapeRichText = function(text, eventInfo) {
return eventInfo.htmlLiteral ? _escapeRichText(text) : text;
};
var _escapeRichText = function(text) {
if(typeof (text) != 'string') return text;
return text.replace('<', '&lt;');
};
});

1389
web/main/static/resources/scripts/axure/style.js

File diff suppressed because it is too large

189
web/main/static/resources/scripts/axure/tree.js

@ -1,189 +0,0 @@
// This is actually for BOTH trees and menus
$axure.internal(function($ax) {
var _tree = $ax.tree = {};
var _menu = $ax.menu = {};
$ax.menu.InitializeSubmenu = function(subMenuId, cellId) {
var $submenudiv = $('#' + subMenuId);
//mouseenter and leave for parent table cell
$('#' + cellId).mouseenter(function(e) {
//show current submenu
// var submenuElement = document.getElementById(subMenuId);
// if($ax.visibility.IsVisible(submenuElement) && submenuElement.style.display !== 'none') return;
$ax.visibility.SetIdVisible(subMenuId, true);
$ax.legacy.BringToFront(subMenuId);
//$submenudiv.find('.menu_item').each(function() {
// $ax.style.updateTextAlignmentForVisibility($ax.GetTextPanelId($(this).attr('id')));
//});
_fireEventForSubmenu(subMenuId, "onShow");
}).mouseleave(function (e) {
var offset = $submenudiv.offset();
var subcontwidth = $submenudiv.width();
var subcontheight = $submenudiv.height();
//If mouse is not within the submenu (added 3 pixel margin to top and left calculations), then close the submenu...
if(e.pageX + 3 < offset.left || e.pageX > offset.left + subcontwidth || e.pageY + 3 < offset.top || e.pageY > offset.top + subcontheight) {
$submenudiv.find('.sub_menu').addBack().each(function () {
// if(!$ax.visibility.IsVisible(this)) return;
$ax.visibility.SetVisible(this, false);
_fireEventForSubmenu(subMenuId, "onHide");
});
$ax.style.SetWidgetHover(cellId, false);
}
});
$submenudiv.css('display', 'none');
//mouseleave for submenu
$submenudiv.mouseleave(function(e) {
//close this menu and all menus below it
$(this).find('.sub_menu').addBack().css({ 'visibility': 'hidden', 'display': 'none' }).each(function () {
// if(!$ax.visibility.IsVisible(this)) return;
_fireEventForSubmenu(this.id, "onHide");
});
$ax.style.SetWidgetHover(cellId, false);
});
};
var _fireEventForSubmenu = function(targetId, eventName) {
var diagramObject = $ax.getObjectFromElementId(targetId);
var event = diagramObject.interactionMap && diagramObject.interactionMap[eventName];
if(event) {
var eventInfo = $ax.getEventInfoFromEvent($ax.getjBrowserEvent(), false, targetId);
$ax.event.handleEvent(targetId, eventInfo, event, false, true);
}
}
function IsNodeVisible(nodeId) {
var current = window.document.getElementById(nodeId);
var parent = current.parentNode;
//move all the parent's children that are below the node and their annotations
while(!$(current).hasClass("treeroot")) {
if(!$ax.visibility.IsVisible(parent)) return false;
current = parent;
parent = parent.parentNode;
}
return true;
}
$ax.tree.ExpandNode = function(nodeId, childContainerId, plusMinusId) {
var container = window.document.getElementById(childContainerId);
if(!container || $ax.visibility.IsVisible(container)) return;
$ax.visibility.SetVisible(container, true);
if(plusMinusId != '') $ax.style.SetWidgetSelected(plusMinusId, true);
var delta = _getExpandCollapseDelta(nodeId, childContainerId);
var isVisible = IsNodeVisible(nodeId);
var current = window.document.getElementById(nodeId);
var parent = current.parentNode;
//move all the parent's children that are below the node and their annotations
while(!$(current).hasClass("treeroot")) {
var after = false;
var i = 0;
for(i = 0; i < parent.childNodes.length; i++) {
var child = parent.childNodes[i];
if(after && child.id && $(child).hasClass("treenode")) {
var elementId = child.id;
child.style.top = $ax.getNumFromPx($(child).css('top')) + delta + 'px';
var ann = window.document.getElementById(elementId + "_ann");
if (ann) ann.style.top = $ax.getNumFromPx($(ann).css('top')) + delta + 'px';
}
if(child == current) after = true;
}
current = parent;
parent = parent.parentNode;
if(!isVisible && $ax.visibility.IsVisible(parent)) break;
}
};
$ax.tree.CollapseNode = function(nodeId, childContainerId, plusMinusId) {
var container = window.document.getElementById(childContainerId);
if(!container || !$ax.visibility.IsVisible(container)) return;
if(plusMinusId != '') $ax.style.SetWidgetSelected(plusMinusId, false);
var delta = _getExpandCollapseDelta(nodeId, childContainerId);
//hide it after getting the delta, otherwise the delta can't be calculated (offsetParent is null)
$ax.visibility.SetVisible(container, false);
var isVisible = IsNodeVisible(nodeId);
var current = window.document.getElementById(nodeId);
var parent = current.parentNode;
//move all the parent's children that are below the node and their annotations
while(!$(current).hasClass("treeroot")) {
var after = false;
var i = 0;
for(i = 0; i < parent.childNodes.length; i++) {
var child = parent.childNodes[i];
if(after && child.id && $(child).hasClass("treenode")) {
var elementId = child.id;
child.style.top = $ax.getNumFromPx($(child).css('top')) - delta + 'px';
var ann = window.document.getElementById(elementId + "_ann");
if (ann) ann.style.top = $ax.getNumFromPx($(ann).css('top')) - delta + 'px';
}
if(child == current) after = true;
}
current = parent;
parent = current.parentNode;
if(!isVisible && $ax.visibility.IsVisible(parent)) break;
}
};
var _getExpandCollapseDelta = function(nodeId, childContainerId) {
return _getChildContainerHeightHelper(childContainerId);
};
var _getChildContainerHeightHelper = function(childContainerId) {
var height = 0;
$('#' + childContainerId).children().each(function() {
if($(this).hasClass("treenode")) {
height += $(this).height();
var subContainer = window.document.getElementById(this.id + '_children');
if(subContainer && $ax.visibility.IsVisible(subContainer)) {
height += _getChildContainerHeightHelper(subContainer.id);
}
}
});
return height;
};
$ax.tree.InitializeTreeNode = function(nodeId, plusminusid, childContainerId, selectText) {
var childContainer = window.document.getElementById(childContainerId);
if(childContainer) {
//relying on the html generator to put this inline so we know to collapse by default
var isCollapsed = childContainer.style.visibility == "hidden";
if(isCollapsed) $ax.visibility.SetVisible(childContainer, false);
if(!isCollapsed && plusminusid != '') $ax.style.SetWidgetSelected(plusminusid, true);
}
if(plusminusid != '') {
$jobj(plusminusid).click(function() {
var visibleSet = $ax.visibility.IsIdVisible(childContainerId);
if(visibleSet) $ax.tree.CollapseNode(nodeId, childContainerId, plusminusid);
else $ax.tree.ExpandNode(nodeId, childContainerId, plusminusid);
$ax.tree.SelectTreeNode(nodeId, true);
return false;
}).css('cursor', 'default');
}
};
var _getButtonShapeId = function(id) {
var obj = $obj(id);
return $ax.public.fn.IsTreeNodeObject(obj.type) ? $ax.getElementIdFromPath([obj.buttonShapeId], { relativeTo: id }) : id;
};
$ax.tree.SelectTreeNode = function(id, selected) {
$ax.style.SetWidgetSelected(_getButtonShapeId(id), selected);
};
});

99
web/main/static/resources/scripts/axure/utils.temp.js

@ -1,99 +0,0 @@
// ******* Deep Copy ******** //
$axure.internal(function($ax) {
// TODO: [ben] Ah, infinite loops cause major issues here. Tried saving objects we've already hit, but that didn't seem to work (at least at my first shot).
// TODO: [ben] To continue from above, added a filter to filter out problem keys. Will need a better way of sorting this out eventually.
var _deepCopy = function (original, trackCopies, filter) {
if(trackCopies) {
var index = _getCopyIndex(original);
if(index != -1) return _originalToCopy[index][1];
}
var isArray = original instanceof Array;
var isObject = !(original instanceof Function) && !(original instanceof Date) && (original instanceof Object);
if(!isArray && !isObject) return original;
var copy = isArray ? [] : { };
if(trackCopies) _originalToCopy.push([original, copy]);
isArray ? deepCopyArray(original, trackCopies, copy, filter) : deepCopyObject(original, trackCopies, copy, filter);
return copy;
};
$ax.deepCopy = _deepCopy;
// Hacky way to copy event info. Copying dragInfo causes major issues due to infinite loops
// Hashmap doesn't map objects well. It just toStrings them, making them all the same key. This has to be slow...
var _originalToCopy = [];
var _getCopyIndex = function(original) {
for(var i = 0; i < _originalToCopy.length; i++) if(original === _originalToCopy[i][0]) return i;
return -1;
};
$ax.eventCopy = function(eventInfo) {
var copy = _deepCopy(eventInfo, true, ['dragInfo', 'elementQuery', 'obj']);
// reset the map. TODO: May need to reset elsewhere too, but this is the only way it's used currently
_originalToCopy = [];
return copy;
};
var deepCopyArray = function(original, trackCopies, copy, filter) {
for(var i = 0; i < original.length; i++) {
copy[i] = _deepCopy(original[i], trackCopies, filter);
}
};
var deepCopyObject = function(original, trackCopies, copy, filter) {
for(var key in original) {
if(!original.hasOwnProperty(key)) continue; // Continue if the prop was not put there like a dictionary, but just a native part of the object
if(filter && filter.indexOf[key] != -1) copy[key] = original[key]; // If that key is filtered out, skip recursion on it.
else copy[key] = _deepCopy(original[key], trackCopies, filter);
}
};
// Our implementation of splice because it is broken in IE8...
$ax.splice = function(array, startIndex, count) {
var retval = [];
if(startIndex >= array.length || startIndex < 0 || count == 0) return retval;
if(!count || startIndex + count > array.length) count = array.length - startIndex;
for(var i = 0; i < count; i++) retval[i] = array[startIndex + i];
for(i = startIndex + count; i < array.length; i++) array[i - count] = array[i];
for(i = 0; i < count; i++) array.pop();
return retval;
};
});
// ******* Flow Shape Links ******** //
$axure.internal(function($ax) {
$(window.document).ready(function() {
if (!$ax.document.configuration.linkFlowsToPages && !$ax.document.configuration.linkFlowsToPagesNewWindow) return;
$ax(function (dObj) { return ($ax.public.fn.IsVector(dObj.type) || $ax.public.fn.IsSnapshot(dObj.type)) && dObj.referencePageUrl; }).each(function (dObj, elementId) {
var elementIdQuery = $('#' + elementId);
if($ax.document.configuration.linkFlowsToPages && !$ax.event.HasClick(dObj)) {
elementIdQuery.css("cursor", "pointer");
elementIdQuery.click(function() {
$ax.navigate({
url: dObj.referencePageUrl,
target: "current",
includeVariables: true
});
});
}
if($ax.document.configuration.linkFlowsToPagesNewWindow) {
$('#' + elementId + "_ref").append("<div id='" + elementId + "PagePopup' class='refpageimage'></div>");
$('#' + elementId + "PagePopup").click(function() {
$ax.navigate({
url: dObj.referencePageUrl,
target: "new",
includeVariables: true
});
});
}
});
});
});

136
web/main/static/resources/scripts/axure/variables.js

@ -1,136 +0,0 @@
// ******* GLOBAL VARIABLE PROVIDER ******** //
$axure.internal(function($ax) {
var _globalVariableValues = {};
var _globalVariableProvider = {};
$ax.globalVariableProvider = _globalVariableProvider;
var setVariableValue = function(variable, value, suppressBroadcast) {
if(!(value instanceof Object)) value = value.toString();
variable = variable.toLowerCase();
_globalVariableValues[variable] = value;
if(suppressBroadcast !== true) {
var varData = {
globalVarName: variable,
globalVarValue: value.toString()
};
$axure.messageCenter.postMessage('setGlobalVar', varData);
}
//Post global var values only if pageData is loaded (suppresses exception which occurs when page loads)
if($ax.pageData) {
_postGlobalVarVals();
}
};
_globalVariableProvider.setVariableValue = setVariableValue;
var getVariableValue = function(variable, eventInfo, ignoreDefaultsForLinkUrl) {
variable = variable.toLowerCase();
if(_globalVariableValues[variable] !== undefined) {
//If this is for the GetLinkUrl function and
//the current value of the global variable is the same as the default defined in the document, don't return it
if(ignoreDefaultsForLinkUrl == true && $ax.document.globalVariables[variable] == _globalVariableValues[variable]) {
return null;
}
return _globalVariableValues[variable];
}
if($ax.document.globalVariables[variable] !== undefined) return ignoreDefaultsForLinkUrl == true ? null : $ax.document.globalVariables[variable];
switch(variable) {
case "pagename": return $ax.pageData.page.name;
case "now": return eventInfo.now;
case "gendate": return $ax.pageData.generationDate;
case "dragx": return $ax.drag.GetDragX();
case "dragy": return $ax.drag.GetDragY();
case "totaldragx": return $ax.drag.GetTotalDragX();
case "totaldragy": return $ax.drag.GetTotalDragY();
case "dragtime": return $ax.drag.GetDragTime();
case "math": return Math;
case "date": return Date;
case "window": return eventInfo && eventInfo.window;
case "this": return eventInfo && eventInfo.thiswidget && $ax.getWidgetInfo(eventInfo.thiswidget.elementId);
case "item": return (eventInfo && eventInfo.item && eventInfo.item.valid && eventInfo.item) || getVariableValue('targetitem', eventInfo, ignoreDefaultsForLinkUrl);
case "targetitem": return eventInfo && eventInfo.targetElement && $ax.getItemInfo(eventInfo.targetElement);
case "repeater": return eventInfo && eventInfo.repeater;
case "target": return eventInfo && eventInfo.targetElement && $ax.getWidgetInfo(eventInfo.targetElement);
case "cursor": return eventInfo && eventInfo.cursor;
default:
var gen = variable.substr(0, 3) == "gen";
var date = gen ? $ax.pageData.generationDate : new Date();
var prop = gen ? variable.substr(3) : variable;
switch(prop) {
case "day": return date.getDate();
case "month": return date.getMonth() + 1;
case "monthname": return $ax.getMonthName(date.getMonth());
case "dayofweek": return $ax.getDayOfWeek(date.getDay());
case "year": return date.getFullYear();
case "time": return date.toLocaleTimeString();
case "hours": return date.getHours();
case "minutes": return date.getMinutes();
case "seconds": return date.getSeconds();
default: return '';
}
}
};
_globalVariableProvider.getVariableValue = getVariableValue;
var load = function() {
let query = (window.location.href.split("#")[1] || ''); //hash.substring(1); Firefox decodes this so & in variables breaks
if(query.length > 0) {
$ax.utils.parseGlobalVars(query, setVariableValue);
}
};
var getLinkUrl = function(baseUrl, useGlobalVarName) {
var toAdd = '';
var definedVariables = _getDefinedVariables();
for(var i = 0; i < definedVariables.length; i++) {
var key = definedVariables[i];
var val = getVariableValue(key, undefined, true);
if(val != null) {
if(toAdd.length > 0) toAdd += '&';
else if(useGlobalVarName) toAdd = GLOBAL_VAR_NAME;
toAdd += key + '=' + encodeURIComponent(val);
}
}
return toAdd.length > 0 ? baseUrl + (useGlobalVarName ? '' : $axure.shouldSendVarsToServer() ? '?' : '#') + toAdd + "&" + GLOBAL_VAR_CHECKSUM + "=1" : baseUrl;
};
_globalVariableProvider.getLinkUrl = getLinkUrl;
var _getDefinedVariables = function() {
return $ax.pageData.variables;
};
_globalVariableProvider.getDefinedVariables = _getDefinedVariables;
var _postGlobalVarVals = function() {
var retVal = {};
var definedVariables = _getDefinedVariables();
for(var i = 0; i < definedVariables.length; i++) {
var key = definedVariables[i];
var val = getVariableValue(key);
if(val != null) {
retVal[key] = val;
}
}
$ax.messageCenter.postMessage('globalVariableValues', retVal);
};
$ax.messageCenter.addMessageListener(function(message, data) {
if(message == 'getGlobalVariables') {
_postGlobalVarVals();
} else if(message == 'resetGlobalVariables') {
_globalVariableValues = {};
_postGlobalVarVals();
}
});
load();
});

268
web/main/static/resources/scripts/axure/viewer.js

@ -1,268 +0,0 @@
// ******* SITEMAP TOOLBAR VIEWER ACTIONS ******** //
$axure.internal(function ($ax) {
var userTriggeredEventNames = ['onClick', 'onDoubleClick', 'onMouseOver', 'onMouseMove', 'onMouseOut', 'onMouseDown', 'onMouseUp',
'onKeyDown', 'onKeyUp', 'onFocus', 'onLostFocus', 'onTextChange', 'onSelectionChange', 'onSelectedChange', 'onSelect', 'onUnselect',
'onSwipeLeft', 'onSwipeRight', 'onSwipeUp', 'onSwipeDown', 'onDragStart', 'onDrag', 'onDragDrop', 'onScroll', 'onContextMenu', 'onMouseHover', 'onLongClick'];
//var _toggleSelectWidgetNoteForRepeater = function (repeaterId, scriptId, select) {
// var itemIds = $ax.getItemIdsForRepeater(repeaterId);
// for(var i = 0; i < itemIds.length; i++) {
// var itemId = itemIds[i];
// var elementId = $ax.repeater.createElementId(scriptId, itemId);
// if(select) $('#' + elementId).addClass('widgetNoteSelected');
// else $('#' + elementId).removeClass('widgetNoteSelected');
// }
//}
$ax.messageCenter.addMessageListener(function (message, data) {
//If annotation toggle message received from sitemap, toggle footnotes
if(message == 'toggleSelectWidgetNote') {
if (!IOS) {
$('.widgetNoteSelected').removeClass('widgetNoteSelected');
}
if(!data.value) return;
//if(lastSelectedWidgetNote == data.id) {
// lastSelectedWidgetNote = null;
// return;
//}
$ax('*').each(function(obj, elementId) {
if (obj.id == data.id) {
if (!IOS) {
$('#' + elementId).addClass('widgetNoteSelected');
}
_scrollToSelectedNote($('#' + elementId), data.view);
}
});
}
});
var _scrollToSelectedNote = function ($elmt, view) {
var isLandscape = IOS ? window.orientation != 0 && window.orientation != 180 : false;
var winWidth = !IOS ? $(window).width() : (isLandscape ? window.screen.height : window.screen.width) - view.panelWidthOffset;
var winHeight = !IOS ? $(window).height() : view.height;
var docLeft = $('html').last().scrollLeft();
var docTop = $('html').last().scrollTop();
var docRight = docLeft + winWidth;
var docBottom = docTop + winHeight;
var scale = $('#base').css('transform');;
scale = (scale == "none") ? 1 : Number(scale.substring(scale.indexOf('(') + 1, scale.indexOf(',')));
var bodyLeft = ($('body').css('left') !== undefined && $('body').css('left') !== "auto") ? Number($('body').css('left').replace('px','')) : 0;
var top = scale * Number($elmt.css('top').replace('px', ''));
var bottom = top + scale * $elmt.height();
var left = scale * Number($elmt.css('left').replace('px', '')) + bodyLeft;
var right = left + scale * $elmt.width();
var doHorizontalMove = left < docLeft || right > docRight;
var doVerticalMove = top < docTop || bottom > docBottom;
var padding = scale * 50;
var newScrollLeft = 0
if (left < docLeft) {
newScrollLeft = left - padding;
} else if (right > docRight) {
newScrollLeft = right + padding - winWidth;
}
var newScrollTop = 0
if (top < docTop) {
newScrollTop = top - padding;
} else if (bottom > docBottom) {
newScrollTop = bottom + padding - winHeight;
}
// Device Frame or Scale to width or Scale to fit (situations where there is no horizontal scroll)
if (view.h || view.scaleVal == 1 || view.scaleVal == 2) {
doHorizontalMove = false;
}
// Has Device Frame or Scale to Width and widget with note is outside of viewable panel right bounds
if ((view.scaleVal == 1 || view.h) && (left > docRight)) {
doVerticalMove = false;
}
// TODO: need to do something for dynamic panel with scroll
if (doHorizontalMove && doVerticalMove) {
$("html, body").animate({ scrollLeft: newScrollLeft, scrollTop: newScrollTop }, 300);
} else if (doHorizontalMove) {
$("html, body").animate({ scrollLeft: newScrollLeft }, 300);
} else if (doVerticalMove) {
$("html, body").animate({ scrollTop: newScrollTop }, 300);
}
}
var highlightEnabled = false;
$ax.messageCenter.addMessageListener(function(message, data) {
if(message == 'highlightInteractive') {
highlightEnabled = data == true;
_applyHighlight($ax('*'));
}
});
var _applyHighlight = $ax.applyHighlight = function(query, ignoreUnset) {
if(ignoreUnset && !highlightEnabled) return;
var pulsateClassName = 'legacyPulsateBorder';
//Determine if the widget has a defined userTriggeredEventName specified in the array above
var _isInteractive = function(diagramObject) {
if(diagramObject && diagramObject.interactionMap) {
for(var index in userTriggeredEventNames) {
if(diagramObject.interactionMap[userTriggeredEventNames[index]]) return true;
}
}
return false;
};
//Traverse through parent layers (if any) of an element and see if any have a defined userTriggeredEventName
var _findMatchInParent = function(id) {
var parents = $ax('#' + id).getParents(true, ['layer'])[0];
for(var i in parents) {
var parentId = parents[i];
var parentObj = $ax.getObjectFromScriptId(parentId);
if(_isInteractive(parentObj)) return true;
}
return false;
};
//Find all widgets with a defined userTriggeredEventName specified in the array above
var $matchingElements = query.filter(function (obj, id) {
//This prevents the top left corner of the page from highlighting with everything else
if($ax.public.fn.IsLayer(obj.type)) return false;
if(_isInteractive(obj)) return true;
else if($ax.public.fn.IsVector(obj.type) && obj.referencePageUrl) return true;
//Last check on the object's parent layer(s), if a layer has a defined userTriggeredEventName
//then we shall highlight each member of that layer TODO This is a design decision and is subject to change
return _findMatchInParent(id);
}).$();
var isHighlighted = $matchingElements.is('.' + pulsateClassName);
//Toggle the pulsate class on the matched elements
if(highlightEnabled && !isHighlighted) {
$matchingElements.addClass(pulsateClassName);
} else if(!highlightEnabled && isHighlighted) {
$matchingElements.removeClass(pulsateClassName);
}
};
var getElementsFromPoint = function (x, y) {
var elementsFromPointFn = document.elementsFromPoint || document.msElementsFromPoint;
if (typeof elementsFromPointFn === "function") {
return elementsFromPointFn.bind(document)(x, y);
}
return [];
}
$axure.getIdAndRectAtLoc = function (data) {
var element = document.elementFromPoint(data.x, data.y);
if (!element) return undefined;
var jObj = _getElementIdFromTarget(element);
if (jObj.length > 0) {
var id = jObj.attr('id');
var axObj = $ax('#' + id);
var rect = axObj.pageBoundingRect();
return { 'id': id, 'rect': rect };
}
return undefined;
}
$axure.getListOfIdAndRectAtLoc = function (data) {
var domElements = getElementsFromPoint(data.x, data.y);
if (!domElements || !domElements.length) return [];
const elements = [];
domElements.forEach(function (domElement) {
var jObj = _getElementIdFromTarget(domElement);
if (jObj.length > 0) {
var id = jObj.attr('id');
var axObj = $ax('#' + id);
var rect = axObj.pageBoundingRect();
if (elements.findIndex(function (x) { return x.id === id }) < 0) {
elements.push( { 'id': id, 'rect': rect } );
}
}
});
return elements;
}
$axure.getIdRectAndStyleAtLoc = function(data) {
var element = document.elementFromPoint(data.x, data.y);
if (!element) return undefined;
var jObj = _getElementIdFromTarget(element);
if (jObj.length > 0) {
var id = jObj.attr('id');
return $axure.getRectAndStyleById(id);
}
return undefined;
}
$axure.getListOfIdRectAndStyleAtLoc = function(data) {
var domElements = getElementsFromPoint(data.x, data.y);
if (!domElements || !domElements.length) return [];
const elements = [];
domElements.forEach(function (domElement) {
var jObj = _getElementIdFromTarget(domElement);
if (jObj.length > 0) {
var id = jObj.attr('id');
if (elements.findIndex(function (x) { return x.id === id }) < 0) {
elements.push($axure.getRectAndStyleById(id));
}
}
});
return elements;
}
$axure.getRectAndStyleById = function (id) {
var axObj = $ax('#' + id);
var rect = axObj.pageBoundingRect();
var style = $ax.style.computeFullStyle(id, $ax.style.generateState(id), $ax.adaptive.currentViewId);
style.text = axObj.text();
return { 'id': id, 'rect': rect, 'style': style };
}
$axure.isIdVisible = function (id) {
return id ? $ax.visibility.IsIdVisible(id) : false;
}
$axure.getParentElementById = function (elementId) {
if (!elementId) return undefined;
var parentId = $ax.getLayerParentFromElementId(elementId);
if (!parentId) {
return undefined;
}
return $axure.getRectAndStyleById(parentId);
}
var _getElementIdFromTarget = function (target) {
var targetId = target.id;
var jTarget = $(target);
while((!targetId || targetId.indexOf('cache') > -1) && jTarget[0].tagName != 'HTML') {
jTarget = jTarget.parent();
targetId = jTarget.attr('id');
}
if(targetId && targetId != 'base') {
var sections = targetId.split('_');
return $('#' + sections[0]);
}
return '';
}
});

1315
web/main/static/resources/scripts/axure/visibility.js

File diff suppressed because it is too large

48
web/main/static/resources/scripts/base.js

@ -37,11 +37,57 @@ function set_select_data(select_ele_id,datas){
//设定选项选中状态
function set_select_selct(select_ele_id,option_str){
let bfind = false;
const select_Ele = document.getElementById(select_ele_id);
for(let i=0;i< select_Ele.options.length;i++){
if(select_Ele.options[i].value === option_str){
select_Ele.options[i].selected = true;
bfind = true;
break;
}
}
}
return bfind;
}
//将输入框内容转换为单精度型,若转换失败则返回0 -- 若需要整型,parseInt
function getInputValueAsFloat(id) {
var value = document.getElementById(id).value;
return value ? parseFloat(value) : 0;
}
//正则匹配IP是否合法 return true,false
function isValidIP(ip) {
const ipRegex = /^(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)\.(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)\.(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)\.(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)$/;
return ipRegex.test(ip);
}
//post提交JSON数据
function postJson(url,data){
}
//post提交From数据 -- 返回数据是JSON
function postFrom(url,data){
fetch(url, {
method: 'POST',
body: data,
})
.then(response => response.json())
.then(data => {
const istatus = data.status;
alert(data.msg);
if(istatus == 1 ){
fetchModelData();
$('#updateMM').modal('hide');
}
})
.catch(error => {
console.error('Error:', error);
alert('升级失败,请重试。');
btn.disabled = false;
});
}
//get请求数据
function getDATA(url){
}

375
web/main/static/resources/scripts/channel_manager.js

@ -20,28 +20,28 @@ let check_area = 0;
let draw_status = false; //是否是绘制状态,处于绘制状态才能开始绘制
let b_img = false; //有没有加载图片成功,如果没有初始化的时候就不绘制线条了。
let points = [];
//布防计划
document.addEventListener('DOMContentLoaded', function () {
fetchChannelData(); //初始化页面元素数据
fetchChannelData(); //初始化通道管理页面元素数据
document.getElementById('searchButton').addEventListener('click', function () {
performSearch();
});
//新增通道
//新增通道模块--保存按钮
document.getElementById('saveButton').addEventListener('click', function () {
addChannel(1);
});
//修改通道
//修改通道模块--保存按钮
document.getElementById('saveButton_cc').addEventListener('click', function () {
addChannel(2);
});
//算法配置
//算法配置模块--取消按钮
document.getElementById('cancelButton_mx').addEventListener('click', function () {
close_mx_model();
});
//保存算法配置
//保存算法配置--保存按钮
document.getElementById('saveButton_mx').addEventListener('click', function () {
save_mx_model();
});
@ -57,25 +57,28 @@ function addChannel(itype) {
let cName;
let Rtsp;
let cid;
const spinnerOverlay = document.getElementById("spinnerOverlay");
let saveButton = null;
let CNameInput = null;
let RTSPInput = null;
if(itype ==1){
const saveButton = document.getElementById('saveButton');
const CNameInput = document.getElementById('CNameInput');
const RTSPInput = document.getElementById('RTSPInput');
saveButton = document.getElementById('saveButton');
CNameInput = document.getElementById('CNameInput');
RTSPInput = document.getElementById('RTSPInput');
area = document.getElementById('areaSelect_M').value;
cName = CNameInput.value.trim();
Rtsp = RTSPInput.value.trim();
cid = -1
}
else if(itype ==2){
const saveButton = document.getElementById('saveButton_cc');
const CNameInput = document.getElementById('CNameInput_cc');
const RTSPInput = document.getElementById('RTSPInput_cc');
saveButton = document.getElementById('saveButton_cc');
CNameInput = document.getElementById('CNameInput_cc');
RTSPInput = document.getElementById('RTSPInput_cc');
area = document.getElementById('areaSelect_CC').value;
cName = CNameInput.value.trim();
Rtsp = RTSPInput.value.trim();
cid = currentEditingRow.cells[0].innerText;
}
console.log("点击了保存按钮");
cName = CNameInput.value.trim();
Rtsp = RTSPInput.value.trim();
if(area === "请选择"){
alert('请选择所属区域');
}
@ -85,6 +88,8 @@ function addChannel(itype) {
//发送视频链接接口
const url = '/api/channel/add';
const data = {"area":area,"cName":cName,"Rtsp":Rtsp,"cid":cid};
// 显示 Spinners
spinnerOverlay.style.display = "flex";
// 发送 POST 请求
fetch(url, {
method: 'POST', // 指定请求方法为 POST
@ -96,27 +101,19 @@ function addChannel(itype) {
.then(response => response.json()) // 将响应解析为 JSON
.then(data => {
const istatus = data.status;
if(istatus === 0){
alert(data.msg); // 使用 Modal 显示消息
// 启用保存按钮
saveButton.disabled = false;
return;
}
else{
// 启用保存按钮
saveButton.disabled = false;
saveButton.disabled = false;
alert(data.msg); // 使用 Modal 显示消息
if(istatus == 1){
//刷新列表
fetchChannelData();
if(itype ==1){
//添加通道成功
$('#channelModal').modal('hide');
alert("添加通道成功!"); // 使用 Modal 显示消息
}
else if(itype==2){
//修改通道成功
currentEditingRow = null;
$('#ChangeC').modal('hide');
alert("修改通道成功!"); // 使用 Modal 显示消息
}
}
})
@ -125,6 +122,10 @@ function addChannel(itype) {
// 启用保存按钮
saveButton.disabled = false;
return;
})
.finally(()=>{
// 隐藏 Spinners
spinnerOverlay.style.display = "none";
});
} else {
alert('通道名称和RTSP地址不能为空');
@ -132,12 +133,22 @@ function addChannel(itype) {
}
}
async function fetchChannelData() { //刷新通道数据
//初始化通道管理页面元素数据
async function fetchChannelData() { //获取通道相关信息(/api/channel/list),刷新通道表格控件数据
try {
const response = await fetch(apiEndpoint);
channelData = await response.json();
channelData_bak = channelData;
renderTable(); //读取通道list接口,刷新表格
url = "/api/channel/area/list"
area_response = await fetch(url);
areaDatas = await area_response.json();
areaData = ["请选择"]; //清空下
areaDatas.forEach((area) => {
areaData.push(area.area_name)
});
renderTable(); //刷新表格
renderPagination(); //刷新分页元素
renderAreaOptions(); //所属区域下来框
} catch (error) {
@ -145,6 +156,41 @@ async function fetchChannelData() { //刷新通道数据
}
}
//刷新表单页面数据
function renderTable() {
const tableBody = document.getElementById('table-body');
tableBody.innerHTML = '';
const start = (currentPage - 1) * rowsPerPage;
const end = start + rowsPerPage;
const pageData = channelData.slice(start, end);
const surplus_count = rowsPerPage - pageData.length;
pageData.forEach((channel) => {
// if(area_name!==channel.area_name){ //这里要求区域名称一样的要在一起
// area_name = channel.area_name;
// areaData.push(area_name);
// }
const row = document.createElement('tr');
row.innerHTML = `
<td>${channel.ID}</td>
<td>${channel.area_name}</td>
<td>${channel.channel_name}</td>
<td>${channel.ulr}</td>
<td>${channel.model_name}</td>
<td>
<button class="btn btn-primary btn-sm modify-btn">修改</button>
<button class="btn btn-secondary btn-sm algorithm-btn">算法</button>
<button class="btn btn-danger btn-sm delete-btn">删除</button>
</td>
`;
tableBody.appendChild(row);
row.querySelector('.modify-btn').addEventListener('click', () => modifyChannel(row));
row.querySelector('.algorithm-btn').addEventListener('click', () => configureAlgorithm(row));
row.querySelector('.delete-btn').addEventListener('click', () => deleteChannel(row));
});
}
//关键字查询数据
async function performSearch() {
try {
@ -186,42 +232,7 @@ async function performSearch() {
}
}
//刷新表单页面数据
function renderTable() {
const tableBody = document.getElementById('table-body');
tableBody.innerHTML = '';
const start = (currentPage - 1) * rowsPerPage;
const end = start + rowsPerPage;
const pageData = channelData.slice(start, end);
const surplus_count = rowsPerPage - pageData.length;
let area_name = "";
pageData.forEach((channel) => {
if(area_name!==channel.area_name){ //这里要求区域名称一样的要在一起
area_name = channel.area_name;
areaData.push(area_name);
}
const row = document.createElement('tr');
row.innerHTML = `
<td>${channel.ID}</td>
<td>${channel.area_name}</td>
<td>${channel.channel_name}</td>
<td>${channel.ulr}</td>
<td>${channel.model_name}</td>
<td>
<button class="btn btn-primary btn-sm modify-btn">修改</button>
<button class="btn btn-secondary btn-sm algorithm-btn">算法</button>
<button class="btn btn-danger btn-sm delete-btn">删除</button>
</td>
`;
tableBody.appendChild(row);
row.querySelector('.modify-btn').addEventListener('click', () => modifyChannel(row));
row.querySelector('.algorithm-btn').addEventListener('click', () => configureAlgorithm(row));
row.querySelector('.delete-btn').addEventListener('click', () => deleteChannel(row));
});
}
//修改通道信息
//点击修改按钮,显示修改通道信息模块 --只是显示
function modifyChannel(row) {
// const cid = row.cells[0].innerText;
const areaName = row.cells[1].innerText;
@ -245,7 +256,7 @@ function modifyChannel(row) {
$('#ChangeC').modal('show');
}
//算法配置 -- 点击算法按钮
//点击算法按钮,显示算法配置模块 --只是显示
function configureAlgorithm(row) {
//获取当前行信息
currentEditingRow = row;
@ -258,8 +269,8 @@ function configureAlgorithm(row) {
b_img = false;
document.getElementById('but_hzqy').textContent = "绘制区域";
//开始初始化算法管理模块
show_channel_img(cid); //显示一帧图片 -- 获取不到图片就是黑画面
show_channel_model_schedule(cid); //显示结构化数据
show_channel_img(cid); //获取并显示一帧图片 -- 获取不到图片就是黑画面
show_channel_model_schedule(cid); //获取并显示结构化数据
//显示窗口
$('#MX_M').modal('show');
}
@ -334,14 +345,21 @@ function handleRadioClick(event) {
console.log('Selected Radio:', selectedRadio.id);
// 根据选中的单选按钮执行相应操作
if (selectedRadio.id === 'qjjc') {
console.log("points.length",points.length);
// 处理全画面生效的逻辑
if(points.length>0){
if (!confirm('已经绘制了检测区域,确认要切换到全画面生效吗?')) {
document.getElementById('zdjc').checked = true;
if(draw_status){
alert("请先结束绘制后,再切换检测方案!");
document.getElementById('zdjc').checked = true;
}
else{
// 处理全画面生效的逻辑
if(points.length>0){
if (!confirm('切换到全画面生效,将清除已绘制的区域信息,是否切换?')) {
document.getElementById('zdjc').checked = true;
}else{
points = [];
}
}
}
console.log('全画面生效');
//console.log('全画面生效');
} else if (selectedRadio.id === 'zdjc') {
// 处理指定区域的逻辑
console.log('指定区域');
@ -359,13 +377,47 @@ canvas.addEventListener('click', (event) => {
const x = (event.clientX - rect.left) * scaleX;
const y = (event.clientY - rect.top) * scaleY;
points.push({ x, y });
console.log(points);
//绘制线条
drawLines();
}
});
//初始化读取该视频通道与算法配置的相关信息 --- 这里用GET会更加贴切一些
// 绘制区域,各点连接
function drawLines() {
if(b_img){
// 清除前台画布
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 将背景画布的内容复制到前台画布上
ctx.drawImage(backgroundCanvas, 0, 0, canvas.width, canvas.height);
// 绘制点和线
ctx.strokeStyle = 'red';
ctx.lineWidth = 2;
if (points.length > 0) {
ctx.beginPath();
ctx.moveTo(points[0].x, points[0].y);
for (let i = 1; i < points.length; i++) {
ctx.lineTo(points[i].x, points[i].y);
}
// 连接最后一个点到起点
ctx.lineTo(points[0].x, points[0].y);
ctx.stroke();
}
points.forEach(point => {
ctx.beginPath();
ctx.arc(point.x, point.y, 5, 0, Math.PI * 2);
ctx.fillStyle = 'red';
ctx.fill();
});
}
}
//获取并显示该通道相关算法的结构化数据 --- 这里用GET会更加贴切一些
function show_channel_model_schedule(cid){
//发送视频链接接口
const url = '/api/channel/C2M';
@ -380,9 +432,9 @@ function show_channel_model_schedule(cid){
})
.then(response => response.json()) // 将响应解析为 JSON
.then(data => {
const m_datas = data.m_datas;
const c2m_data = data.c2m_data;
const schedule = data.schedule;
const m_datas = data.m_datas; //算法清单
const c2m_data = data.c2m_data; //该通道管理算法的相关数据,会有空的情况
const schedule = data.schedule; //布防计划
//console.log("m_datas--",m_datas);
//console.log("c2m_data--",c2m_data);
//console.log("schedule--",schedule);
@ -412,13 +464,12 @@ function show_channel_model_schedule(cid){
drawLines();
}
}
console.log("m_polygon",m_polygon);
//阈值
document.getElementById('zxyz').value = c2m_data[0].conf_thres
document.getElementById('iouyz').value = c2m_data[0].iou_thres
}
//布防计划
const days = ['一', '二', '三', '四', '五', '六','日'];
const num_days=['0','1','2','3','4','5','6']
days.forEach((day, dayIndex) => {
@ -473,40 +524,6 @@ function parseCoordStr(str) {
});
}
// 绘制区域,各点连接
function drawLines() {
if(b_img){
// 清除前台画布
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 将背景画布的内容复制到前台画布上
ctx.drawImage(backgroundCanvas, 0, 0, canvas.width, canvas.height);
// 绘制点和线
ctx.strokeStyle = 'red';
ctx.lineWidth = 2;
if (points.length > 0) {
ctx.beginPath();
ctx.moveTo(points[0].x, points[0].y);
for (let i = 1; i < points.length; i++) {
ctx.lineTo(points[i].x, points[i].y);
}
// 连接最后一个点到起点
ctx.lineTo(points[0].x, points[0].y);
ctx.stroke();
}
points.forEach(point => {
ctx.beginPath();
ctx.arc(point.x, point.y, 5, 0, Math.PI * 2);
ctx.fillStyle = 'red';
ctx.fill();
});
}
}
//关闭算法配置窗口
function close_mx_model(){
if (confirm('确定退出窗口吗?未保存的修改将丢失!')) {
@ -516,13 +533,122 @@ function close_mx_model(){
//保存算法配置窗口数据
function save_mx_model(){
//?
currentEditingRow =null;
let model_name; //算法名称
let check_area; //检测区域标识 0-全局,1-指定范围
let polygon_str; //具体的检测区域
let conf_thres; //置信阈值
let iou_thres; //iou阈值
let schedule; //布防计划
const saveButton = document.getElementById('saveButton_mx');
saveButton.disabled = true; //不可点击状态
//配置算法
model_name = document.getElementById("model_select").value;
//检测区域
if(document.getElementById('zdjc').checked){
check_area = 1;
console.log("points--",points);
if (points.length > 0){
const formattedArray = points.map(point => `(${point.x},${point.y})`);
polygon_str = `[${formattedArray.join(',')}]`;
}else{
polygon_str = "";
}
}else{
check_area = 0;
polygon_str = "";
}
//置信阈值和IOU阈值
conf_thres = getInputValueAsFloat('zxyz');
iou_thres = getInputValueAsFloat('iouyz');
//验证数据
if(model_name !== "请选择"){
console.log(model_name);
if(conf_thres <= 0 || conf_thres>=1 || iou_thres <= 0 || iou_thres>=1){
alert("阈值的有效范围是大于0,小于1;请输入正确的阈值(默认可0.5)。");
saveButton.disabled = false; //不可点击状态
return;
}
}
//布防计划
// 定义一个对象来存储数据
const scheduleData = {
'0': Array(24).fill(0),
'1': Array(24).fill(0),
'2': Array(24).fill(0),
'3': Array(24).fill(0),
'4': Array(24).fill(0),
'5': Array(24).fill(0),
'6': Array(24).fill(0)
};
// 遍历 tbody 的每一行
[...tbody.children].forEach((row, dayIndex) => {
// 获取当前行的所有单元格
const cells = row.getElementsByTagName('td');
// 遍历每一个单元格
for (let hour = 0; hour < cells.length; hour++) {
// 检查单元格的 class 是否包含 'blocked'
if (cells[hour].classList.contains('blocked')) {
// 将对应的 scheduleData 位置设置为 1
scheduleData[dayIndex][hour] = 1;
} else {
// 将对应的 scheduleData 位置设置为 0
scheduleData[dayIndex][hour] = 0;
}
}
});
// 将 scheduleData 对象转换为 JSON 字符串
const scheduleData_json = JSON.stringify(scheduleData);
//提交到服务器
// console.log("model_name--",model_name);
// console.log("check_area--",check_area);
// console.log("polygon_str--",polygon_str);
// console.log("iou_thres--",iou_thres);
// console.log("conf_thres--",conf_thres);
// console.log("schedule-- ",scheduleData_json);
cid = currentEditingRow.cells[0].innerText;
const url = '/api/channel/chanegeC2M';
const data = {"model_name":model_name,"check_area":check_area,"polygon_str":polygon_str,"iou_thres":iou_thres,
"conf_thres":conf_thres,"schedule":scheduleData_json,"cid":cid};
// 发送 POST 请求
fetch(url, {
method: 'POST', // 指定请求方法为 POST
headers: {
'Content-Type': 'application/json' // 设置请求头,告诉服务器请求体的数据类型为 JSON
},
body: JSON.stringify(data) // 将 JavaScript 对象转换为 JSON 字符串
})
.then(response => response.json()) // 将响应解析为 JSON
.then(data => {
const istatus = data.status;
if(istatus === 0){
alert(data.msg); // 使用 Modal 显示消息
// 启用保存按钮
saveButton.disabled = false;
return;
}
else{
// 启用保存按钮
saveButton.disabled = false;
//刷新列表
fetchChannelData();
//$('#MX_M').modal('hide');
alert("修改成功!");
}
})
.catch((error) => {
alert(`Error: ${error.message}`);
// 启用保存按钮
saveButton.disabled = false;
return;
});
}
//删除通道
function deleteChannel(row) {
if (confirm('确定删除此区域吗?')) {
if (confirm('确定删除此通道吗?')) {
cid = row.cells[0].innerText;
//发送视频链接接口
const url = '/api/channel/del';
@ -540,13 +666,9 @@ function deleteChannel(row) {
const istatus = data.status;
if(istatus === 0){
alert(data.msg); // 使用 Modal 显示消息
// 启用保存按钮
saveButton.disabled = false;
return;
}
else{
// 启用保存按钮
saveButton.disabled = false;
//刷新列表
row.remove();
alert("删除通道成功!");
@ -554,8 +676,6 @@ function deleteChannel(row) {
})
.catch((error) => {
alert(`Error: ${error.message}`); // 使用 Modal 显示错误信息
// 启用保存按钮
saveButton.disabled = false;
return;
});
@ -587,6 +707,11 @@ function renderAreaOptions() {
const areaSelect = document.getElementById('areaSelect');
const areaSelect_M = document.getElementById('areaSelect_M')
const areaSelect_CC = document.getElementById('areaSelect_CC')
//先清空
areaSelect.innerHTML = '';
areaSelect_M.innerHTML = '';
areaSelect_CC.innerHTML = '';
//再添加
areaData.forEach(option => {
const optionElement = document.createElement('option');
optionElement.textContent = option;

303
web/main/static/resources/scripts/model_manager.js

@ -0,0 +1,303 @@
let currentPage = 1;
const rowsPerPage = 10;
let modelData = [];
let modelData_bak = []; //用于关键字检索
let currentEditingRow = null;
//页面加载初始化
document.addEventListener('DOMContentLoaded', function () {
fetchModelData(); //初始化通道管理页面元素数据
//新增算法模态框---保存按钮
document.getElementById('saveButton_model').addEventListener('click',function () {
addModel();
});
//配置算法模态框--保存按钮
document.getElementById('saveButton_config_model').addEventListener('click',function () {
post_configureModel();
});
//升级算法模态框--保存按钮
document.getElementById('saveButton_upmodel').addEventListener('click',function () {
post_modifyModel();
});
//查询按钮
document.getElementById('searchMButton').addEventListener('click',function () {
searchModel();
});
});
//获取算法列表数据,并更新页面
async function fetchModelData() {
try{
let response = await fetch('/api/model/list');
if (!response.ok) {
throw new Error('Network response was not ok');
}
modelData = await response.json();
modelData_bak = modelData;
currentPage = 1; // 重置当前页为第一页
renderTable(); //刷新表格
renderPagination();
}catch (error) {
console.error('Error fetching model data:', error);
}
}
//刷新表单页面数据
function renderTable() {
const tableBody = document.getElementById('table-body-model');
tableBody.innerHTML = ''; //清空
const start = (currentPage - 1) * rowsPerPage;
const end = start + rowsPerPage;
const pageData = modelData.slice(start, end);
const surplus_count = rowsPerPage - pageData.length;
pageData.forEach((model) => {
const row = document.createElement('tr');
row.innerHTML = `
<td>${model.ID}</td>
<td>${model.name}</td>
<td>${model.version}</td>
<td>${model.duration_time}</td>
<td>${model.proportion}</td>
<td>
<button class="btn btn-primary btn-sm modify-btn">升级</button>
<button class="btn btn-secondary btn-sm algorithm-btn">配置</button>
<button class="btn btn-danger btn-sm delete-btn">删除</button>
</td>
`;
tableBody.appendChild(row);
row.querySelector('.modify-btn').addEventListener('click', () => modifyModel(row));
row.querySelector('.algorithm-btn').addEventListener('click', () => configureModel(row));
row.querySelector('.delete-btn').addEventListener('click', () => deleteModel(row));
});
}
//刷新分页标签
function renderPagination() {
const pagination = document.getElementById('pagination-model');
pagination.innerHTML = '';
const totalPages = Math.ceil(modelData.length / rowsPerPage);
for (let i = 1; i <= totalPages; i++) {
const pageItem = document.createElement('li');
pageItem.className = 'page-item' + (i === currentPage ? ' active' : '');
pageItem.innerHTML = `<a class="page-link" href="#">${i}</a>`;
pageItem.addEventListener('click', (event) => {
event.preventDefault();
currentPage = i;
renderTable();
renderPagination();
});
pagination.appendChild(pageItem);
}
}
//显示升级算法模态框
function modifyModel(row){
currentEditingRow = row;
model_name = row.cells[1].innerText;
version_name = row.cells[2].innerText;
document.getElementById('update_mname_label').innerText = `算法名称: ${model_name}`;
document.getElementById('update_mversion_label').innerText = `当前版本: ${version_name}`;
$('#updateMM').modal('show');
}
//升级算法模态框--点击保存按钮
function post_modifyModel(){
mid = currentEditingRow.cells[0].innerText;
const btn = document.getElementById('saveButton_upmodel');
const fileInput = document.getElementById('updateModelFile');
const file = fileInput.files[0];
if(file){
btn.disabled = true; //不可点击
const formData = new FormData();
formData.append('file', file);
formData.append('mid', mid);
fetch('/api/model/upgrade', {
method: 'POST',
body: formData,
})
.then(response => response.json())
.then(data => {
const istatus = data.status;
alert(data.msg);
btn.disabled = false;
if(istatus == 1 ){
fetchModelData();
$('#updateMM').modal('hide');
}
})
.catch(error => {
console.error('Error:', error);
alert('升级失败,请重试。');
btn.disabled = false;
});
}
else{
alert('请选择升级包进行上传。');
btn.disabled = false;
}
}
//显示配置算法模态框
function configureModel(row){
currentEditingRow = row;
model_name = row.cells[1].innerText;
duration_time = row.cells[3].innerText;
proportion = row.cells[4].innerText;
//设置模态框控件遍历
document.getElementById('config_mname_label').innerText = `算法名称: ${model_name}`;
document.getElementById('duration_timeInput').value = duration_time;
document.getElementById('proportionInput').value = proportion;
$('#configMM').modal('show');
}
//配置算法模态框--点击保存按钮
function post_configureModel(){
mid = currentEditingRow.cells[0].innerText;
duration_time = parseInt(document.getElementById('duration_timeInput').value);
proportion = parseFloat(document.getElementById('proportionInput').value);
if(isNaN(duration_time) || isNaN(proportion) ){
alert("请输入数字!");
return;
}
if(proportion<=0 || proportion>=1){
alert("占比阈值需要大于0,且小于1");
return;
}
//提交数据
const url = '/api/model/changecnf';
const data = {"mid":mid,"duration_time":duration_time,"proportion":proportion};
// 发送 POST 请求
fetch(url, {
method: 'POST', // 指定请求方法为 POST
headers: {
'Content-Type': 'application/json' // 设置请求头,告诉服务器请求体的数据类型为 JSON
},
body: JSON.stringify(data) // 将 JavaScript 对象转换为 JSON 字符串
})
.then(response => response.json()) // 将响应解析为 JSON
.then(data => {
const istatus = data.status;
if(istatus === 0){
alert(data.msg);
return;
}
else{
//刷新列表
fetchModelData();
alert(data.msg);
$('#configMM').modal('hide');
}
})
.catch((error) => {
alert(`Error: ${error.message}`);
return;
});
}
//删除算法记录
function deleteModel(row){
if (confirm('确定删除此算法吗?')) {
mid = row.cells[0].innerText;
const url = '/api/model/del';
const data = {"mid":mid};
// 发送 POST 请求
fetch(url, {
method: 'POST', // 指定请求方法为 POST
headers: {
'Content-Type': 'application/json' // 设置请求头,告诉服务器请求体的数据类型为 JSON
},
body: JSON.stringify(data) // 将 JavaScript 对象转换为 JSON 字符串
})
.then(response => response.json()) // 将响应解析为 JSON
.then(data => {
const istatus = data.status;
if(istatus === 0){
alert(data.msg);
return;
}
else{
//刷新列表
row.remove();
alert("删除算法成功!");
}
})
.catch((error) => {
alert(`Error: ${error.message}`);
return;
});
}
}
//新增算法--保存按钮
function addModel(){
const btn = document.getElementById('saveButton_model');
const fileInput = document.getElementById('uploadModelFile');
const file = fileInput.files[0];
const mName = document.getElementById('MNameInput').value;
if (file && mName) {
btn.disabled = true; //不可点击
const formData = new FormData();
formData.append('file', file);
formData.append('mName', mName);
fetch('/api/model/add', {
method: 'POST',
body: formData,
})
.then(response => response.json())
.then(data => {
const istatus = data.status;
alert(data.msg);
btn.disabled = false;
if(istatus == 1 ){
fetchModelData();
$('#addMM').modal('hide');
}
})
.catch(error => {
console.error('Error:', error);
alert('上传失败,请重试。');
btn.disabled = false;
});
} else {
alert('请填写算法名称并选择一个升级包进行上传。');
btn.disabled = false;
}
}
//关键字检索
function searchModel(){
try {
const modelName = document.getElementById('modelNameInput').value;
if(modelName===""){
modelData = modelData_bak;
}
else{
modelData = [];
modelData_bak.forEach((model) => {
if(model.name.includes(modelName)){
modelData.push(model);
}
});
}
// 渲染表格和分页控件
currentPage = 1; // 重置当前页为第一页
renderTable();
renderPagination();
} catch (error) {
console.error('Error performing search:', error);
}
}

2631
web/main/static/resources/scripts/player/axplayer.js

File diff suppressed because it is too large

18
web/main/static/resources/scripts/player/init.js

@ -1,18 +0,0 @@
(function () {
$.holdReady(true);
var script = window.document.createElement("script");
script.type = "text/javascript";
script.async = true;
script.onload = script.onreadystatechange = function (e, isAbort) {
if (isAbort || !script.readyState || /loaded|complete/.test(script.readyState)) {
script.onload = script.onreadystatechange = null;
script = undefined;
}
if (!isAbort) { $.holdReady(false); }
}
script.src = "data/document.js";
window.document.head.appendChild(script);
})();

219
web/main/static/resources/scripts/player/splitter.js

@ -1,219 +0,0 @@
/*
* jQuery.splitter.js - two-pane splitter window plugin
*
* version 1.51 (2009/01/09)
*
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*/
/**
* The splitter() plugin implements a two-pane resizable splitter window.
* The selected elements in the jQuery object are converted to a splitter;
* each selected element should have two child elements, used for the panes
* of the splitter. The plugin adds a third child element for the splitbar.
*
* For more details see: http://methvin.com/splitter/
*
*
* @example $('#MySplitter').splitter();
* @desc Create a vertical splitter with default settings
*
* @example $('#MySplitter').splitter({type: 'h', accessKey: 'M'});
* @desc Create a horizontal splitter resizable via Alt+Shift+M
*
* @name splitter
* @type jQuery
* @param Object options Options for the splitter (not required)
* @cat Plugins/Splitter
* @return jQuery
* @author Dave Methvin (dave.methvin@gmail.com)
*/
;(function($){
$.fn.splitter = function(args){
args = args || {};
return this.each(function() {
var zombie; // left-behind splitbar for outline resizes
function startSplitMouse(evt) {
if ( opts.outline )
zombie = zombie || bar.clone(false).insertAfter(A);
panes.css("-webkit-user-select", "none"); // Safari selects A/B text on a move
bar.addClass(opts.activeClass);
$('<div class="splitterMask"></div>').insertAfter(bar);
A._posSplit = A[0][opts.pxSplit] - evt[opts.eventPos];
$(document)
.bind("mousemove", doSplitMouse)
.bind("mouseup", endSplitMouse);
}
function doSplitMouse(evt) {
var newPos = A._posSplit+evt[opts.eventPos];
if ( opts.outline ) {
newPos = Math.max(0, Math.min(newPos, splitter._DA - bar._DA));
bar.css(opts.origin, newPos);
} else
resplit(newPos);
}
function endSplitMouse(evt) {
$('div.splitterMask').remove();
bar.removeClass(opts.activeClass);
var newPos = A._posSplit+evt[opts.eventPos];
if ( opts.outline ) {
zombie.remove(); zombie = null;
resplit(newPos);
}
panes.css("-webkit-user-select", "text"); // let Safari select text again
$(document)
.unbind("mousemove", doSplitMouse)
.unbind("mouseup", endSplitMouse);
}
function resplit(newPos) {
// Constrain new splitbar position to fit pane size limits
newPos = Math.max(A._min, splitter._DA - B._max,
Math.min(newPos, A._max, splitter._DA - bar._DA - B._min));
// Resize/position the two panes
bar._DA = bar[0][opts.pxSplit]; // bar size may change during dock
var posOffset = bar.is(':visible') ? bar._DA - 1 : 0;
bar.css(opts.origin, newPos - posOffset).css(opts.fixed, splitter._DF);
A.css(opts.origin, 0).css(opts.split, newPos).css(opts.fixed, splitter._DF);
B.css(opts.origin, newPos + bar._DA - posOffset)
.css(opts.split, splitter._DA-bar._DA-newPos).css(opts.fixed, splitter._DF);
// IE fires resize for us; all others pay cash
if ( !IE_10_AND_BELOW )
panes.trigger("resize");
}
function dimSum(jq, dims) {
// Opera returns -1 for missing min/max width, turn into 0
var sum = 0;
for ( var i=1; i < arguments.length; i++ )
sum += Math.max(parseInt(jq.css(arguments[i])) || 0, 0);
return sum;
}
// Determine settings based on incoming opts, element classes, and defaults
var vh = (args.splitHorizontal? 'h' : args.splitVertical? 'v' : args.type) || 'v';
var opts = $.extend({
activeClass: 'active', // class name for active splitter
pxPerKey: 8, // splitter px moved per keypress
tabIndex: 0, // tab order indicator
accessKey: '' // accessKey for splitbar
},{
v: { // Vertical splitters:
keyLeft: 39, keyRight: 37, cursor: "col-resize",
splitbarClass: "vsplitbar", outlineClass: "voutline",
type: 'v', eventPos: "pageX", origin: "left",
split: "width", pxSplit: "offsetWidth", side1: "Left", side2: "Right",
fixed: "height", pxFixed: "offsetHeight", side3: "Top", side4: "Bottom"
},
h: { // Horizontal splitters:
keyTop: 40, keyBottom: 38, cursor: "row-resize",
splitbarClass: "hsplitbar", outlineClass: "houtline",
type: 'h', eventPos: "pageY", origin: "top",
split: "height", pxSplit: "offsetHeight", side1: "Top", side2: "Bottom",
fixed: "width", pxFixed: "offsetWidth", side3: "Left", side4: "Right"
}
}[vh], args);
// Create jQuery object closures for splitter and both panes
var splitter = $(this).css({position: "relative"});
var panes = $(">*", splitter[0]).css({
position: "absolute", // positioned inside splitter container
"z-index": "1", // splitbar is positioned above
"-moz-outline-style": "none" // don't show dotted outline
});
var A = $(panes[0]); // left or top
var B = $(panes[1]); // right or bottom
// Focuser element, provides keyboard support; title is shown by Opera accessKeys
var focuser = $('<a href="javascript:void(0)"></a>')
.attr({accessKey: opts.accessKey, tabIndex: opts.tabIndex, title: opts.splitbarClass})
//.bind($.browser.opera?"click":"focus", function(){ this.focus(); bar.addClass(opts.activeClass) })
.bind("focus", function () { this.focus(); bar.addClass(opts.activeClass) })
.bind("keydown", function(e){
var key = e.which || e.keyCode;
var dir = key==opts["key"+opts.side1]? 1 : key==opts["key"+opts.side2]? -1 : 0;
if ( dir )
resplit(A[0][opts.pxSplit]+dir*opts.pxPerKey, false);
})
.bind("blur", function(){ bar.removeClass(opts.activeClass) });
// Splitbar element, can be already in the doc or we create one
var bar = $(panes[2] || '<div></div>')
.insertAfter(A).css("z-index", "100").append(focuser)
.attr({"class": opts.splitbarClass, unselectable: "on"})
.css({position: "absolute", "user-select": "none", "-webkit-user-select": "none",
"-khtml-user-select": "none", "-moz-user-select": "none", "top": "0px"})
.bind("mousedown", startSplitMouse);
// Use our cursor unless the style specifies a non-default cursor
if ( /^(auto|default|)$/.test(bar.css("cursor")) )
bar.css("cursor", opts.cursor);
// Cache several dimensions for speed, rather than re-querying constantly
bar._DA = bar[0][opts.pxSplit];
splitter._PBF = $.boxModel? dimSum(splitter, "border"+opts.side3+"Width", "border"+opts.side4+"Width") : 0;
splitter._PBA = $.boxModel? dimSum(splitter, "border"+opts.side1+"Width", "border"+opts.side2+"Width") : 0;
A._pane = opts.side1;
B._pane = opts.side2;
$.each([A,B], function(){
this._min = opts["min"+this._pane] || dimSum(this, "min-"+opts.split);
this._max = opts["max"+this._pane] || dimSum(this, "max-"+opts.split) || 9999;
this._init = opts["size"+this._pane]===true ?
parseInt($.curCSS(this[0],opts.split)) : opts["size"+this._pane];
});
// Determine initial position, get from cookie if specified
var initPos = A._init;
if ( !isNaN(B._init) ) // recalc initial B size as an offset from the top or left side
initPos = splitter[0][opts.pxSplit] - splitter._PBA - B._init - bar._DA;
if ( opts.cookie ) {
if ( !$.cookie )
alert('jQuery.splitter(): jQuery cookie plugin required');
var ckpos = parseInt($.cookie(opts.cookie));
if ( !isNaN(ckpos) )
initPos = ckpos;
$(window).bind("unload", function(){
var state = String(bar.css(opts.origin)); // current location of splitbar
$.cookie(opts.cookie, state, {expires: opts.cookieExpires || 365,
path: opts.cookiePath || document.location.pathname});
});
}
if ( isNaN(initPos) ) // King Solomon's algorithm
initPos = Math.round((splitter[0][opts.pxSplit] - splitter._PBA - bar._DA)/2);
// Resize event propagation and splitter sizing
if ( opts.anchorToWindow ) {
// Account for margin or border on the splitter container and enforce min height
splitter._hadjust = dimSum(splitter, "borderTopWidth", "borderBottomWidth", "marginBottom");
splitter._hmin = Math.max(dimSum(splitter, "minHeight"), 20);
$(window).bind("resize", function(){
var top = splitter.offset().top;
var wh = $(window).height();
splitter.css("height", Math.max(wh-top-splitter._hadjust, splitter._hmin)+"px");
if ( !IE_10_AND_BELOW ) splitter.trigger("resize");
}).trigger("resize");
}
else if ( opts.resizeToWidth && !IE_10_AND_BELOW )
$(window).bind("resize", function(){
splitter.trigger("resize");
});
// Resize event handler; triggered immediately to set initial position
splitter.bind("resize", function(e, size){
// Custom events bubble in jQuery 1.3; don't Yo Dawg
if ( e.target != this ) return;
// Determine new width/height of splitter container
splitter._DF = splitter[0][opts.pxFixed] - splitter._PBF;
splitter._DA = splitter[0][opts.pxSplit] - splitter._PBA;
// Bail if splitter isn't visible or content isn't there yet
if ( splitter._DF <= 0 || splitter._DA <= 0 ) return;
// Re-divvy the adjustable dimension; maintain size of the preferred pane
resplit(!isNaN(size)? size : (!(opts.sizeRight||opts.sizeBottom)? A[0][opts.pxSplit] :
splitter._DA-B[0][opts.pxSplit]-bar._DA));
}).trigger("resize" , [initPos]);
});
};
})(jQuery);

440
web/main/static/resources/scripts/system_manager.js

@ -0,0 +1,440 @@
let currentPage = 1;
const rowsPerPage = 10;
let currentEditingRow = null;
let areaData = [];
let areaData_bak = [];
//网络信息
let wired_type;
let wired_ip;
let wired_mask;
let wired_gateway;
let wired_dns;
let wireless_type;
let wireless_ip;
let wireless_mask;
let wireless_gateway;
let wireless_dns;
let wireless_ssid;
let wireless_passwd;
let wifi_list = [];
//页面加载初始化
document.addEventListener('DOMContentLoaded', function () {
fetchSystemData(); //初始化系统信息
fetchAreaData();//初始化区域信息
//升级按钮
document.getElementById('upsystem').addEventListener('click',function () {upgrade_system();});
//设备IP配置按钮--显示模态框
document.getElementById('showIPConfig').addEventListener('click',function () {show_IPConfigModel();});
//设备IP配置模态框--保存按钮
document.getElementById('saveIPConfig').addEventListener('click',function () {save_IPConfig();});
document.getElementById('connectWifi').addEventListener('click',function () {connect_wifi();});
//服务器IP配置
document.getElementById('showServerIP').addEventListener('click',function () {show_ServerIPConfig();});
document.getElementById('saveServerIP').addEventListener('click',function () {save_ServerIPConfig();});
//区域管理
document.getElementById('addAreaButton').addEventListener('click',function () {show_AreaManager();});
document.getElementById('addArea').addEventListener('click',function () {add_Area();});
//修改区域模态框
document.getElementById('modifArea').addEventListener('click',function () {modify_Area();});
});
//刷新系统信息
async function fetchSystemData() {
try{
let response = await fetch('/api/system/info');
if (!response.ok) {
throw new Error('Network response was not ok');
}
data = await response.json();
document.getElementById('system_version').textContent = data.version;
document.getElementById('dev_ID').textContent = data.ID;
document.getElementById('service_ip').value = data.service_ip;
document.getElementById('service_port').value = data.service_port;
//网络信息
wired_type = data.wired_type;
wired_ip = data.wired_ip;
wired_mask = data.wired_mask;
wired_gateway = data.wired_gateway;
wired_dns = data.wired_dns;
wireless_type = data.wireless_type;
wireless_ip = data.wireless_ip;
wireless_mask = data.wireless_mask;
wireless_gateway = data.wireless_gateway;
wireless_dns = data.wireless_dns;
wireless_ssid = data.ssid;
wireless_passwd = data.wifi_passwd;
//wifi -list
wifi_list = data.wifi_list;
wifi_list.unshift("请选择");
document.getElementById('dev_IP').textContent = `有线--${wired_ip} 无线--${wireless_ip}`;
}catch (error) {
console.error('Error fetching model data:', error);
}
}
//刷新区域信息--
async function fetchAreaData() {
try{
let response = await fetch('/api/system/area');
if (!response.ok) {
throw new Error('Network response was not ok');
}
areaData = await response.json();
areaData_bak = areaData;
currentPage = 1; // 重置当前页为第一页
renderTable(); //刷新表格
renderPagination();
}catch (error) {
console.error('Error fetching model data:', error);
}
}
//刷新表格
function renderTable(){
const tableBody = document.getElementById('table-body-area');
tableBody.innerHTML = '';
const start = (currentPage - 1) * rowsPerPage;
const end = start + rowsPerPage;
const pageData = areaData.slice(start, end);
const surplus_count = rowsPerPage - pageData.length;
pageData.forEach((area) => {
const row = document.createElement('tr');
row.innerHTML = `
<td>${area.ID}</td>
<td>${area.area_name}</td>
<td>
<button class="btn btn-primary btn-sm modify-btn">修改</button>
<button class="btn btn-danger btn-sm delete-btn">删除</button>
</td>
`;
tableBody.appendChild(row);
row.querySelector('.modify-btn').addEventListener('click', () => show_modify_Area(row));
row.querySelector('.delete-btn').addEventListener('click', () => del_Area(row));
});
}
//刷新分页标签
function renderPagination() {
const pagination = document.getElementById('pagination-area');
pagination.innerHTML = '';
const totalPages = Math.ceil(areaData.length / rowsPerPage);
for (let i = 1; i <= totalPages; i++) {
const pageItem = document.createElement('li');
pageItem.className = 'page-item' + (i === currentPage ? ' active' : '');
pageItem.innerHTML = `<a class="page-link" href="#">${i}</a>`;
pageItem.addEventListener('click', (event) => {
event.preventDefault();
currentPage = i;
renderTable();
renderPagination();
});
pagination.appendChild(pageItem);
}
}
//系统升级
async function upgrade_system(){
alert("点击了系统升级按钮");
}
//设备IP地址配置 --- 显示模态框---------------------
function show_IPConfigModel(){
//wired页面
const el_wired_dhcp = document.getElementById('dhcp_lan');
const el_wired_static = document.getElementById('static_lan');
const el_wired_ip = document.getElementById('wiredIpAddress');
const el_wired_mask = document.getElementById('wiredSubnetMask');
const el_wired_gateway = document.getElementById('wiredGateway');
const el_wired_dns = document.getElementById('wiredDNS');
if(wired_type==0){ //dhcp
el_wired_dhcp.checked = true;
}else{
el_wired_static.checked = true;
}
el_wired_ip.value = wired_ip;
el_wired_mask.value = wired_mask;
el_wired_gateway.value = wired_gateway;
el_wired_dns.value = wired_dns;
//wireless页面
//document.getElementById('wirelessNetwork');
const el_wireless_passwd = document.getElementById('wifi_passwd');
const el_wireless_dhcp = document.getElementById('dhcp_wifi');
const el_wireless_static = document.getElementById('static_wifi');
const el_wireless_ip = document.getElementById('wirelessIpAddress');
const el_wireless_mask = document.getElementById('wirelessSubnetMask');
const el_wireless_gateway = document.getElementById('wirelessGateway');
const el_wireless_dns = document.getElementById('wirelessDNS');
//wireless_ssid = data.ssid;
//wireless_passwd = data.wifi_passwd;
if(wired_type==0){ //dhcp
el_wireless_dhcp.checked = true;
}else{
el_wireless_static.checked = true;
}
set_select_data("wirelessNetwork",wifi_list);
if(wireless_ssid == null || wireless_ssid == ""){
//控件不可操作
el_wireless_dhcp.disabled=true;
el_wireless_static.disabled=true;
el_wireless_ip.disabled=true;
el_wireless_mask.disabled=true;
el_wireless_gateway.disabled=true;
el_wireless_dns.disabled=true;
}else{
let bfind = set_select_selct("wirelessNetwork",wireless_ssid);
if(bfind== false){
el_wireless_dhcp.disabled=true;
el_wireless_static.disabled=true;
el_wireless_ip.disabled=true;
el_wireless_mask.disabled=true;
el_wireless_gateway.disabled=true;
el_wireless_dns.disabled=true;
}else{
el_wireless_passwd.value = wireless_passwd;
el_wireless_ip.value = wireless_ip;
el_wireless_mask.value = wireless_mask;
el_wireless_gateway.value = wireless_gateway;
el_wireless_dns.value = wireless_dns;
}
}
$('#ipConfigModal').modal('show');
}
//点击连接wifi 按钮
async function connect_wifi(){
alert("点击了连接wifi按钮");
}
//设备IP地址配置 --- 点击保存按钮
async function save_IPConfig(){
alert("点击了设备IP保存按钮");
}
//IP配置模态框,单选按钮点击
function handleRadioClick_lan(event){
const selectedRadio = event.target;
const el_ip = document.getElementById('wiredIpAddress');
const el_mask = document.getElementById('wiredSubnetMask');
const el_gateway = document.getElementById('wiredGateway');
const el_dns = document.getElementById('wiredDNS');
let net_type = 0; //0--dhcp,1--static
if (selectedRadio.id === 'dhcp_lan') {
net_type = 1;
el_ip.disabled = true;
el_mask.disabled = true;
el_gateway.disabled = true;
el_dns.disabled = true;
}
else if(selectedRadio.id === 'static_lan'){
net_type = 2;
el_ip.disabled = false;
el_mask.disabled = false;
el_gateway.disabled = false;
el_dns.disabled = false;
}
}
//IP配置模态框,单选按钮点击
function handleRadioClick_wifi(event){
const selectedRadio = event.target;
let wifi_type = 0; //0--dhcp,1--static
const el_ip = document.getElementById('wirelessIpAddress');
const el_mask = document.getElementById('wirelessSubnetMask');
const el_gateway = document.getElementById('wirelessGateway');
const el_dns = document.getElementById('wirelessDNS');
if (selectedRadio.id === 'dhcp_wifi') {
net_type = 1;
el_ip.disabled = true;
el_mask.disabled = true;
el_gateway.disabled = true;
el_dns.disabled = true;
}
else if(selectedRadio.id === 'static_wifi'){
net_type = 2;
el_ip.disabled = false;
el_mask.disabled = false;
el_gateway.disabled = false;
el_dns.disabled = false;
}
}
//服务器IP配置-----------------------------------------
function show_ServerIPConfig(){
const el_serviceIP = document.getElementById('serviceIP_model');
const el_servicePort = document.getElementById('servicePort_model');
el_serviceIP.value = document.getElementById('service_ip').value;
el_servicePort.value = document.getElementById('service_port').value;
$('#ServerIPModal').modal('show');
}
async function save_ServerIPConfig(){
const el_serverIP = document.getElementById('serviceIP_model');
const el_serverPort = document.getElementById('servicePort_model');
const btn = document.getElementById('saveServerIP');
serverIP = el_serverIP.value;
serverPort = el_serverPort.value;
if(serverIP==="" || serverPort===""){
alert("服务端IP和端口号不能为空!")
}
else{
if(isValidIP(serverIP)){
btn.disabled = true;
const formData = new FormData();
formData.append('ip', serverIP);
formData.append('port', serverPort);
fetch("/api/system/changeserver", {
method: 'POST',
body: formData,
})
.then(response => response.json())
.then(data => {
btn.disabled = false;
const istatus = data.status;
alert(data.msg);
if(istatus == 1){
fetchSystemData();
$('#ServerIPModal').modal('hide');
}
})
.catch(error => {
console.error('Error:', error);
alert('修改失败,请重试。');
btn.disabled = false;
});
}
else{
alert("请输入正确的IP地址!")
}
}
}
//区域管理-------------------------------------------
function show_AreaManager(){
$('#addAreaModal').modal('show');
}
async function add_Area(){
const el_ereaname = document.getElementById('area_name');
const btn = document.getElementById('addArea');
area_name = el_ereaname.value;
if(area_name===""){
alert("请输入区域名称");
}else{
btn.disabled = true;
//提交数据
const url = '/api/channel/area/add';
const data = {"name":area_name};
// 发送 POST 请求
fetch(url, {
method: 'POST', // 指定请求方法为 POST
headers: {
'Content-Type': 'application/json' // 设置请求头,告诉服务器请求体的数据类型为 JSON
},
body: JSON.stringify(data) // 将 JavaScript 对象转换为 JSON 字符串
})
.then(response => response.json()) // 将响应解析为 JSON
.then(data => {
btn.disabled = false;
const istatus = data.status;
alert(data.msg);
if(istatus == 1){
fetchAreaData();
$('#addAreaModal').modal('hide');
}
})
.catch((error) => {
alert(`Error: ${error.message}`);
btn.disabled = false;
});
}
}
//显示修改区域信息
function show_modify_Area(row){
currentEditingRow = row;
area_name = row.cells[1].innerText;
const el_areaname = document.getElementById('area_name_modif');
el_areaname.value = area_name;
$('#modifyAreaModal').modal('show');
}
//点击修改模态框的保存按钮
async function modify_Area(){
area_id = currentEditingRow.cells[0].innerText;
area_name = document.getElementById('area_name_modif').value;
const btn = document.getElementById('modifArea');
if(area_name===""){
alert("请输入区域名称!")
}else{
btn.disabled = true;
//提交数据
const url = '/api/channel/area/change';
const formData = new FormData();
formData.append('name', area_name);
formData.append('id', area_id);
//const data = {"name":area_name,"id":area_id};
// 发送 POST 请求
fetch(url, {
method: 'POST',
body: formData,
})
.then(response => response.json()) // 将响应解析为 JSON
.then(data => {
btn.disabled = false;
const istatus = data.status;
alert(data.msg);
if(istatus == 1){
fetchAreaData();
$('#modifyAreaModal').modal('hide');
}
})
.catch((error) => {
alert(`Error: ${error.message}`);
btn.disabled = false;
});
}
}
//删除区域信息
async function del_Area(row){
if (confirm('确定删除此区域吗?')){
currentEditingRow = row;
area_id =row.cells[0].innerText;
const url = '/api/channel/area/del';
const formData = new FormData();
formData.append('id', area_id);
//const data = {"name":area_name,"id":area_id};
// 发送 POST 请求
fetch(url, {
method: 'POST',
body: formData,
})
.then(response => response.json()) // 将响应解析为 JSON
.then(data => {
const istatus = data.status;
alert(data.msg);
if(istatus == 1){
//刷新列表
row.remove();
}
})
.catch((error) => {
alert(`Error: ${error.message}`);
btn.disabled = false;
});
}
}

48
web/main/static/resources/scripts/user_manager.js

@ -0,0 +1,48 @@
document.getElementById('changePasswd').addEventListener('click',function () {
changePasswd();
});
function changePasswd(){
const el_oldpasswd = document.getElementById('source_passwd');
const el_new_passwd = document.getElementById('new_passwd');
const el_again_passwd = document.getElementById('again_passwd');
const btn = document.getElementById('changePasswd');
oldpasswd = el_oldpasswd.value;
newpasswd = el_new_passwd.value;
againpasswd = el_again_passwd.value;
if(oldpasswd === "" || newpasswd === "" || againpasswd === ""){
alert("密码不能为空!")
}else{
if(newpasswd !== againpasswd){
alert("两次输入的密码不相同!")
}else{
btn.disabled = true;
//提交请求
const url = "/api/user/passwd"
const data = {"oldpasswd":oldpasswd,"newpasswd":newpasswd};
fetch(url, {
method: 'POST', // 指定请求方法为 POST
headers: {
'Content-Type': 'application/json' // 设置请求头,告诉服务器请求体的数据类型为 JSON
},
body: JSON.stringify(data) // 将 JavaScript 对象转换为 JSON 字符串
})
.then(response => response.json()) // 将响应解析为 JSON
.then(data => {
btn.disabled = false;
const istatus = data.status;
alert(data.msg);
if(istatus == 1){
el_oldpasswd.value = "";
el_new_passwd.value = "";
el_again_passwd.value = "";
}
})
.catch((error) => {
btn.disabled = false;
alert(`Error: ${error.message}`);
return;
});
}
}
}

32
web/main/templates/base.html

@ -11,6 +11,31 @@
vertical-align: -.125em;
fill: currentColor;
}
.form-label {
font-weight: bold;
font-size: 1.2rem;
}
.form-group {
margin-bottom: 1rem;
}
#spinnerOverlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(255, 255, 255, 0.7); /* 半透明的背景 */
display: flex;
justify-content: center;
align-items: center;
z-index: 1060; /* 确保在最上层显示 */
}
/* 确保 Spinners 的大小合适 */
#spinnerOverlay .spinner-border {
width: 3rem;
height: 3rem;
}
{% block style %}{% endblock %}
</style>
@ -34,6 +59,13 @@
</div>
</div>
</div>
<div id="spinnerOverlay" style="display: none;">
<div class="d-flex align-items-center">
<div class="spinner-border text-primary" role="status" aria-hidden="true"></div>
<span class="ml-3"><H5>设置中,需要重启线程,请稍候...</H5></span>
</div>
</div>
<main class="p-0 mb-0">
{% block content %}{% endblock %}
</main>

36
web/main/templates/channel_manager.html

@ -76,23 +76,21 @@
{% block content %}
<div class="container d-flex flex-column" >
<div class="row mb-3 d-flex justify-content-center align-items-center ">
<div class="col"><h5 class="form-group-right">所属区域:</h5></div>
<div class="col-3 mr-2">
<select id="areaSelect" class="form-select mr-2" aria-label="Default select example">
<!-- 数据动态填充 -->
</select></div>
<div class="col"><h5 class="form-group-right">通道名称:</h5></div>
<div class="col-5 mr-2">
<input id="channelNameInput" type="text" class="form-control mr-2" placeholder="Channel_name" aria-label="Channel_name"></div>
<div class="col-1"><button id="searchButton" type="button" class="btn btn-primary">查 询</button></div>
</div>
<div class="row justify-content-center align-items-center mb-3">
<div class="col-md-2 text-end"><label class="col-form-label form-label">所属区域:</label></div>
<div class="col-md-3">
<select id="areaSelect" class="form-select mr-2" aria-label="Default select example"></select></div>
<div class="col-md-2 text-end"><label class="col-form-label form-label">通道名称:</label></div>
<div class="col-md-3"><input id="channelNameInput" type="text" class="form-control"></div>
<div class="col-md-2"><button id="searchButton" type="button" class="btn btn-primary">查 询</button></div>
</div>
<div class="mb-3">
<!-- <button id="manageAreaButton" type="button" class="btn btn-primary mr-2">区域管理</button>-->
<button id="addChannelButton" type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#channelModal">
新增通道
</button>
</div>
<!-- 新增通道模态框 -->
<div class="modal fade" id="channelModal" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="add_channel" aria-hidden="true">
<div class="modal-dialog">
@ -103,17 +101,17 @@
</div>
<div class="modal-body">
<div class="form-group">
<label for="areaSelect_M">所属区域:</label>
<label for="areaSelect_M" class="form-label">所属区域:</label>
<select id="areaSelect_M" class="form-select" aria-label="D">
<!-- 数据动态填充 -->
</select>
</div>
<div class="form-group">
<label for="CNameInput">通道名称:</label>
<label for="CNameInput" class="form-label">通道名称:</label>
<input type="text" class="form-control" id="CNameInput">
</div>
<div class="form-group">
<label for="RTSPInput">RTSP地址:</label>
<label for="RTSPInput" class="form-label">RTSP地址:</label>
<input type="text" class="form-control" id="RTSPInput">
</div>
</div>
@ -135,17 +133,17 @@
</div>
<div class="modal-body">
<div class="form-group">
<label for="areaSelect_CC">所属区域:</label>
<label for="areaSelect_CC" class="form-label">所属区域:</label>
<select id="areaSelect_CC" class="form-select" aria-label="D">
<!-- 数据动态填充 -->
</select>
</div>
<div class="form-group">
<label for="CNameInput_cc">通道名称:</label>
<label for="CNameInput_cc" class="form-label">通道名称:</label>
<input type="text" class="form-control" id="CNameInput_cc">
</div>
<div class="form-group">
<label for="RTSPInput_cc">RTSP地址:</label>
<label for="RTSPInput_cc" class="form-label">RTSP地址:</label>
<input type="text" class="form-control" id="RTSPInput_cc">
</div>
</div>
@ -229,7 +227,7 @@
</div>
<!-- 布放计划 -->
<div class="row form-group">
<label for="11">计划:</label>
<label for="11">计划:</label>
<div id="11">
<table class="schedule-table table table-sm table-bordered" style="font-size: 7px;">
<thead>

10
web/main/templates/header.html

@ -8,12 +8,12 @@
<span class="fs-4">ZF_BOX</span>
</a>
<ul class="nav nav-pills">
<ul class="nav nav-pills mr-2">
<li class="nav-item"><a href="/view_main.html" class="nav-link active" aria-current="page">实时预览</a></li>
<li class="nav-item"><a href="/channel_manager.html" class="nav-link">通道管理</a></li>
<li class="nav-item"><a href="/schedule.html" class="nav-link">算法管理</a></li>
<li class="nav-item"><a href="#" class="nav-link">系统管理</a></li>
<li class="nav-item"><a href="#" class="nav-link">用户管理</a></li>
<li class="nav-item"><a href="/model_manager.html" class="nav-link">算法管理</a></li>
<li class="nav-item"><a href="/system_manager.html" class="nav-link">系统管理</a></li>
<li class="nav-item"><a href="/user_manager.html" class="nav-link">用户管理</a></li>
</ul>
<div class="dropdown text-end">
@ -25,7 +25,7 @@
<!-- <img src="https://github.com/mdo.png" alt="mdo" width="32" height="32" class="rounded-circle">-->
</a>
<ul class="dropdown-menu text-small">
<li><a class="dropdown-item" href="#">修改密码</a></li>
<li><a class="dropdown-item" href="/user_manager.html">修改密码</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="#">退 出</a></li>
</ul>

145
web/main/templates/model_manager.html

@ -0,0 +1,145 @@
{% extends 'base.html' %}
{% block title %}ZFBOX{% endblock %}
{% block style %}
.table-container {
min-height: 400px; /* 设置最小高度,可以根据需要调整 */
}
/* 缩小表格行高 */
.table-sm th,
.table-sm td {
padding: 0.2rem; /* 调整这里的值来改变行高 */
}
.pagination {
justify-content: flex-end; /* 右对齐 */
}
{% endblock %}
{% block content %}
<div class="container d-flex flex-column" >
<!-- 模态框区域 -->
<!-- 新增算法模态框 -->
<div class="modal fade" id="addMM" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="add_model" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">新增算法</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="form-group mb-2">
<label for="MNameInput" class="form-label">算法名称:</label>
<input type="text" class="form-control" id="MNameInput">
</div>
<div class="form-group mb-2">
<label for="uploadModelFile" class="form-label">上传文件:</label>
<input type="file" class="form-control" id="uploadModelFile" accept=".zip">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" id="cancelButton_model">取消</button>
<button type="button" class="btn btn-primary" id="saveButton_model">保存</button>
</div>
</div>
</div>
</div>
<!-- 升级算法模态框 -->
<div class="modal fade" id="updateMM" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="update_model" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">升级算法</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="form-group mb-3">
<label id="update_mname_label" class="form-label">算法名称:</label>
</div>
<div class="form-group mb-3">
<label id="update_mversion_label" class="form-label">当前版本:</label>
</div>
<div class="form-group mb-3">
<label for="uploadModelFile" class="form-label">上传文件:</label>
<input type="file" class="form-control" id="updateModelFile" accept=".zip">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" id="cancelButton_upmodel">取消</button>
<button type="button" class="btn btn-primary" id="saveButton_upmodel">保存</button>
</div>
</div>
</div>
</div>
<!-- 配置算法模态框 -->
<div class="modal fade" id="configMM" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="config_model" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">配置算法</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="form-group mb-3">
<label id="config_mname_label" class="form-label">算法名称:</label>
</div>
<div class="form-group mb-3">
<label for="duration_timeInput" class="form-label">持续判断时间(秒):</label>
<input type="text" class="form-control" id="duration_timeInput">
</div>
<div class="form-group mb-3">
<label for="proportionInput" class="form-label">占比阈值(0-1):</label>
<input type="text" class="form-control" id="proportionInput">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" id="cancelButton_config_model">取消</button>
<button type="button" class="btn btn-primary" id="saveButton_config_model">保存</button>
</div>
</div>
</div>
</div>
<!-- 搜索区 -->
<div class="row justify-content-center align-items-center mb-3">
<div class="col-md-2 text-end"><label class="col-form-label form-label">算法名称:</label></div>
<div class="col-md-6"><input id="modelNameInput" type="text" class="form-control"></div>
<div class="col-md-2"><button id="searchMButton" type="button" class="btn btn-primary">查 询</button></div>
</div>
<!-- 按钮区 -->
<div class="mb-3">
<button id="addModelButton" type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addMM">
新增算法
</button>
</div>
<!-- 表格区 -->
<div class="table-container">
<table class="table">
<thead class="table-light">
<tr>
<th scope="col">ID</th>
<th scope="col">算法名称</th>
<th scope="col">版本号</th>
<th scope="col">持续判断时间</th>
<th scope="col">占比阈值</th>
<th scope="col">操作</th>
</tr>
</thead>
<tbody id="table-body-model" class="table-group-divider">
<!-- 表格数据动态填充 -->
</tbody>
</table>
<nav>
<ul id="pagination-model" class="pagination">
<!-- 分页控件将动态生成 -->
</ul>
</nav>
</div>
</div>
{% endblock %}
{% block script %}
<script src="{{ url_for('main.static', filename='scripts/model_manager.js') }}"></script>
<script src="{{ url_for('main.static', filename='scripts/jquery-3.2.1.slim.min.js') }}"></script>
{% endblock %}

156
web/main/templates/schedule.html

@ -1,156 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>布防时间计划</title>
<link rel="stylesheet" href="{{ url_for('main.static', filename='css/bootstrap.min.css') }}">
<style>
.schedule-table {
width: 100%;
table-layout: fixed;
}
.schedule-table th, .schedule-table td {
text-align: center;
vertical-align: middle;
cursor: pointer;
border: 1px solid #dee2e6;
padding: 8px;
}
.schedule-table td.allowed {
background-color: white;
}
.schedule-table td.blocked {
background-color: blue;
}
</style>
</head>
<body>
<div class="container mt-5">
<table class="schedule-table table table-bordered">
<thead>
<tr>
<th>小时</th>
<th>00</th>
<th>01</th>
<th>02</th>
<th>03</th>
<th>04</th>
<th>05</th>
<th>06</th>
<th>07</th>
<th>08</th>
<th>09</th>
<th>10</th>
<th>11</th>
<th>12</th>
<th>13</th>
<th>14</th>
<th>15</th>
<th>16</th>
<th>17</th>
<th>18</th>
<th>19</th>
<th>20</th>
<th>21</th>
<th>22</th>
<th>23</th>
</tr>
</thead>
<tbody>
<!-- Repeat above row for each day of the week (Monday to Saturday) -->
<tr>
<th>星期一</th>
<td class="blocked"></td><td class="blocked"></td><td class="blocked"></td><td class="blocked"></td>
<td class="blocked"></td><td class="blocked"></td><td class="blocked"></td><td class="blocked"></td>
<td class="blocked"></td><td class="blocked"></td><td class="blocked"></td><td class="blocked"></td>
<td class="blocked"></td><td class="blocked"></td><td class="blocked"></td><td class="blocked"></td>
<td class="blocked"></td><td class="blocked"></td><td class="blocked"></td><td class="blocked"></td>
<td class="blocked"></td><td class="blocked"></td><td class="blocked"></td><td class="blocked"></td>
</tr>
<tr>
<th>星期二</th>
<td class="blocked"></td><td class="blocked"></td><td class="blocked"></td><td class="blocked"></td>
<td class="blocked"></td><td class="blocked"></td><td class="blocked"></td><td class="blocked"></td>
<td class="blocked"></td><td class="blocked"></td><td class="blocked"></td><td class="blocked"></td>
<td class="blocked"></td><td class="blocked"></td><td class="blocked"></td><td class="blocked"></td>
<td class="blocked"></td><td class="blocked"></td><td class="blocked"></td><td class="blocked"></td>
<td class="blocked"></td><td class="blocked"></td><td class="blocked"></td><td class="blocked"></td>
</tr>
<tr>
<th>星期三</th>
<td class="blocked"></td><td class="blocked"></td><td class="blocked"></td><td class="blocked"></td>
<td class="blocked"></td><td class="blocked"></td><td class="blocked"></td><td class="blocked"></td>
<td class="blocked"></td><td class="blocked"></td><td class="blocked"></td><td class="blocked"></td>
<td class="blocked"></td><td class="blocked"></td><td class="blocked"></td><td class="blocked"></td>
<td class="blocked"></td><td class="blocked"></td><td class="blocked"></td><td class="blocked"></td>
<td class="blocked"></td><td class="blocked"></td><td class="blocked"></td><td class="blocked"></td>
</tr>
<tr>
<th>星期四</th>
<td class="blocked"></td><td class="blocked"></td><td class="blocked"></td><td class="blocked"></td>
<td class="blocked"></td><td class="blocked"></td><td class="blocked"></td><td class="blocked"></td>
<td class="blocked"></td><td class="blocked"></td><td class="blocked"></td><td class="blocked"></td>
<td class="blocked"></td><td class="blocked"></td><td class="blocked"></td><td class="blocked"></td>
<td class="blocked"></td><td class="blocked"></td><td class="blocked"></td><td class="blocked"></td>
<td class="blocked"></td><td class="blocked"></td><td class="blocked"></td><td class="blocked"></td>
</tr>
<tr>
<th>星期五</th>
<td class="blocked"></td><td class="blocked"></td><td class="blocked"></td><td class="blocked"></td>
<td class="blocked"></td><td class="blocked"></td><td class="blocked"></td><td class="blocked"></td>
<td class="blocked"></td><td class="blocked"></td><td class="blocked"></td><td class="blocked"></td>
<td class="blocked"></td><td class="blocked"></td><td class="blocked"></td><td class="blocked"></td>
<td class="blocked"></td><td class="blocked"></td><td class="blocked"></td><td class="blocked"></td>
<td class="blocked"></td><td class="blocked"></td><td class="blocked"></td><td class="blocked"></td>
</tr>
<tr>
<th>星期六</th>
<td class="blocked"></td><td class="blocked"></td><td class="blocked"></td><td class="blocked"></td>
<td class="blocked"></td><td class="blocked"></td><td class="blocked"></td><td class="blocked"></td>
<td class="blocked"></td><td class="blocked"></td><td class="blocked"></td><td class="blocked"></td>
<td class="blocked"></td><td class="blocked"></td><td class="blocked"></td><td class="blocked"></td>
<td class="blocked"></td><td class="blocked"></td><td class="blocked"></td><td class="blocked"></td>
<td class="blocked"></td><td class="blocked"></td><td class="blocked"></td><td class="blocked"></td>
</tr>
<tr>
<th>星期日</th>
<!-- 24 cells for each hour -->
<td class="blocked"></td><td class="blocked"></td><td class="blocked"></td><td class="blocked"></td>
<td class="blocked"></td><td class="blocked"></td><td class="blocked"></td><td class="blocked"></td>
<td class="blocked"></td><td class="blocked"></td><td class="blocked"></td><td class="blocked"></td>
<td class="blocked"></td><td class="blocked"></td><td class="blocked"></td><td class="blocked"></td>
<td class="blocked"></td><td class="blocked"></td><td class="blocked"></td><td class="blocked"></td>
<td class="blocked"></td><td class="blocked"></td><td class="blocked"></td><td class="blocked"></td>
</tr>
</tbody>
</table>
<div class="mt-3">
<div class="d-inline-block mr-3">
<div class="d-inline-block align-middle" style="width: 20px; height: 20px; background-color: white; border: 1px solid black;"></div>
<span class="align-middle">允许</span>
</div>
<div class="d-inline-block">
<div class="d-inline-block align-middle" style="width: 20px; height: 20px; background-color: blue;"></div>
<span class="align-middle">阻止</span>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
const cells = document.querySelectorAll('.schedule-table tbody td');
cells.forEach(cell => {
cell.addEventListener('click', () => {
if (cell.classList.contains('blocked')) {
cell.classList.remove('blocked');
cell.classList.add('allowed');
} else {
cell.classList.remove('allowed');
cell.classList.add('blocked');
}
});
});
});
</script>
</body>
</html>

286
web/main/templates/system_manager.html

@ -0,0 +1,286 @@
{% extends 'base.html' %}
{% block title %}ZFBOX{% endblock %}
{% block style %}
.btn-blue {
background-color: #007bff;
color: white;
}
.btn-blue:hover {
background-color: #0056b3;
}
.table-container {
min-height: 300px; /* 设置最小高度,可以根据需要调整 */
}
/* 缩小表格行高 */
.table-sm th,
.table-sm td {
padding: 0.2rem; /* 调整这里的值来改变行高 */
}
.pagination {
justify-content: flex-end; /* 右对齐 */
}
.section-title {
position: relative;
margin: 20px 0;
}
.section-title hr {
margin: 0;
border-color: #000; /* You can change the color of the line if needed */
}
{% endblock %}
{% block content %}
<div class="container d-flex flex-column" >
<!-- 模态框区域 -->
<!-- 配置IP模态框-->
<div class="modal fade" id="ipConfigModal" tabindex="-1" aria-labelledby="ipConfigModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="ipConfigModalLabel">IP地址配置</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<!-- Tabs for Wired and Wireless IP -->
<ul class="nav nav-tabs" id="ipTab" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="wired-tab" data-bs-toggle="tab" data-bs-target="#wired" type="button" role="tab" aria-controls="wired" aria-selected="true">有线IP</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="wireless-tab" data-bs-toggle="tab" data-bs-target="#wireless" type="button" role="tab" aria-controls="wireless" aria-selected="false">无线IP</button>
</li>
</ul>
<!-- Tab content -->
<div class="tab-content mt-3" id="ipTabContent">
<!-- Wired IP Configuration -->
<div class="tab-pane fade show active" id="wired" role="tabpanel" aria-labelledby="wired-tab">
<div class="mb-3">
<div class="row">
<div class="col-6">
<div class="form-check">
<input class="form-check-input" type="radio" name="ip_lan"
id="dhcp_lan" checked onclick="handleRadioClick_lan(event)">
<label class="form-check-label" for="dhcp_lan">自动获取</label>
</div>
</div>
<div class="col-6">
<div class="form-check">
<input class="form-check-input" type="radio" name="ip_lan"
id="static_lan" onclick="handleRadioClick_lan(event)">
<label class="form-check-label" for="static_lan">静态IP</label>
</div>
</div>
</div>
</div>
<div class="mb-3">
<label for="wiredIpAddress" class="form-label">有线IP地址</label>
<input type="text" class="form-control" id="wiredIpAddress" placeholder="例如: 192.168.1.2">
</div>
<div class="mb-3">
<label for="wiredSubnetMask" class="form-label">子网掩码</label>
<input type="text" class="form-control" id="wiredSubnetMask" placeholder="例如: 255.255.255.0">
</div>
<div class="mb-3">
<label for="wiredGateway" class="form-label">网关</label>
<input type="text" class="form-control" id="wiredGateway" placeholder="例如: 192.168.1.1">
</div>
<div>
<label for="wirelessGateway" class="form-label">DNS</label>
<input type="text" class="form-control" id="wiredDNS" placeholder="例如: 114.114.114.114">
</div>
</div>
<!-- Wireless IP Configuration -->
<div class="tab-pane fade" id="wireless" role="tabpanel" aria-labelledby="wireless-tab">
<div class="mb-2">
<label for="wirelessNetwork" class="form-label">选择无线网络</label>
<select class="form-select" id="wirelessNetwork">
<!-- 数据动态填充 -->
</select>
</div>
<div class="mb-4">
<div class="row justify-content-center align-items-center">
<div class="col-2"><label for="wirelessSubnetMask" class="form-label">密码:</label></div>
<div class="col-8"><input type="password" class="form-control" id="wifi_passwd"></div>
<div class="col-2"><button type="button" class="btn btn-primary" id="connectWifi">连接</button></div>
</div>
</div>
<div class="mb-2">
<div class="row">
<div class="col-6">
<div class="form-check">
<input class="form-check-input" type="radio" name="ip_wifi"
id="dhcp_wifi" checked onclick="handleRadioClick_wifi(event)">
<label class="form-check-label" for="dhcp_wifi">自动获取</label>
</div>
</div>
<div class="col-6">
<div class="form-check">
<input class="form-check-input" type="radio" name="ip_wifi"
id="static_wifi" onclick="handleRadioClick_wifi(event)">
<label class="form-check-label" for="static_wifi">静态IP</label>
</div>
</div>
</div>
</div>
<div class="mb-2">
<label for="wirelessIpAddress" class="form-label">无线IP地址</label>
<input type="text" class="form-control" id="wirelessIpAddress" placeholder="例如: 192.168.1.3">
</div>
<div class="mb-2">
<label for="wirelessSubnetMask" class="form-label">子网掩码</label>
<input type="text" class="form-control" id="wirelessSubnetMask" placeholder="例如: 255.255.255.0">
</div>
<div class="mb-2">
<label for="wirelessGateway" class="form-label">网关</label>
<input type="text" class="form-control" id="wirelessGateway" placeholder="例如: 192.168.1.1">
</div>
<div>
<label for="wirelessGateway" class="form-label">DNS</label>
<input type="text" class="form-control" id="wirelessDNS" placeholder="例如: 114.114.114.114">
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button>
<button type="button" class="btn btn-primary" id="saveIPConfig">保存设置</button>
</div>
</div>
</div>
</div>
<!-- 修改服务器IP模态框-->
<div class="modal fade" id="ServerIPModal" tabindex="-1" aria-labelledby="ServerIPModal" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">服务器IP地址配置</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="mb-3">
<label for="serviceIP_model" class="form-label">服务器IP</label>
<input type="text" class="form-control" id="serviceIP_model" placeholder="例如: 127.0.0.1">
</div>
<div class="mb-3">
<label for="servicePort_model" class="form-label">端口号</label>
<input type="text" class="form-control" id="servicePort_model" placeholder="例如: 8085">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button>
<button type="button" class="btn btn-primary" id="saveServerIP">保存设置</button>
</div>
</div>
</div>
</div>
<!-- 新增区域模态框-->
<div class="modal fade" id="addAreaModal" tabindex="-1" aria-labelledby="AreaModal" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="area_modal_title_id">新增区域</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="mb-3">
<label for="area_name" class="form-label">区域名称</label>
<input type="text" class="form-control" id="area_name">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button>
<button type="button" class="btn btn-primary" id="addArea">保存设置</button>
</div>
</div>
</div>
</div>
<!-- 修改区域模态框-->
<div class="modal fade" id="modifyAreaModal" tabindex="-1" aria-labelledby="AreaModal" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">修改区域</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="mb-3">
<label for="area_name" class="form-label">区域名称</label>
<input type="text" class="form-control" id="area_name_modif">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button>
<button type="button" class="btn btn-primary" id="modifArea">保存设置</button>
</div>
</div>
</div>
</div>
<!-- 系统信息区域 -->
<div class="container mt-4">
<div class="row justify-content-center align-items-center">
<div class="col-md-3 text-end"><label class="col-form-label form-label">系统版本号:</label></div>
<div class="col-md-9"><p class="form-control-plaintext" id="system_version">1.0.0.1</p></div>
</div>
<div class="row justify-content-center align-items-center">
<div class="col-md-3 text-end"><label class="col-form-label form-label">升级包:</label></div>
<div class="col-md-6"><input type="file" class="form-control" id="upgrade-system"></div>
<div class="col-md-3"><button class="btn btn-blue" id="upsystem">升级</button></div>
</div>
<div class="row justify-content-center align-items-center">
<div class="col-md-3 text-end"><label class="col-form-label form-label">设备ID:</label></div>
<div class="col-md-9"><p class="form-control-plaintext" id="dev_ID">1.0.0.1</p></div>
</div>
<div class="row justify-content-center align-items-center">
<div class="col-md-3 text-end"><label class="col-form-label form-label">设备IP:</label></div>
<div class="col-md-6"><p class="form-control-plaintext" id="dev_IP">
有线--192.168.3.45 WIFI--192.168.3.45 5G--192.168.3.45</p></div>
<div class="col-md-3"><button class="btn btn-blue" id="showIPConfig">配置</button></div>
</div>
<div class="row justify-content-center align-items-center">
<div class="col-md-3 text-end"><label class="col-form-label form-label">服务器IP:</label></div>
<div class="col-md-3"><input type="text" class="form-control" id="service_ip"></div>
<div class="col-md"><label class="col-form-label form-label">端口号:</label></div>
<div class="col-md"><input type="text" class="form-control" id="service_port"></div>
<div class="col-md-3"><button class="btn btn-blue" id="showServerIP">修改</button></div>
</div>
</div>
<!-- 区域管理区域 -->
<div class="section-title">
<hr>
</div>
<div class="mb-3">
<button id="addAreaButton" type="button" class="btn btn-primary">
新增区域
</button>
</div>
<div class="table-container">
<table class="table">
<thead class="table-light">
<tr>
<th scope="col" style="width: 20%;">ID</th>
<th scope="col" style="width: 50%;">区域名称</th>
<th scope="col" style="width: 30%;">操作</th>
</tr>
</thead>
<tbody id="table-body-area" class="table-group-divider">
<!-- 表格数据动态填充 -->
</tbody>
</table>
<nav>
<ul id="pagination-area" class="pagination">
<!-- 分页控件将动态生成 -->
</ul>
</nav>
</div>
</div>
{% endblock %}
{% block script %}
<script src="{{ url_for('main.static', filename='scripts/jquery-3.2.1.slim.min.js') }}"></script>
<script src="{{ url_for('main.static', filename='scripts/system_manager.js') }}"></script>
{% endblock %}

48
web/main/templates/user_manager.html

@ -0,0 +1,48 @@
{% extends 'base.html' %}
{% block title %}ZFBOX{% endblock %}
{% block style %}
.note {
color: red;
font-size: 0.9rem;
}
.btn-blue {
background-color: #007bff;
color: white;
}
.btn-blue:hover {
background-color: #0056b3;
}
{% endblock %}
{% block content %}
<div class="container d-flex flex-column" >
<div class="row justify-content-center align-items-center mb-2">
<div class="col-md-2 text-end"><label class="col-form-label form-label">用户名:</label></div>
<div class="col-md-7"><p class="form-control-plaintext" id="system_version">zfadmin</p></div>
</div>
<div class="row justify-content-center align-items-center mb-2">
<div class="col-md-2 text-end"><label class="col-form-label form-label">原密码:</label></div>
<div class="col-md-7"><input type="password" class="form-control" id="source_passwd"></div>
</div>
<div class="row justify-content-center align-items-center mb-2">
<div class="col-md-2 text-end"><label class="col-form-label form-label">新密码:</label></div>
<div class="col-md-7"><input type="password" class="form-control" id="new_passwd"></div>
</div>
<div class="row justify-content-center align-items-center mb-2">
<div class="col-md-2 text-end"><label class="col-form-label form-label">确认密码:</label></div>
<div class="col-md-7"><input type="password" class="form-control" id="again_passwd"></div>
</div>
<div class="row justify-content-center align-items-center mb-2">
<div class="col-md-6 text-end"></div>
<div class="col-md-3"><button class="btn btn-blue w-100" id="changePasswd">修改密码</button></div>
</div>
</div>
{% endblock %}
{% block script %}
<script src="{{ url_for('main.static', filename='scripts/user_manager.js') }}"></script>
{% endblock %}

367
web/main/templates/实时预览.html

@ -1,367 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>实时预览</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<link href="resources/css/axure_rp_page.css" type="text/css" rel="stylesheet"/>
<link href="data/styles.css" type="text/css" rel="stylesheet"/>
<link href="files/实时预览/styles.css" type="text/css" rel="stylesheet"/>
<script src="resources/scripts/jquery-3.2.1.min.js"></script>
<script src="resources/scripts/axure/axQuery.js"></script>
<script src="resources/scripts/axure/globals.js"></script>
<script src="resources/scripts/axutils.js"></script>
<script src="resources/scripts/axure/annotation.js"></script>
<script src="resources/scripts/axure/axQuery.std.js"></script>
<script src="resources/scripts/axure/doc.js"></script>
<script src="resources/scripts/messagecenter.js"></script>
<script src="resources/scripts/axure/events.js"></script>
<script src="resources/scripts/axure/recording.js"></script>
<script src="resources/scripts/axure/action.js"></script>
<script src="resources/scripts/axure/expr.js"></script>
<script src="resources/scripts/axure/geometry.js"></script>
<script src="resources/scripts/axure/flyout.js"></script>
<script src="resources/scripts/axure/model.js"></script>
<script src="resources/scripts/axure/repeater.js"></script>
<script src="resources/scripts/axure/sto.js"></script>
<script src="resources/scripts/axure/utils.temp.js"></script>
<script src="resources/scripts/axure/variables.js"></script>
<script src="resources/scripts/axure/drag.js"></script>
<script src="resources/scripts/axure/move.js"></script>
<script src="resources/scripts/axure/visibility.js"></script>
<script src="resources/scripts/axure/style.js"></script>
<script src="resources/scripts/axure/adaptive.js"></script>
<script src="resources/scripts/axure/tree.js"></script>
<script src="resources/scripts/axure/init.temp.js"></script>
<script src="resources/scripts/axure/legacy.js"></script>
<script src="resources/scripts/axure/viewer.js"></script>
<script src="resources/scripts/axure/math.js"></script>
<script src="resources/scripts/axure/jquery.nicescroll.min.js"></script>
<script src="data/document.js"></script>
<script src="files/实时预览/data.js"></script>
<script type="text/javascript">
$axure.utils.getTransparentGifPath = function() { return 'resources/images/transparent.gif'; };
$axure.utils.getOtherPath = function() { return 'resources/Other.html'; };
$axure.utils.getReloadPath = function() { return 'resources/reload.html'; };
</script>
</head>
<body>
<div id="base" class="">
<!-- Unnamed (web框架一) -->
<!-- Unnamed (Rectangle) -->
<div id="u16" class="ax_default flow_shape">
<div id="u16_div" class=""></div>
<div id="u16_text" class="text " style="display:none; visibility: hidden">
<p></p>
</div>
</div>
<!-- Unnamed (Rectangle) -->
<div id="u17" class="ax_default flow_shape">
<div id="u17_div" class=""></div>
<div id="u17_text" class="text " style="display:none; visibility: hidden">
<p></p>
</div>
</div>
<!-- Unnamed (Rectangle) -->
<div id="u18" class="ax_default heading_1">
<div id="u18_div" class=""></div>
<div id="u18_text" class="text ">
<p><span>智凡BOX</span></p>
</div>
</div>
<!-- Unnamed (Rectangle) -->
<div id="u19" class="ax_default heading_3">
<div id="u19_div" class=""></div>
<div id="u19_text" class="text ">
<p><span>@2024 ZFKJ All Rights Reserved </span></p>
</div>
</div>
<!-- Unnamed (Menu) -->
<div id="u20" class="ax_default">
<img id="u20_menu" class="img " src="images/实时预览/u20_menu.png" alt="u20_menu"/>
<!-- Unnamed (Table) -->
<div id="u21" class="ax_default">
<!-- Unnamed (Menu Item) -->
<div id="u22" class="ax_default menu_item">
<img id="u22_img" class="img " src="images/实时预览/u22.png"/>
<div id="u22_text" class="text ">
<p><span>实时预览</span></p>
</div>
</div>
<!-- Unnamed (Menu Item) -->
<div id="u23" class="ax_default menu_item">
<img id="u23_img" class="img " src="images/实时预览/u22.png"/>
<div id="u23_text" class="text ">
<p><span>通道管理</span></p>
</div>
</div>
<!-- Unnamed (Menu Item) -->
<div id="u24" class="ax_default menu_item">
<img id="u24_img" class="img " src="images/实时预览/u22.png"/>
<div id="u24_text" class="text ">
<p><span>算法管理</span></p>
</div>
</div>
<!-- Unnamed (Menu Item) -->
<div id="u25" class="ax_default menu_item">
<img id="u25_img" class="img " src="images/实时预览/u22.png"/>
<div id="u25_text" class="text ">
<p><span>系统管理</span></p>
</div>
</div>
<!-- Unnamed (Menu Item) -->
<div id="u26" class="ax_default menu_item">
<img id="u26_img" class="img " src="images/实时预览/u26.png"/>
<div id="u26_text" class="text ">
<p><span>用户管理</span></p>
</div>
</div>
</div>
</div>
<!-- Unnamed (Shape) -->
<div id="u27" class="ax_default icon">
<img id="u27_img" class="img " src="images/登录/u4.svg"/>
<div id="u27_text" class="text " style="display:none; visibility: hidden">
<p></p>
</div>
</div>
<!-- Unnamed (Rectangle) -->
<div id="u28" class="ax_default heading_3">
<div id="u28_div" class=""></div>
<div id="u28_text" class="text ">
<p><span>张三</span></p>
</div>
</div>
<!-- Unnamed (Rectangle) -->
<div id="u29" class="ax_default primary_button">
<div id="u29_div" class=""></div>
<div id="u29_text" class="text ">
<p><span>退出</span></p>
</div>
</div>
<div id="u15" style="display:none; visibility:hidden;"></div>
<!-- Unnamed (Rectangle) -->
<div id="u30" class="ax_default primary_button">
<div id="u30_div" class=""></div>
<div id="u30_text" class="text ">
<p><span>实时预览</span></p>
</div>
</div>
<!-- Unnamed (Rectangle) -->
<div id="u31" class="ax_default flow_shape">
<div id="u31_div" class=""></div>
<div id="u31_text" class="text " style="display:none; visibility: hidden">
<p></p>
</div>
</div>
<script src="/resources/scripts/aiortc-client-new.js">
console.log('当指定了src属性时,浏览器会加载并执行该文件中的脚本,而忽略标签内部的任何内容,所以不会执行');
</script>
<!-- Unnamed (Image) -->
<div id="u32" class="ax_default image">
<img id="u32_video" src="" alt="Video Stream">
</div>
<!-- Unnamed (Image) -->
<div id="u33" class="ax_default image">
<img id="u33_video" src="" alt="Video Stream">
</div>
<!-- Unnamed (Image) -->
<div id="u34" class="ax_default image">
<!-- <video id="u34_video" autoplay="true" playsinline="true"></video>-->
<img id="u34_video" src="" alt="Video Stream">
</div>
<!-- Unnamed (Image) -->
<div id="u35" class="ax_default image">
<!-- <video id="u35_video" autoplay="true" playsinline="true"></video>-->
<img id="u35_video" src="" alt="Video Stream">
</div>
<!-- Unnamed (Image) -->
<div id="u36" class="ax_default image">
<!-- <video id="u36_video" autoplay="true" playsinline="true"></video>-->
<img id="u36_video" src="" alt="Video Stream">
</div>
<!-- Unnamed (Image) -->
<div id="u37" class="ax_default image">
<!-- <video id="u37_video" autoplay="true" playsinline="true"></video>-->
<img id="u37_video" src="" alt="Video Stream">
</div>
<!-- Unnamed (Image) -->
<div id="u38" class="ax_default image">
<!-- <video id="u38_video" autoplay="true" playsinline="true"></video>-->
<img id="u38_video" src="" alt="Video Stream">
</div>
<!-- Unnamed (Image) -->
<div id="u39" class="ax_default image">
<!-- <video id="u39_video" autoplay="true" playsinline="true"></video>-->
<img id="u39_video" src="" alt="Video Stream">
</div>
<!-- Unnamed (Image) -->
<div id="u40" class="ax_default image">
<img id="u40_img" class="img " src="images/实时预览/u32.png"/>
<div id="u40_text" class="text " style="display:none; visibility: hidden">
<p></p>
</div>
</div>
<!-- Unnamed (Rectangle) -->
<div id="u41" class="ax_default label">
<div id="u41_div" class=""></div>
<div id="u41_text" class="text ">
<p><span>&lt;&lt;&nbsp; 1/2&nbsp; &gt;&gt;</span></p>
</div>
</div>
<!-- Unnamed (Rectangle) -->
<div id="u42" class="ax_default button">
<div id="u42_div" class=""></div>
<div id="u42_text" class="text ">
<p><span>一画面</span></p>
</div>
</div>
<!-- Unnamed (Rectangle) -->
<div id="u43" class="ax_default button">
<div id="u43_div" class=""></div>
<div id="u43_text" class="text ">
<p><span>四画面</span></p>
</div>
</div>
<!-- Unnamed (Rectangle) -->
<div id="u44" class="ax_default button">
<div id="u44_div" class=""></div>
<div id="u44_text" class="text ">
<p><span>九画面</span></p>
</div>
</div>
<!-- Unnamed (Rectangle) -->
<div id="u45" class="ax_default button">
<div id="u45_div" class=""></div>
<div id="u45_text" class="text ">
<p><span>十六<br>画面</span></p>
</div>
</div>
<!-- Unnamed (Tree) -->
<div id="u46" class="ax_default tree_node treeroot">
<div id="u46_children" class="u46_children">
<!-- Unnamed (Tree Node) -->
<div id="u47" class="ax_default tree_node treenode">
<!-- Unnamed (Image) -->
<div id="u48" class="ax_default image">
<img id="u48_img" class="img " src="images/实时预览/u48_selected.png"/>
<div id="u48_text" class="text " style="display:none; visibility: hidden">
<p></p>
</div>
</div>
<!-- Unnamed (Rectangle) -->
<div id="u49" class="" selectiongroup="u46_tree_group">
<div id="u49_div" class=""></div>
<div id="u49_text" class="text ">
<p><span>一厂区</span></p>
</div>
</div>
<div id="u47_children" class="u47_children">
<!-- Unnamed (Tree Node) -->
<div id="u50" class="ax_default tree_node treenode">
<!-- Unnamed (Rectangle) -->
<div id="u51" class="" selectiongroup="u46_tree_group">
<div id="u51_div" class=""></div>
<div id="u51_text" class="text ">
<p><span>北门通道一</span></p>
</div>
</div>
</div>
<!-- Unnamed (Tree Node) -->
<div id="u52" class="ax_default tree_node treenode">
<!-- Unnamed (Rectangle) -->
<div id="u53" class="" selectiongroup="u46_tree_group">
<div id="u53_div" class=""></div>
<div id="u53_text" class="text ">
<p><span>南门通道二</span></p>
</div>
</div>
</div>
<!-- Unnamed (Tree Node) -->
<div id="u54" class="ax_default tree_node treenode">
<!-- Unnamed (Rectangle) -->
<div id="u55" class="" selectiongroup="u46_tree_group">
<div id="u55_div" class=""></div>
<div id="u55_text" class="text ">
<p><span>通道三</span></p>
</div>
</div>
</div>
</div>
</div>
<!-- Unnamed (Tree Node) -->
<div id="u56" class="ax_default tree_node treenode">
<!-- Unnamed (Image) -->
<div id="u57" class="ax_default image">
<img id="u57_img" class="img " src="images/实时预览/u48_selected.png"/>
<div id="u57_text" class="text " style="display:none; visibility: hidden">
<p></p>
</div>
</div>
<!-- Unnamed (Rectangle) -->
<div id="u58" class="" selectiongroup="u46_tree_group">
<div id="u58_div" class=""></div>
<div id="u58_text" class="text ">
<p><span>二区域</span></p>
</div>
</div>
<div id="u56_children" class="u56_children">
<!-- Unnamed (Tree Node) -->
<div id="u59" class="ax_default tree_node treenode">
<!-- Unnamed (Rectangle) -->
<div id="u60" class="" selectiongroup="u46_tree_group">
<div id="u60_div" class=""></div>
<div id="u60_text" class="text ">
<p><span>通道一</span></p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="resources/scripts/axure/ios.js"></script>
</body>
</html>

1412
web/main/templates/通道管理.html

File diff suppressed because it is too large

BIN
zfbox.db

Binary file not shown.
Loading…
Cancel
Save