Merge pull request 'v2.2 -> v2.4' (#49) from v2.2 into master

Reviewed-on: cloud/cms#49
master
Steve L. Nyemba 2 weeks ago
commit 643ced07b0

@ -293,7 +293,7 @@ def create(folder:Annotated[str,typer.Argument(help="path of the project folder"
# #
# Build the configuration for the project # Build the configuration for the project
if not os.path.exists(folder) : if not os.path.exists(folder) :
root = 'www/html' root = f'www{os.sep}html'
_system = System() _system = System()
_layout = Layout() _layout = Layout()
_layout = _layout.build(root=root, order={'menu':[]}, footer = [{"text":term} for term in footer.split(',')],header={'title':title,'subtitle':subtitle} ) _layout = _layout.build(root=root, order={'menu':[]}, footer = [{"text":term} for term in footer.split(',')],header={'title':title,'subtitle':subtitle} )

@ -1,3 +1,2 @@
REM python .\qcms-sandbox\Scripts\qcms %1 %2 %3 %4 %5 %6
cd /D "%~dp0" cd /D "%~dp0"
python qcms %1 %2 %3 %4 %5 %6 python qcms %1 %2 %3 %4 %5 %6

@ -181,5 +181,9 @@ class delegate:
</script> </script>
""" """
# if _mimeType in ['text/html','plain/html'] :
# _env = Environment(loader=BaseLoader()).from_string(_data)
# _kwargs = {'layout':_config['layout'],'system':_config['system']}
# print (_data)
# _data = _env.render(**_kwargs)
return _data,_code,{'Content-Type':_mimeType} return _data,_code,{'Content-Type':_mimeType}

@ -68,8 +68,16 @@ def build (_config, keep=[]): #(_path,_content):
def _realpath (uri,_config) : def _realpath (uri,_config) :
_layout = _config['layout'] _layout = _config['layout']
_uri = copy.copy(uri) _uri = copy.copy(uri)
if _layout['root'] not in _uri :
_uri = os.sep.join([_layout['root'],_uri])
if 'location' in _layout and _layout['location']: if 'location' in _layout and _layout['location']:
_loc = _layout['location'].strip()
if _loc.endswith(os.sep) and _uri.endswith(os.sep) :
_uri = os.sep.join(_uri.split(os.sep)[1:])
_uri = os.sep.join([_layout['location'],_uri]) _uri = os.sep.join([_layout['location'],_uri])
return _uri return _uri
def _format (uri,_config): def _format (uri,_config):
@ -82,12 +90,13 @@ def read (**_args):
This will read binary files from disk, and allow the location or not to be read This will read binary files from disk, and allow the location or not to be read
@TODO: add permissions otherwise there can be disk-wide reads @TODO: add permissions otherwise there can be disk-wide reads
""" """
request = _args['request'] request = _args['request'] if 'request' in _args else None
_layout = _args['config']['layout'] _layout = _args['config']['layout']
_uri = request.args['uri'] # if 'location' in _layout : _uri = request.args['uri'] if request else _args['uri'] # if 'location' in _layout :
# _uri = os.sep.join([_layout['location'],_uri]) # _uri = os.sep.join([_layout['location'],_uri])
_uri = _realpath(_uri, _args['config']) _uri = _realpath(_uri, _args['config'])
_mimeType = 'text/plain' _mimeType = 'text/plain'
if os.path.exists(_uri): if os.path.exists(_uri):
f = open(_uri,mode='rb') f = open(_uri,mode='rb')
_stream = f.read() _stream = f.read()
@ -135,6 +144,8 @@ def html(_uri,_config) :
# _html = _html.replace(f'{os.sep}{_layout["root"]}',_layout['root']) # _html = _html.replace(f'{os.sep}{_layout["root"]}',_layout['root'])
return _html return _html
pass
def plugins (**_args): def plugins (**_args):
""" """
This function will load plugins from disk given where they come from This function will load plugins from disk given where they come from

@ -2,7 +2,7 @@
This file handles the structure (strict) of the configuration file, This file handles the structure (strict) of the configuration file,
Not all elements are programmatically editable (for now) Not all elements are programmatically editable (for now)
""" """
import meta # import meta
class Section : class Section :
def build (self,**_args): def build (self,**_args):
@ -36,7 +36,8 @@ class System (Section) :
""" """
return 'default' if 'name' not in _args else _args['name'] return 'default' if 'name' not in _args else _args['name']
def version(self,**_args): def version(self,**_args):
return meta.__version__ if 'version' not in _args else _args['version'] import cms
return cms.meta.__version__ if 'version' not in _args else _args['version']
def context (self,**_args): def context (self,**_args):
return "" if 'context' not in _args else _args['context'] return "" if 'context' not in _args else _args['context']
def app (self,**_args): def app (self,**_args):
@ -74,4 +75,4 @@ class Layout (Section):
def header (self,**_args): def header (self,**_args):
_data = {"title":"QCMS Project", "subtitle":"Powered by Python Flask"} _data = {"title":"QCMS Project", "subtitle":"Powered by Python Flask"}
return self.update(_data,**_args) return self.update(_data,**_args)

@ -2,7 +2,7 @@
import base64 import base64
import os import os
import json import json
import meta # import meta
from cms.engine import themes from cms.engine import themes
# def make (**_args): # def make (**_args):
# """ # """
@ -94,10 +94,11 @@ def _index (_path,root):
""" """
Creating a default index.html for the site given the project root location Creating a default index.html for the site given the project root location
""" """
import cms
_html = f""" _html = f"""
<div align="center"> <div align="center">
<div class="large-text">Thank you for considering QCMS</div> <div class="large-text">Thank you for considering QCMS</div>
<div>version {meta.__version__} by {meta.__author__}, {meta.__email__}</div> <div>version {cms.meta.__version__} by {cms.meta.__author__}, {cms.meta.__email__}</div>
</div> </div>
<p> <p>

@ -4,8 +4,8 @@ __doc__ = """
""" """
from flask import Flask,render_template,send_from_directory,request, redirect, Response, session from flask import Flask,render_template,send_from_directory,request, redirect, Response, session
import flask import flask
import transport #import transport
from transport import providers #from transport import providers
import cms import cms
from cms import Plugin from cms import Plugin
import sys import sys
@ -44,6 +44,14 @@ def _getId(app_id,app_x):
def _setHandler (app_id,resource) : def _setHandler (app_id,resource) :
session['app_id'] = _getId(app_id,resource) session['app_id'] = _getId(app_id,resource)
@_app.route("/favicon.ico")
@_app.route("/<app>/favicon.ico")
def favicon (app):
global _qcms
_site = _qcms.get (app)
print([' **** ',_site.get('layout.location'),_site.get('system.icon')])
return
@_app.route("/<_id>/robots.txt") @_app.route("/<_id>/robots.txt")
@_app.route("/robots.txt",defaults={'_id':None}) @_app.route("/robots.txt",defaults={'_id':None})
def robots_txt(_id): def robots_txt(_id):
@ -95,7 +103,7 @@ def _index ():
_app = _qcms.get(None) _app = _qcms.get(None)
_uri = os.sep.join([_app.get('layout.root'),_app.get('layout.index')]) _uri = os.sep.join([_app.get('layout.root'),_app.get('layout.index')])
_html = _qcms.render(_uri,'index') _html = _qcms.render(_uri,'index')
print (_html)
return render_template('index.html',**_html),200 #render_template('index.html',**_qcms.render(_uri,'index')),200 return render_template('index.html',**_html),200 #render_template('index.html',**_qcms.render(_uri,'index')),200
@_app.route("/<app>/<resource>") @_app.route("/<app>/<resource>")
@ -106,7 +114,16 @@ def _altIndex(app,resource):
_site = _qcms.get(_id) _site = _qcms.get(_id)
_uri = os.sep.join([_site.get('layout.root'),_site.get('layout.index')]) _uri = os.sep.join([_site.get('layout.root'),_site.get('layout.index')])
return render_template('index.html',**_qcms.render(_uri,'index',_id)),200 return render_template('index.html',**_qcms.render(_uri,'index',_id)),200
@_app.route('/files/<path:file>',defaults={'app':None,'module':None})
@_app.route('/<app>/files/<path:file>', defaults=[{'module':None}])
@_app.route('/<app>/<module>/files/<path:file>')
def _read(app,module,file):
global _qcms
_id = _getId(app,module)
_site = _qcms.get(_id)
_stream,_mimeType = _site.read(file)
return io.BytesIO(_stream),200,{'Content-Type':_mimeType}
@_app.route('/<app>/dialog') @_app.route('/<app>/dialog')
@_app.route('/dialog',defaults={'app':None}) @_app.route('/dialog',defaults={'app':None})
def _getdialog(app): def _getdialog(app):
@ -167,6 +184,7 @@ def getPostedPage(app_id,key):
_id = _getId(app_id,key) _id = _getId(app_id,key)
_site = _qcms.get(_id) _site = _qcms.get(_id)
_uri = request.headers['uri'] _uri = request.headers['uri']
if 'dom' not in request.headers : if 'dom' not in request.headers :
_id = _uri.split('/')[-1].split('.')[0] _id = _uri.split('/')[-1].split('.')[0]
else: else:

@ -1,5 +1,5 @@
__author__ = "Steve L. Nyemba" __author__ = "Steve L. Nyemba"
__version__= "2.2.22" __version__= "2.4.0"
__email__ = "steve@the-phi.com" __email__ = "steve@the-phi.com"
__license__=""" __license__="""
Copyright 2010 - 2024, Steve L. Nyemba, Vanderbilt University Medical Center Copyright 2010 - 2024, Steve L. Nyemba, Vanderbilt University Medical Center

@ -318,6 +318,9 @@ class Site(Initialization) :
_handler = cloud if self.get('system.source.id') == 'cloud' else disk _handler = cloud if self.get('system.source.id') == 'cloud' else disk
_html = _handler.html(_uri, self.get(None)) _html = _handler.html(_uri, self.get(None))
return " ".join([f'<div id="{_id}"> ',_html,"</div>"]) return " ".join([f'<div id="{_id}"> ',_html,"</div>"])
def read(self,_uri) :
_handler = cloud if self.get('system.source.id') == 'cloud' else disk
return _handler.read(uri=_uri, config=self.get(None))
class QCMS: class QCMS:
def __init__(self,**_args): def __init__(self,**_args):
@ -346,5 +349,4 @@ class QCMS:
def set(self,_id): def set(self,_id):
self._id = _id self._id = _id
def get(self,_id=None): def get(self,_id=None):
return self._sites[self._id] if not _id else self._sites[_id] return self._sites[self._id] if not _id else self._sites[_id]

@ -1,87 +0,0 @@
/**
* This file has functions that allow pages to be fetched and rendered on bootup
*/
var bootup = {}
//
// We implement this function using an observer design pattern
bootup.CMSObserver = function(_context,_domId,_fileURI){
this._context = _context
this._domId = _domId
this._fileURI = _fileURI
this.apply = function (_caller){
var http = HttpClient.instance()
http.setHeader('uri',_fileURI)
uri = '/page'
if (this._context != '' && this._context != null) {
uri = this._context + uri
}
if (window.location.pathname != '/'){
uri = ([window.location.pathname,'page']).join('/')
}
try{
// var _domElement = jx.dom.get.instance('div')
// _domElement.className = 'busy-loading'
// jx.dom.append(_domId, _domElement)
http.post(uri,function(x){
if (x.status == 200 && x.readyState == 4){
setTimeout(function(){
_content = $(x.responseText)
var _id = $(_content).attr('id')
_pid = (['#',_domId,' #',_id]).join('')
if( $(_pid).length != 0){
$(_pid).remove()
}
$('#'+_domId).append(x.responseText)
},10)
}
_caller.notify()
})
}catch(error){
_caller.notify()
}
}
}
//
// Finalize the process of rendering the content on the fly
bootup.finalize = function(_id){
this.apply = function(_caller){
// menu.runScript('#'+_id)
setTimeout(function(){menu.events.finalize(_id);},1000)
// menu.events.finalize(_id)
}
}
bootup.init = function(sys_id,_layout){
if (!_layout) {
return ;
}
if (_layout.on){
jx.utils.keys(_layout.on.load).forEach(function(_domId){
var observers =
jx.utils.patterns.visitor(_layout.on.load[_domId], function(_uri){
// _uri = _layout.root_prefix != null? (_layout.root_prefix+_uri) : _uri
return new bootup.CMSObserver(sys_id,_domId,_uri)
})
observers.push(new bootup.finalize(_domId))
//
// At this point we can execute the observer design pattern
//
// console.log(observers)
jx.utils.patterns.observer(observers,'apply')
})
}
}

@ -1,44 +0,0 @@
var dialog = {}
dialog.context = ''
dialog.show = function(_args,_pointer){
var http = HttpClient.instance()
// http.setData({title:_title,html:_message},'application/json')
var uri = _args.context+'/dialog'
http.setHeader('dom',_args.title)
if (_args.uri.match(/=/)){
_args.uri = _args.uri.split(/=/)[1]
}
http.setHeader('uri',_args.uri)
http.get(uri,function(x){
$('.jxmodal').remove()
jx.modal.show({html:x.responseText,id:'body'})
if(jx.dom.exists('dialog-message') && _args.message != null){
jx.dom.set.value('dialog-message',_args.message)
}
//
// In order to perhaps execute any js script that should have been executed on load ...
//
var scripts = $('.jxmodal script')
jx.utils.patterns.visitor(scripts,function(_item){
if(_item.text.trim().length > 0){
var _routine = eval(_item.text)
//
//@TODO:
// Find a way to add the running function into the page to enable scripts to work
//
}
})
if (_pointer !=null){
_pointer()
}
})
}
if (! qcms){
var qcms = {}
}
qcms.dialog = dialog

@ -1,449 +0,0 @@
/*
* Let us load the menu items here ...
*/
var menu = {}
/*
* This function will load menu items from the configuration file
* :uri
* :id
* :pid parent identifier
*/
menu.apply = function (uri,id,pid,_context){
id = id.replace(/ /g,'-')
if(uri == null){
return ;
}
$('.content').children().hide()
var httpclient = HttpClient.instance()
httpclient.setHeader('uri',uri)
httpclient.setHeader('dom',id)
httpclient.post(_context+'/page',function(x){
var _html = x.responseText
var template = document.createElement('template');
template.innerHTML = _html.trim();
var _dom = template.content.firstChild;
if(jx.dom.exists(pid) && jx.dom.exists(id)){
jx.dom.remove(id)
}
$('#'+pid).append(_dom)
// jx.dom.append(pid,_dom)
// $('#'+id).show('fast',function(){
// $('#'+pid).slideUp()
// })
$('#'+pid).children().slideUp('fast', function(){
$('#'+id).slideDown('fast',function(){
$('#'+pid).slideDown('fast',function(){
var input = $('#'+pid).find('input')
if (input.length > 0 ){
$(input[0]).focus()
}
})
})
})
// $('.content').append(_dom)
})
}
menu.apply_link =function(_args,_context){
//
// type:
// redirect open new window
// dialog open in a dialog
//
var url = _args['url']
_args.type = (_args.type == null)? 'redirect' :_args.type
if (_args.type.match(/dialog|embed/i) ) {
//
// calling jx.modal.show
if (_args.url){
jx.modal.show(_args.url)
}else{
// _html = jx.dom.get.value(_args.text)
// console.log(_html)
// jx.modal.show(_html)
var http = HttpClient.instance()
http.setHeader('uri',_args.uri)
http.setHeader('dom',(_args.title)?_args.title:'dialog')
// http.setHeader('dom',_args.text)
http.get(_context+'/dialog',function(x){
jx.modal.show({html:x.responseText,id:'dialog'})
console.log([$('.jxmodal')])
menu.runScript ('.jxmodal')
})
}
}else{
window.open(_args.url,_args.text)
}
}
var _delegate = {scripts:{}}
menu.runScript = function(_id){
var scripts = $(_id+' script')
jx.utils.patterns.visitor(scripts,function(_item){
if(_item.text.trim().length > 0){
var _code = eval(_item.text)
var id = _id
if (_item.parentNode != null){
var id = _item.parentNode.id == null?_item.parentNode.className : _item.parentNode.id
}
id = (id != null)?id : _id
// _delegate.scripts[id] = _code
}
})
}
menu.events = {}
menu.events._dialog = function (_item,_context){
// var url = _args['url']
_item.type = (_item.type == null)? 'redirect' :_item.type
var http = HttpClient.instance()
_regex = /uri=(.+)/;
if (_item.uri.match(_regex)) {
_seg = _item.uri.match(_regex)
_item.uri = _seg[_seg.length - 1]
}
http.setHeader('uri',_item.uri)
http.setHeader('dom',(_item.title)?_item.title:'dialog')
// http.setHeader('dom',_args.text)
http.get(_context+'/dialog',function(x){
jx.modal.show({html:x.responseText,id:'dialog'})
menu.events.finalize ('.jxmodal')
})
}
menu.events._openTabs = function (_TabContentPane, _id) {
_id = _id[0] != '.' ? ('.'+_id) : _id
$(_TabContentPane).children().slideUp('fast')
$(_id).slideDown()
}
menu.events._open = function (id,uri,_context){
id = id.replace(/ /g,'-')
var pid = '#content'
$('.content').children().slideUp()
// if ( $('#'+id).parent() == null){
// $('.content').children().slideUp()
// }else{
// var parent = $('#'+id).parent()
// parent.slideUp()
// if (parent[0].id == null){
// pid = ('.' + parent[0].className)
// }else{
// pid = ('#'+parent[0].id)
// }
// }
$('#'+id).remove()
var httpclient = HttpClient.instance()
_context = (_context == null)?'':_context;
httpclient.setHeader('uri',uri)
httpclient.setHeader('dom',id)
httpclient.post(_context+'/page',function(x){
if(x.readyState == 4 && x.status == 200){
var _html = x.responseText
var _dom = $(_html)
if(jx.dom.exists(pid) && jx.dom.exists(id)){
jx.dom.remove(id)
}
$(pid).append(_dom)
var ref = pid + ' #'+id
// menu.events.finalize (ref)
$(pid).children().slideUp('fast', function(){
$(ref ).slideDown('fast',function(){
$(pid).slideDown('fast',function(){
var input = $(pid).find('input')
if (input.length > 0 ){
$(input[0]).focus()
}
})
})
})
}
// $('.content').append(_dom)
})
}
menu.utils = {}
menu.utils.format = function(text){
return text.replace(/(-|_)/g,' ').trim()
}
menu.utils._delegate = function (_id,_itemIndex,_index) {
if ($(_id).children().length >= _itemIndex ){
var _node = $(_id).children()[_itemIndex ]
if ($(_node).children().length >= _index ){
var _node = $(_node).children()[_index]
_node = $(_node).find('.active')
if ($(_node).length > 0 ){
$(_node)[0].click()
}
}
}
}
menu.events.finalize = function (ref) {
var scripts = $(ref+' script')
jx.utils.patterns.visitor(scripts,function(_item){
if(_item.text.trim().length > 0){
var _code = eval(_item.text)
var id = ref
if (_item.parentNode != null){
var id = _item.parentNode.id == null?_item.parentNode.className : _item.parentNode.id
}
id = (id != null)?id : ref
// _delegate.scripts[id] = _code
}
})
}
/**
* Let's build the tab handling here ...
*
*/
var QCMSBasic= function(_layout,_context,_clickEvent) {
this._layout = _layout
this._context= _context
this._make = function (_items){
var _panes = []
var _context = this._context ;
_items.forEach(_item=>{
var _div = jx.dom.get .instance('DIV')
_div.innerHTML = menu.utils.format(_item.text)
//
// We need to check for the override text and see if it goes here
_div.className = 'active'
_div.data = _item
_panes.push(_div)
$(_div).on('click', function (){
//
// how do we process this ...
if(this.data.uri && this.data.type != 'open') {
if (this.data.type == 'dialog') {
// console.log(this.data)
menu.events._dialog(this.data,_context)
}else{
menu.events._open(menu.utils.format(this.data.text),this.data.uri,_context)
}
}else{
if (this.data.uri != null){
window.open(this.data.uri,'_self')
}else{
window.open(this.data.url,menu.utils.format(this.data.text))
}
}
})
})
return _panes ;
}
this.init = function (){
var _me = this ;
var _make = this._make
var _layout = this._layout
var _names = _layout.order.menu.length > 0 ? _layout.order.menu : Object.keys(_layout.menu)
// Object.keys(this._layout.menu)
_names.forEach(function(_name){
var _div = _me._make(_layout.menu[_name]) ;
var _sub = jx.dom.get.instance('DIV')
var _menuItem = jx.dom.get.instance('DIV')
_menuItem.innerHTML = menu.utils.format (_name)
_sub.className = 'sub-menu border-round border '
_menuItem.className = 'item'
_div.forEach(_item=>{$(_sub).append(_item) })
$(_sub).append(_div)
_menuItem.appendChild(_sub)
$('.main .menu').append(_menuItem)
})
}
}
var QCMSTabs = function(_layout,_context,_id){
//
// This object will make tabs in the area of the menu
// @TODO: we can parameterize where the menu is made to improve flexibility
//
this.tabs = jx.dom.get.instance('DIV')
this.tabs.className = 'tabs'
this._context = _context
this._layout = _layout
this._target = (_id == null)?'.main .menu':_id
this._make = function (text,_item,_event){
var text = text.trim().replace(/(_|-)/ig,' ').trim()
var _context = this._context;
if (text.match(/\//)){
text = text.split(/\//g).slice(-1)[0]
}
var _button = jx.dom.get.instance('INPUT')
var _label = jx.dom.get.instance('LABEL')
_button.type= 'radio'
_button.id = text+'tab'
_button.name = 'menu-tabs'
_label.data = {id:text.toLowerCase(),uri:_item[0].uri}
// _button._uri = _label._uri
// if(this._layout.icons[text] != null) {
if (this._layout.icon){
var _icon = jx.dom.get.instance('I')
_icon.className = this._layout.icons[text]
$(_label).append(_icon)
}
text = ' ' + text
// }
$(_label).append(text)
// _button.value= text.toLowerCase()
$(_button).val(text.toLowerCase())
_label.htmlFor = _button.id
$(_label).on('click',function (){
menu.events._open(this.data.id,this.data.uri,_context)
})
// $(_button).on('click',function (){
// menu.events._open(this.value,this._uri,_context) ;})
return [_button,_label]
}
this.init = function (){
var _me = this;
var _make = this._make
var tabs = this.tabs
var _names = _layout.order.menu.length > 0 ? _layout.order.menu : Object.keys(_layout.menu)
// Object.keys(_layout.menu).
_names.forEach(function(_key){
_item = _layout.menu[_key]
// console.log([_item])
_tabItem = _me._make(_key,_item)
$(tabs).append(_tabItem)
})
this.tabs.className = 'tabs'
$(this._target).append(this.tabs)
$(this._target).css({'border':'1px solid transparent'})
$(this._target).css({'grid-template-columns':'64px auto'})
}
//
// We need to load the pages here ...
//
}
menu.delegate = { }
// menu.tabs.make = function(text,_clickEvent){
// var _id = text.trim()
// if (text.match(/\//)){
// _id = text.split(/\//g).slice(-1)[0]
// }
// var _button = jx.dom.get.instance('div')
// var _label = jx.dom.get.instance('LABEL')
// _button.type= 'radio'
// _button.id = _id
// _label.innerHTML = _id.toLowerCase()
// $(_label).on('click',_clickEvent)
// return [_button,_label]
// }
menu.init =function (_layout,_context){
//
// Let us determine what kind of menu is suited for this
// @TODO: Make menus configurable i.e on other areas of the site
//
if (_layout.order != null){
if (_layout.order.length == null && _layout.order.menu == null){
_layout.order = {menu:[]}
}else if (_layout.order.menu == null){
_layout.order.menu = []
}
}else{
_layout.order = {menu:[]}
}
var _count = 0
var _items = 0
Object.keys(_layout.menu).forEach(_name=>{
_items += _layout.menu[_name].length
_count += 1
})
if (_count == _items){
var _menuObject = new QCMSTabs (_layout,_context)
}else{
var _menuObject = new QCMSBasic (_layout,_context)
}
_menuObject.init()
}
/***
*
* Source Code
*/
if (! code){
var code = {}
}
code.copy = function(_node) {
var _code = $(_node.parentNode).text().trim().replace(/ {8}/g,'').replace(/ {4}/g,'\t').replace(/\r/g,'\n')
navigator.clipboard.writeText(_code);
$(_node).empty()
$(_node).html('<i class="fa-solid fa-check"></i>')
setTimeout(function(){
$(_node).empty()
$(_node).html('<i class="fa-regular fa-copy"></i>')
},750)
}

@ -0,0 +1,43 @@
if (!qcms){
var qcms = {}
}
/**
* THIS FILE DEPENDS ON qcms.html.Common
*/
qcms.dialog = {}
qcms.dialog.show = function (_args){
if (_args.uri.match(/=/)){
_args.uri = _args.uri.split(/=/)[1]
}
var http = HttpClient.instance()
http.setHeader('dom',_args.title)
http.setHeader('uri',_args.uri)
http.get(`${qcms.context}/dialog`,(x)=>{
$('.jxmodal').remove()
jx.modal.show({html:x.responseText,id:'body'})
if(jx.dom.exists('dialog-message') && _args.message != null){
jx.dom.set.value('dialog-message',_args.message)
}
//-- are there scripts in the modal window
var scripts = $('.jxmodal script')
scripts.each((_index)=>{
var _code = $(scripts)[_index].text
eval(_code)
})
})
}
//
// Make a proxy for backward compatibility (not everything was prefixed by qcms)
//
var dialog = qcms.dialog

@ -0,0 +1,234 @@
/**
* This file implements 2 types of menus (basic roll down and tabs), they are implemented as objects given
*/
if (!qcms){
var qcms = {}
}
qcms.menu = {}
qcms.menu.Common = function (){
this._format = function (text){
return text.replace(/(-|_)/g,' ').trim()
}
this._open = function (text,uri,_parentId){
var _domId = text.replace(/ /g,'-')
var http = HttpClient.instance()
http.setHeader('dom',_domId)
http.setHeader('uri',uri)
http.post(`${qcms.context}/page`,(x)=>{
//
// @TODO: In case of an error
var _dom = $(x.responseText)
if($(`${_parentId} #${_domId}`).length){
$(`${_parentId} #${_domId}`).remove()
}
var _found = qcms.html.hasNode ($(`${_parentId}`),$(_domId))
if (_found == 0){
$(`${_parentId}`).children().slideUp('fast',()=>{
$(`${_parentId}`).append(_dom)
this._finalize(`${_parentId} #${_domId}`)
})
}
})
}
this._finalize = function (_id){
var _script = $(`${_id} script`)
if (_script.lenth > 0){
_script.each( (_index)=>{
var _code = $(_script)[_index].text
eval(_code)
})
}
}
}
qcms.menu.Basic = function (_layout,_outputId,_domId){
qcms.menu.Common.call(this)
this._layout = _layout
this._parentId = _outputId //-- target of the output
this.init = function (){}
this._build = function (_items){
var _panes = []
var _context = this._context ;
var _open = this._open
var _parentId = this._parentId
// var _format = this._format
// var _finalize = this._finalize
// var _domId = this._domId
var _me = this ;
_items.forEach(_item=>{
var _div = jx.dom.get .instance('DIV')
_div.innerHTML = this._format(_item.text)
//
// We need to check for the override text and see if it goes here
_div.className = 'active'
_div.data = _item
_panes.push(_div)
$(_div).on('click', function (){
//
// how do we process this ...
if (this.data.type == 'redirect') {
window.open(this.data.url,_me._format(this.data.text))
}else if (this.data.type == 'dialog'){
qcms.dialog.show(this.data)
}else if (this.data.type == 'open'){
window.open(this.data.uri,'_self')
}else{
_me._open(_me._format(this.data.text),this.data.uri,_parentId)
}
// if(this.data.uri && this.data.type != 'open') {
// if (this.data.type == 'dialog') {
// qcms.dialog.show(this.data)
// }else{
// _me._open(_me._format(this.data.text),this.data.uri,_parentId)
// }
// }else{
// //
// // redirecting
// if (this.data.uri != null){
// window.open(this.data.uri,'_self')
// }else{
// window.open(this.data.url,_format(this.data.text))
// }
// }
})
})
return _panes ;
}
/**
* This part builds the menu automatically
*/
var _names = _layout.order.menu.length > 0 ? _layout.order.menu : Object.keys(_layout.menu)
_names.forEach ((_name)=>{
var _div = this._build(_layout.menu[_name]) ;
var _sub = jx.dom.get.instance('DIV')
var _menuItem = jx.dom.get.instance('DIV')
_menuItem.innerHTML = this._format (_name)
_sub.className = 'sub-menu border-round border '
_menuItem.className = 'item'
_div.forEach(_item=>{$(_sub).append(_item) })
$(_sub).append(_div)
_menuItem.appendChild(_sub)
_domId = (_domId == null || $(_domId).length == 0)?'.main .menu' : _domId
$(`${_domId}`).append(_menuItem)
})
}
/**
* Implementing Tab based menu
*/
qcms.menu.Tabs = function (_layout,_outputId,_domId){
qcms.menu.Common.call(this) //-- inheriting format and open functions
this._layout = _layout
this._parentId = _outputId //-- target of the output
this._domId = _domId
this.tabs = jx.dom.get.instance('DIV')
this.tabs.className = 'tabs'
this._context = qcms.context
this._build = function (text,_item,event){
var text = text.trim().replace(/(_|-)/ig,' ').trim()
var _context = this._context;
if (text.match(/\//)){
text = text.split(/\//g).slice(-1)[0]
}
var _button = jx.dom.get.instance('INPUT')
var _label = jx.dom.get.instance('LABEL')
_button.type= 'radio'
_button.id = text+'tab'
_button.name = 'menu-tabs'
_label.data = {id:text.toLowerCase(),uri:_item[0].uri}
if (this._layout.icon){
var _icon = jx.dom.get.instance('I')
_icon.className = this._layout.icons[text]
$(_label).append(_icon)
}
text = ' ' + text
$(_label).append(text)
$(_button).val(text.toLowerCase())
_label.htmlFor = _button.id
// var _open = this._open
// var _parentId = this._parentId
var _me = this ;
$(_label).on('click',function (){
// _me._open(this.data.id,this.data.uri,_me._parentId)
_me._open(_me._format(this.data.text),this.data.uri,_parentId)
})
return [_button,_label]
}
var _names = _layout.order.menu.length > 0 ? _layout.order.menu : Object.keys(_layout.menu)
// Object.keys(_layout.menu).
_names.forEach(function(_text){
_item = _layout.menu[_text]
_tabItem = this._build(_text,_item)
$(tabs).append(_tabItem)
})
this.tabs.className = 'tabs'
$(this._domId).append(this.tabs)
$(this._domId).css({'border':'1px solid transparent'})
$(this._domId).css({'grid-template-columns':'64px auto'})
}
qcms.menu.init = function(_layout){
if (_layout.order != null){
if (_layout.order.length == null && _layout.order.menu == null){
_layout.order = {menu:[]}
}else if (_layout.order.menu == null){
_layout.order.menu = []
}
}else{
_layout.order = {menu:[]}
}
var _count = 0
var _items = 0
Object.keys(_layout.menu).forEach(_name=>{
_items += _layout.menu[_name].length
_count += 1
})
if (_count == _items){
var _menuObject = new qcms.menu.Tabs (_layout,'.main #content','.main .menu')
}else{
var _menuObject = new qcms.menu.Basic (_layout,'.main #content','.main .menu')
}
}
//
// backward compatibility ...
if(!menu){
var menu = {}
}
menu.init = qcms.menu.init

@ -0,0 +1,86 @@
if(!qcms){
var qcms = {}
}
qcms.page = {}
qcms.page.Observer = function (_parentId,_domId,_uri){
this._parentId = _parentId == null?'':_parentId
this._domId = _domId
this._uri = _uri
this.finalize = function(_id){
var _script = $(`${_id} script`)
if (_script.lenth > 0){
_script.each( (_index)=>{
var _code = $(_script)[_index].text
if (_code){eval(_code)}
})
}
}
this.apply = function (_caller){
_uri = this._uri
_finalize = this.finalize
_domId = this._domId
var _id = `${this._parentId} #${this._domId}`.trim()
var http = HttpClient.instance()
http.setHeader('dom',this._domId)
http.setHeader('uri',this._uri)
var _uri = this._uri
http.post(`${qcms.context}/page`,function(x){
var _dom = $(x.responseText)
var _found = qcms.html.hasNode( $(_id), $(_dom))
if (_found == 0){
$(_id).append (_dom)
_finalize(_id)
}
_caller.notify()
})
}
}
qcms.page.loader = function(_parentId,_layout){
if (_parentId.constructor == Object) {
_layout = _parentId
_parentId = null
}
if (!_layout) {
return ;
}
if (_layout.on){
jx.utils.keys(_layout.on.load).forEach(function(_domId){
var observers =
jx.utils.patterns.visitor(_layout.on.load[_domId], function(_uri){
_uri = _layout.root_prefix != null? (_layout.root_prefix+_uri) : _uri
return new qcms.page.Observer(_parentId,_domId,_uri)
})
jx.utils.patterns.observer(observers,'apply')
})
}
}
//
// making backwards compatibility
if(!bootup){
var bootup = {}
}
bootup.init =qcms.page.loader

@ -0,0 +1,23 @@
if (!qcms){
var qcms = {}
}
qcms.html = {}
qcms.html.hasNode = function (_parent,_child){
var _found = 0
if ($(_child).length == 0){
return 0
}
$(_parent).each((_index)=>{
var _node = $(_parent)[_index]
if ( $(_node)[0].innerHTML == $(_child)[0].outerHTML){
_found = 1
}
})
return _found
}

@ -1,14 +1,33 @@
var Search = function(_searchBoxId,_paneId,_bind){ // var Search = function(_searchBoxId,_paneId,_bind){
// var _text = jx.dom.get.value(_searchBoxId)
// _regex = new RegExp(_text.toLowerCase())
// _paneId = (_paneId[0] == '#')?_paneId:('#'+_paneId)
// $(_paneId).slideUp()
// (_paneId).children().each(_index=>{
// _div = $(_paneId).children()[_index]
// if (_div.html().match(_regex)){
// $(_div).slideDown()
// }
// })
// }
if (!qcms) {
var qcms = {}
}
qcms.search = function(_searchBoxId,_paneId,_bind){
var _text = jx.dom.get.value(_searchBoxId) var _text = jx.dom.get.value(_searchBoxId)
_regex = new RegExp(_text.toLowerCase()) _regex = new RegExp(_text.toLowerCase().trim())
_paneId = (_paneId['#'])?_paneId:('#'+_paneId) _paneId = (_paneId[0] == '#')?_paneId:('#'+_paneId)
$(_paneId).slideUp() // $(_paneId).children().css({display:'none'})
(_paneId).children().each(_index=>{ var found = 0
$(_paneId).children().each(_index=>{
_div = $(_paneId).children()[_index] _div = $(_paneId).children()[_index]
if (_div._data.match(_regex)){ if ($(_div).html().toLowerCase().match(_regex)){
$(_div).slideDown() $(_div).slideDown()
}else{
$(_div).css({display:'none'})
} }
}) })
} }

@ -56,7 +56,10 @@ Vanderbilt University Medical Center
<meta property="og:image:alt" content="{{layout.header.title}}" /> <meta property="og:image:alt" content="{{layout.header.title}}" />
<meta property="og:description" content="{{layout.header.title}}; {{layout.header.subtitle}}, version {{system.version}}" /> <meta property="og:description" content="{{layout.header.title}}; {{layout.header.subtitle}}, version {{system.version}}" />
<meta property="og:site_name" content="{{layout.header.title}}" /> <meta property="og:site_name" content="{{layout.header.title}}" />
<script src="{{system.parentContext}}/static/js/qcms/qcms.js"></script>
<script src="{{system.parentContext}}/static/js/qcms/menu.js"></script>
<script src="{{system.parentContext}}/static/js/qcms/page-loader.js"></script>
<script src="{{system.parentContext}}/static/js/qcms/dialog.js"></script>
<script src="{{system.parentContext}}/static/js/dashboard.js"></script> <script src="{{system.parentContext}}/static/js/dashboard.js"></script>
<script src="{{system.parentContext}}/static/js/jx/dom.js"></script> <script src="{{system.parentContext}}/static/js/jx/dom.js"></script>
<script src="{{system.parentContext}}/static/js/jx/utils.js"></script> <script src="{{system.parentContext}}/static/js/jx/utils.js"></script>
@ -64,10 +67,10 @@ Vanderbilt University Medical Center
<script src="{{system.parentContext}}/static/js/jx/ext/modal.js"></script> <script src="{{system.parentContext}}/static/js/jx/ext/modal.js"></script>
<script src="{{system.parentContext}}/static/js/jx/ext/math.js"></script> <script src="{{system.parentContext}}/static/js/jx/ext/math.js"></script>
<script src="{{system.parentContext}}/static/js/jquery/jquery.js"></script> <script src="{{system.parentContext}}/static/js/jquery/jquery.js"></script>
<script src="{{system.parentContext}}/static/js/menu.js"></script> <!-- <script src="{{system.parentContext}}/static/js/menu.js"></script> -->
<script src="{{system.parentContext}}/static/js/search.js"></script> <script src="{{system.parentContext}}/static/js/search.js"></script>
<script src="{{system.parentContext}}/static/js/bootup.js"></script> <!-- <script src="{{system.parentContext}}/static/js/bootup.js"></script> -->
<script src="{{system.parentContext}}/static/js/dialog.js"></script> <!-- <script src="{{system.parentContext}}/static/js/dialog.js"></script> -->
<script src="{{system.parentContext}}/static/js/apexcharts/apexcharts.min.js"></script> <script src="{{system.parentContext}}/static/js/apexcharts/apexcharts.min.js"></script>
<script src="{{system.parentContext}}/static/js/fontawesome/js/all.js"></script> <script src="{{system.parentContext}}/static/js/fontawesome/js/all.js"></script>
</head> </head>
@ -75,12 +78,17 @@ Vanderbilt University Medical Center
// sessionStorage.setItem('{{system.id}}','{{system.context|safe}}') // sessionStorage.setItem('{{system.id}}','{{system.context|safe}}')
var _layout = {{layout|tojson}} var _layout = {{layout|tojson}}
// if (!qcms){
// var qcms = {}
// }
qcms.context = '{{system.context}}'
// dialog.context = '{{system.context}}'
//sessionStorage.setItem('{{system.id}}','{{system.context|safe}}') //sessionStorage.setItem('{{system.id}}','{{system.context|safe}}')
$(document).ready( function(){ $(document).ready( function(){
bootup.init('{{system.id}}',_layout) bootup.init('{{system.id}}',_layout)
menu.init({{layout|tojson}},'{{system.context}}') // menu.init({{layout|tojson}},'{{system.context}}')
qcms.menu.init({{layout|tojson}})
}) })

@ -5,10 +5,12 @@
{% else %} {% else %}
{% set _backURI = system.parentContext%} {% set _backURI = system.parentContext%}
{% endif %} {% endif %}
<div class="icon active"> <div class="icon" style="margin:0px" >
<div align="center" class="button" onclick="window.open('{{_backURI}}','_self')" style="display:grid; grid-template-columns:auto auto; gap:4px; align-items:center "> <div align="left" class="back-button active" onclick="window.open('{{_backURI}}','_self')" >
<i class="fa-solid fa-chevron-left" style="color:darkgray; display:block"></i> <div style="display:grid; align-items:center; grid-template-columns: auto auto;">
<img src="{{system.caller.icon}}" style="height:100%"/> <i class="fa-solid fa-chevron-left" style="color:darkgray;"></i>
<img src="{{system.caller.icon}}"/>
</div>
</div> </div>
</div> </div>
{% else %} {% else %}

Loading…
Cancel
Save