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
if not os.path.exists(folder) :
root = 'www/html'
root = f'www{os.sep}html'
_system = System()
_layout = Layout()
_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"
python qcms %1 %2 %3 %4 %5 %6

@ -181,5 +181,9 @@ class delegate:
</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}

@ -68,8 +68,16 @@ def build (_config, keep=[]): #(_path,_content):
def _realpath (uri,_config) :
_layout = _config['layout']
_uri = copy.copy(uri)
if _layout['root'] not in _uri :
_uri = os.sep.join([_layout['root'],_uri])
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])
return _uri
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
@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']
_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 = _realpath(_uri, _args['config'])
_mimeType = 'text/plain'
if os.path.exists(_uri):
f = open(_uri,mode='rb')
_stream = f.read()
@ -135,6 +144,8 @@ def html(_uri,_config) :
# _html = _html.replace(f'{os.sep}{_layout["root"]}',_layout['root'])
return _html
pass
def plugins (**_args):
"""
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,
Not all elements are programmatically editable (for now)
"""
import meta
# import meta
class Section :
def build (self,**_args):
@ -36,7 +36,8 @@ class System (Section) :
"""
return 'default' if 'name' not in _args else _args['name']
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):
return "" if 'context' not in _args else _args['context']
def app (self,**_args):

@ -2,7 +2,7 @@
import base64
import os
import json
import meta
# import meta
from cms.engine import themes
# def make (**_args):
# """
@ -94,10 +94,11 @@ def _index (_path,root):
"""
Creating a default index.html for the site given the project root location
"""
import cms
_html = f"""
<div align="center">
<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>
<p>

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

@ -1,5 +1,5 @@
__author__ = "Steve L. Nyemba"
__version__= "2.2.22"
__version__= "2.4.0"
__email__ = "steve@the-phi.com"
__license__="""
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
_html = _handler.html(_uri, self.get(None))
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:
def __init__(self,**_args):
@ -346,5 +349,4 @@ class QCMS:
def set(self,_id):
self._id = _id
def get(self,_id=None):
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)
_regex = new RegExp(_text.toLowerCase())
_paneId = (_paneId['#'])?_paneId:('#'+_paneId)
$(_paneId).slideUp()
(_paneId).children().each(_index=>{
_regex = new RegExp(_text.toLowerCase().trim())
_paneId = (_paneId[0] == '#')?_paneId:('#'+_paneId)
// $(_paneId).children().css({display:'none'})
var found = 0
$(_paneId).children().each(_index=>{
_div = $(_paneId).children()[_index]
if (_div._data.match(_regex)){
if ($(_div).html().toLowerCase().match(_regex)){
$(_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:description" content="{{layout.header.title}}; {{layout.header.subtitle}}, version {{system.version}}" />
<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/jx/dom.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/math.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/bootup.js"></script>
<script src="{{system.parentContext}}/static/js/dialog.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/apexcharts/apexcharts.min.js"></script>
<script src="{{system.parentContext}}/static/js/fontawesome/js/all.js"></script>
</head>
@ -75,12 +78,17 @@ Vanderbilt University Medical Center
// sessionStorage.setItem('{{system.id}}','{{system.context|safe}}')
var _layout = {{layout|tojson}}
// if (!qcms){
// var qcms = {}
// }
qcms.context = '{{system.context}}'
// dialog.context = '{{system.context}}'
//sessionStorage.setItem('{{system.id}}','{{system.context|safe}}')
$(document).ready( function(){
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 %}
{% set _backURI = system.parentContext%}
{% endif %}
<div class="icon active">
<div align="center" class="button" onclick="window.open('{{_backURI}}','_self')" style="display:grid; grid-template-columns:auto auto; gap:4px; align-items:center ">
<i class="fa-solid fa-chevron-left" style="color:darkgray; display:block"></i>
<img src="{{system.caller.icon}}" style="height:100%"/>
<div class="icon" style="margin:0px" >
<div align="left" class="back-button active" onclick="window.open('{{_backURI}}','_self')" >
<div style="display:grid; align-items:center; grid-template-columns: auto auto;">
<i class="fa-solid fa-chevron-left" style="color:darkgray;"></i>
<img src="{{system.caller.icon}}"/>
</div>
</div>
</div>
{% else %}

Loading…
Cancel
Save